From bf6a7ea5838fa99af569920ab9235fef2de67b3b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Thu, 1 Feb 2018 17:49:27 -0300 Subject: [PATCH 01/28] Replace setMultiple() with fill() --- src/Model.php | 26 +++----------------------- 1 file changed, 3 insertions(+), 23 deletions(-) diff --git a/src/Model.php b/src/Model.php index 9a0fa90..ebe9ea6 100644 --- a/src/Model.php +++ b/src/Model.php @@ -517,8 +517,6 @@ public static function dump($where = [], $columns = []) * * Very useful when chaining __construct() * - * @todo Replaces setMultiple() - * * @param mixed[] $data An array of known columns => value * * @return $this @@ -527,7 +525,9 @@ public static function dump($where = [], $columns = []) */ public function fill(array $data) { - $this->setMultiple($data); + foreach ($data as $column => $value) { + $this->__set($column, $value); + } return $this; } @@ -582,26 +582,6 @@ public function reload() return $this->load($this->getPrimaryKey()); } - /** - * Changes the value in multiple columns - * - * @see __set() - * - * @deprecated Use fill() instead - * - * @param mixed[] $data An array of known columns => value - * - * @throws ReadOnlyModelException - * @throws UnknownColumnException - * @throws ForeignConstraintException - */ - public function setMultiple($data) - { - foreach ($data as $column => $value) { - $this->__set($column, $value); - } - } - /** * Converts the Model to array * From 480db58087882f45bd465d987428aa7231bbf1b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Fri, 9 Feb 2018 19:36:01 -0300 Subject: [PATCH 02/28] Add Unreleased sections --- CHANGELOG.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2fab195..da069c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +### Added + +### Changed + +### Deprecated + +### Removed + +### Fixed + +### Security + ## [3.1.0] - 2018-02-09 From bca1536e21944b0504279b8679f1060433330b6a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Fri, 9 Feb 2018 20:05:21 -0300 Subject: [PATCH 03/28] Add fill() example --- CHANGELOG.md | 1 + src/Model.php | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index da069c3..11ca996 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] ### Added +- Model `fill()` example ### Changed diff --git a/src/Model.php b/src/Model.php index efb6d88..c5cf86a 100644 --- a/src/Model.php +++ b/src/Model.php @@ -520,6 +520,12 @@ public static function dump($where = [], $columns = []) * * Very useful when chaining __construct() * + * Example: + * + * $model = (new My\Model)->fill([ + * 'column' => 'value', + * ]); + * * @todo Replaces setMultiple() * * @param mixed[] $data An array of known columns => value From 9f08691bcd9d6761ab754d68a6276f54365270b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Fri, 9 Feb 2018 20:50:13 -0300 Subject: [PATCH 04/28] Add isFresh() --- CHANGELOG.md | 2 ++ README.md | 1 + src/Model.php | 16 +++++++++++++--- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 11ca996..d119b14 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Added - Model `fill()` example +- Model methods: + - `isFresh()` ### Changed diff --git a/README.md b/README.md index ac0e559..943eca1 100644 --- a/README.md +++ b/README.md @@ -178,6 +178,7 @@ Useful methods that are available: to keep timezone consistent - `getDatabase()`: Gives a direct access to the Database, already connected and ready to use. See [catfan/Medoo] for details +- `isFresh()`: Tells if the object is a new Model - `jsonSerialize()`: You can [json_encode] models! - `reload()`: Use to re fetch the row with model's Primary Key diff --git a/src/Model.php b/src/Model.php index c5cf86a..10ba8a3 100644 --- a/src/Model.php +++ b/src/Model.php @@ -312,7 +312,7 @@ public function save() throw new ReadOnlyModelException(); } - $is_fresh = $this->data === null; + $is_fresh = $this->isFresh(); if (($is_fresh && !$this->onFirstSaveHook()) || !$this->onSaveHook() @@ -413,7 +413,7 @@ public function update($columns) if (static::READ_ONLY) { throw new ReadOnlyModelException(); } - if ($this->data === null) { + if ($this->isFresh()) { throw new \LogicException('Can not update a fresh Model'); } @@ -603,12 +603,22 @@ final public static function getInstance($where) */ public function getPrimaryKey() { - if ($this->data === null) { + if ($this->isFresh()) { return null; } return Utils::arrayWhitelist($this->data, static::PRIMARY_KEY); } + /** + * Tells if the object is a new Model + * + * @return boolean + */ + final public function isFresh() + { + return $this->data === null; + } + /** * Reloads model data * From 95028948a9ddefcebee496859770fa9432c5d0f0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Fri, 9 Feb 2018 23:24:37 -0300 Subject: [PATCH 05/28] Forbid assigning a fresh foreign model --- CHANGELOG.md | 1 + src/Model.php | 9 ++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index cdae2da..e1158e3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - `isFresh()` ### Changed +- Forbid assigning a fresh foreign model ### Deprecated diff --git a/src/Model.php b/src/Model.php index 5435dae..7e91a93 100644 --- a/src/Model.php +++ b/src/Model.php @@ -238,13 +238,14 @@ public function __isset($column) * * NOTE: * - Changes need to be saved in the Database with save() or update($column) + * - You can not assign a foreign model that was not saved yet * * @param string $column A known column * @param mixed $value The new value * * @throws ReadOnlyModelException * @throws UnknownColumnException - * @throws ForeignConstraintException @see loadForeign() + * @throws ForeignConstraintException */ public function __set($column, $value) { @@ -258,6 +259,12 @@ public function __set($column, $value) if (array_key_exists($column, static::FOREIGN_KEYS)) { $foreign_map = static::FOREIGN_KEYS[$column]; if ($value instanceof $foreign_map[0]) { + if ($value->isFresh()) { + throw new ForeignConstraintException( + static::class, + $column + ); + } $this->foreign[$column] = $value; $this->changes[$column] = $value->data[$foreign_map[1]]; return; From 982f907e7ce96609e4b123c350ace73e85d71811 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Fri, 16 Feb 2018 09:25:41 -0300 Subject: [PATCH 06/28] Add getIterator() --- CHANGELOG.md | 1 + README.md | 3 +++ src/Model.php | 12 ++++++++++++ 3 files changed, 16 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1158e3..c1050e6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Added - Model `fill()` example - Model methods: + - `getIterator()` - `isFresh()` ### Changed diff --git a/README.md b/README.md index 943eca1..a5e2659 100644 --- a/README.md +++ b/README.md @@ -151,6 +151,9 @@ Give it a model instance you want to iterate over, it can be a fresh one, and some [filter][where_clause] array. Then it will `load()` each matched row, one by one. +A shortcut is calling `getIterator()` directly from the model class, which just +asks for `$where`. + ## Foreign models diff --git a/src/Model.php b/src/Model.php index 7e91a93..467f50c 100644 --- a/src/Model.php +++ b/src/Model.php @@ -599,6 +599,18 @@ final public static function getInstance($where) ); } + /** + * Shortcut for ModelIterator + * + * @param mixed $where @see ModelIterator::__construct() + * + * @return ModelIterator of this Model + */ + final public static function getIterator($where) + { + return new ModelIterator(static::class, $where); + } + /** * Returns model's Primary Key * From d62c86d25fc1a224ee6437f8b616b282f75ac441 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Fri, 16 Feb 2018 09:28:03 -0300 Subject: [PATCH 07/28] Compact Model::getInstance() --- src/Model.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/Model.php b/src/Model.php index 467f50c..d77452c 100644 --- a/src/Model.php +++ b/src/Model.php @@ -593,10 +593,7 @@ final public static function getDatabase() */ final public static function getInstance($where) { - return ModelManager::getInstance( - static::class, - $where - ); + return ModelManager::getInstance(static::class, $where); } /** From a3cec088c72b726777b50a367f377de128a1a027 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Fri, 16 Feb 2018 09:33:08 -0300 Subject: [PATCH 08/28] Fix ModelIterator and ModelManager __construct() Ensure a model class is used, and not a model instance --- CHANGELOG.md | 2 ++ README.md | 5 ++--- src/ModelIterator.php | 2 +- src/ModelManager.php | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index c1050e6..abd0a6e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,6 +24,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Removed ### Fixed +- ModelIterator and ModelManager `__construct()`: Ensure a model class is used, + and not a model instance ### Security diff --git a/README.md b/README.md index a5e2659..e72d74e 100644 --- a/README.md +++ b/README.md @@ -147,9 +147,8 @@ And change data with: A [ModelIterator] is provided to access multiple rows, but it provides only one at time. -Give it a model instance you want to iterate over, it can be a fresh one, and -some [filter][where_clause] array. Then it will `load()` each matched row, one -by one. +Give it a model class you want to iterate over, and some [filter][where_clause] +array. Then it will `load()` each matched row, one by one. A shortcut is calling `getIterator()` directly from the model class, which just asks for `$where`. diff --git a/src/ModelIterator.php b/src/ModelIterator.php index 680ffeb..405e0e8 100644 --- a/src/ModelIterator.php +++ b/src/ModelIterator.php @@ -57,7 +57,7 @@ class ModelIterator implements \Iterator * @param string $model A Fully Qualified Model Class to iterate * @param mixed[] $where \Medoo\Medoo where clause */ - public function __construct($model_class, $where = []) + public function __construct(string $model_class, $where = []) { $this->model_class = $model_class; $this->list = $model_class::dump($where, $model_class::PRIMARY_KEY); diff --git a/src/ModelManager.php b/src/ModelManager.php index 01ae691..b50afea 100644 --- a/src/ModelManager.php +++ b/src/ModelManager.php @@ -61,7 +61,7 @@ private function __wakeup() * * @throws \InvalidArgumentException @see Model::processWhere() */ - public static function getInstance($model_class, $where) + public static function getInstance(string $model_class, $where) { $database = $model_class::getDatabase(); $primary_key = $database->get( From b423f31fb6223bdd0d3d935eaff33333ec94c3fb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Fri, 16 Feb 2018 12:40:36 -0300 Subject: [PATCH 09/28] Add undo() --- CHANGELOG.md | 1 + README.md | 2 ++ src/Model.php | 22 ++++++++++++++++++++++ 3 files changed, 25 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index abd0a6e..0dd30cf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Model methods: - `getIterator()` - `isFresh()` + - `undo()` ### Changed - Forbid assigning a fresh foreign model diff --git a/README.md b/README.md index e72d74e..4452ceb 100644 --- a/README.md +++ b/README.md @@ -183,6 +183,8 @@ Useful methods that are available: - `isFresh()`: Tells if the object is a new Model - `jsonSerialize()`: You can [json_encode] models! - `reload()`: Use to re fetch the row with model's Primary Key +- `undo()`: Removes changes. Pass a column name to only remove that column, + otherwise it removes all changes You can also add custom methods in your models, to automatically get some data in a format, or for doing a specific task. diff --git a/src/Model.php b/src/Model.php index d77452c..5adcefe 100644 --- a/src/Model.php +++ b/src/Model.php @@ -722,6 +722,28 @@ public function undelete() return $this->update($column); } + /** + * Removes changes + * + * Pass a column name to only remove that column, otherwise it removes all + * changes + * + * @param string $column Which column to undo + * + * @throws UnknownColumnException + */ + public function undo(string $column = null) + { + if ($column === null) { + $this->changes = []; + } else { + if (!in_array($column, static::COLUMNS)) { + throw new UnknownColumnException(); + } + unset($this->changes[$column]); + } + } + /* * Internal methods * ========================================================================= From ca6d0f67ef5e8017f15c2c285026f7ded01b04df Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Sat, 17 Feb 2018 00:44:35 -0300 Subject: [PATCH 10/28] Update Composer --- CHANGELOG.md | 1 + composer.json | 2 +- composer.lock | 12 ++++++------ 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0dd30cf..838fed5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,6 +18,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - `undo()` ### Changed +- Update [aryelgois/utils] - Forbid assigning a fresh foreign model ### Deprecated diff --git a/composer.json b/composer.json index 9b05fd7..a9641d3 100644 --- a/composer.json +++ b/composer.json @@ -11,7 +11,7 @@ ], "require": { "php": "^7.0", - "aryelgois/utils": "^0.2", + "aryelgois/utils": "^0.3.0", "catfan/medoo": "^1.5" }, "autoload": { diff --git a/composer.lock b/composer.lock index 9c78edc..7758ca0 100644 --- a/composer.lock +++ b/composer.lock @@ -4,20 +4,20 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file", "This file is @generated automatically" ], - "content-hash": "d00eb8c68bad5927f9fcdbc41f3974c9", + "content-hash": "78efb27497773dbaccf2931e94ede743", "packages": [ { "name": "aryelgois/utils", - "version": "v0.2.1", + "version": "v0.3.0", "source": { "type": "git", "url": "https://github.com/aryelgois/utils.git", - "reference": "dcd2d5bd5866e4feaa1ad1e1a83c9b4f4217c3b0" + "reference": "449383ce0393eaf975deb64e91b8a8e50bc629eb" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/aryelgois/utils/zipball/dcd2d5bd5866e4feaa1ad1e1a83c9b4f4217c3b0", - "reference": "dcd2d5bd5866e4feaa1ad1e1a83c9b4f4217c3b0", + "url": "https://api.github.com/repos/aryelgois/utils/zipball/449383ce0393eaf975deb64e91b8a8e50bc629eb", + "reference": "449383ce0393eaf975deb64e91b8a8e50bc629eb", "shasum": "" }, "require": { @@ -43,7 +43,7 @@ "keywords": [ "utils" ], - "time": "2017-11-19T12:27:56+00:00" + "time": "2018-02-17T03:29:37+00:00" }, { "name": "catfan/medoo", From caa3cc8ccdba9b3050b0aa31255add87430f45d1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Sat, 17 Feb 2018 08:10:33 -0300 Subject: [PATCH 11/28] Fix Person --- src/Models/Person.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/Models/Person.php b/src/Models/Person.php index 78ea651..3ff24fd 100644 --- a/src/Models/Person.php +++ b/src/Models/Person.php @@ -29,10 +29,13 @@ class Person extends Medools\Model * * @return mixed[] With keys 'type' and 'valid' * @return false If document is invalid - * @return null If a document row was not found + * @return null If document is not set */ public function documentValidate() { + if (!isset($this->document)) { + return null; + } return Utils\Validation::document($this->document); } @@ -43,7 +46,7 @@ public function documentValidate() * * @return string Formatted document * @return string Unformatted document if it is invalid - * @return null If a document row was not found + * @return null If document is not set */ public function documentFormat($prepend = false) { From b214641b68a70af2dd4bf89cfadb0c07abdbb64c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Sat, 17 Feb 2018 08:33:58 -0300 Subject: [PATCH 12/28] Add getRequiredColumns() --- CHANGELOG.md | 1 + README.md | 1 + src/Model.php | 29 +++++++++++++++++++---------- 3 files changed, 21 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 838fed5..fad286f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Model `fill()` example - Model methods: - `getIterator()` + - `getRequiredColumns()` - `isFresh()` - `undo()` diff --git a/README.md b/README.md index 4452ceb..4eb6bb7 100644 --- a/README.md +++ b/README.md @@ -180,6 +180,7 @@ Useful methods that are available: to keep timezone consistent - `getDatabase()`: Gives a direct access to the Database, already connected and ready to use. See [catfan/Medoo] for details +- `getRequiredColumns()`: Gives a list of columns that must be set before saving - `isFresh()`: Tells if the object is a new Model - `jsonSerialize()`: You can [json_encode] models! - `reload()`: Use to re fetch the row with model's Primary Key diff --git a/src/Model.php b/src/Model.php index 5adcefe..997ba7f 100644 --- a/src/Model.php +++ b/src/Model.php @@ -789,6 +789,24 @@ public static function getAutoStampColumns() return array_keys($auto_stamp); } + /** + * Returns required columns + * + * @return string[] + */ + public static function getRequiredColumns() + { + return array_diff( + static::COLUMNS, + static::OPTIONAL_COLUMNS, + [ // implicit optional columns + static::AUTO_INCREMENT, + static::SOFT_DELETE, + ], + static::getAutoStampColumns() + ); + } + /** * Returns the stored data in an array * @@ -1012,16 +1030,7 @@ protected static function validate($data, $full) * Check missing columns */ if ($full) { - $required = array_diff( - static::COLUMNS, - static::OPTIONAL_COLUMNS, - [ // implicit optional columns - static::AUTO_INCREMENT, - static::SOFT_DELETE, - ], - static::getAutoStampColumns() - ); - $missing = array_diff($required, $columns); + $missing = array_diff(static::getRequiredColumns(), $columns); if (!empty($missing)) { throw new MissingColumnException($missing); } From dab9d5fadd2dc101cb772aa8b0fe47ddcebdbfc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Sat, 17 Feb 2018 09:07:44 -0300 Subject: [PATCH 13/28] Change validateHook() --- CHANGELOG.md | 1 + src/Model.php | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fad286f..caa4c50 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Changed - Update [aryelgois/utils] - Forbid assigning a fresh foreign model +- `validateHook()` only receives the data to be validated ### Deprecated diff --git a/src/Model.php b/src/Model.php index 997ba7f..4f4848d 100644 --- a/src/Model.php +++ b/src/Model.php @@ -1047,7 +1047,7 @@ protected static function validate($data, $full) /* * Expanded validation */ - $result = static::validateHook($data, $full); + $result = static::validateHook($data); if ($result === false) { throw new \UnexpectedValueException('Invalid data'); } elseif (is_array($result)) { @@ -1091,12 +1091,11 @@ protected function onSaveHook() * You may return an array of some $data keys with patched/validated data. * * @param mixed[] $data Data to be validated - * @param boolean $full @see validate() * * @return mixed[] For success with a validation patch to $data * @return boolean For success or failure */ - protected static function validateHook($data, $full) + protected static function validateHook($data) { return true; } From cdc7cca853c6ff38c766e3d1a249136488dfa1d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Sat, 17 Feb 2018 09:18:51 -0300 Subject: [PATCH 14/28] Add onColumnChangeHook() --- CHANGELOG.md | 1 + README.md | 2 ++ src/Model.php | 14 ++++++++++++++ 3 files changed, 17 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index caa4c50..6822898 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - `getIterator()` - `getRequiredColumns()` - `isFresh()` + - `onColumnChangeHook()` - `undo()` ### Changed diff --git a/README.md b/README.md index 4eb6bb7..68d58eb 100644 --- a/README.md +++ b/README.md @@ -367,6 +367,8 @@ some functionalities. Currently, these hooks are available: +- `onColumnChangeHook()`: Called when a column is changed. Useful to filter data + before storing in the model - `onFirstSaveHook()`: Called on the first time a model is saved - `onSaveHook()`: Called every time a model is saved - `validateHook()`: Use it to validate the data before sending to the Database. diff --git a/src/Model.php b/src/Model.php index 4f4848d..436a28e 100644 --- a/src/Model.php +++ b/src/Model.php @@ -256,6 +256,8 @@ public function __set($column, $value) throw new UnknownColumnException(); } + $value = $this->onColumnChangeHook($column, $value); + if (array_key_exists($column, static::FOREIGN_KEYS)) { $foreign_map = static::FOREIGN_KEYS[$column]; if ($value instanceof $foreign_map[0]) { @@ -1064,6 +1066,18 @@ protected static function validate($data, $full) * ========================================================================= */ + /** + * Called when a column is changed + * + * Useful to filter data before storing in the model + * + * @return mixed New column value + */ + protected function onColumnChangeHook($column, $value) + { + return $value; + } + /** * Called on the first time a model is saved * From d589c0a268eda9ea8bd42736d2ee18b30b450b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Sat, 17 Feb 2018 09:30:17 -0300 Subject: [PATCH 15/28] Make Person::document*() static --- CHANGELOG.md | 1 + src/Models/Person.php | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 6822898..f1fb323 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -23,6 +23,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Update [aryelgois/utils] - Forbid assigning a fresh foreign model - `validateHook()` only receives the data to be validated +- Person methods ### Deprecated diff --git a/src/Models/Person.php b/src/Models/Person.php index 3ff24fd..4db136d 100644 --- a/src/Models/Person.php +++ b/src/Models/Person.php @@ -25,31 +25,34 @@ class Person extends Medools\Model const COLUMNS = ['id', 'name', 'document']; /** - * Validates Person's document as Brazilian CPF or CNPJ + * Validates a document as Brazilian CPF or CNPJ + * + * @param boolean $document Data to be validated * * @return mixed[] With keys 'type' and 'valid' * @return false If document is invalid * @return null If document is not set */ - public function documentValidate() + public static function documentValidate($document) { - if (!isset($this->document)) { + if (!isset($document)) { return null; } - return Utils\Validation::document($this->document); + return Utils\Validation::document($document); } /** - * Formats Person's Document + * Formats a document * - * @param boolean $prepend If should prepend the document name + * @param boolean $document Data to be formated + * @param boolean $prepend If should prepend the document type * * @return string Formatted document * @return string Unformatted document if it is invalid * @return null If document is not set */ - public function documentFormat($prepend = false) + public static function documentFormat($document, $prepend = false) { - return Utils\Format::document($this->document, $prepend); + return Utils\Format::document($document, $prepend); } } From 71eece61f737dfbd57e3b880217134bf5cca4706 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Sat, 17 Feb 2018 09:31:30 -0300 Subject: [PATCH 16/28] Add Person::onColumnChangeHook() --- src/Models/Person.php | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/Models/Person.php b/src/Models/Person.php index 4db136d..c15a6db 100644 --- a/src/Models/Person.php +++ b/src/Models/Person.php @@ -55,4 +55,18 @@ public static function documentFormat($document, $prepend = false) { return Utils\Format::document($document, $prepend); } + + /** + * Called when a column is changed + * + * @return mixed New column value + */ + protected function onColumnChangeHook($column, $value) + { + if ($column == 'document') { + $value = static::documentValidate($value)['valid'] ?? $value; + } + + return $value; + } } From 26cf0f625f48869d9b2c2f2a7866621c46ba1fab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Sat, 17 Feb 2018 09:53:08 -0300 Subject: [PATCH 17/28] Rename Hook to Event --- CHANGELOG.md | 3 ++- README.md | 26 ++++++++++++-------------- src/Model.php | 18 +++++++++--------- src/Models/Person.php | 2 +- 4 files changed, 24 insertions(+), 25 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f1fb323..7599183 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - `getIterator()` - `getRequiredColumns()` - `isFresh()` - - `onColumnChangeHook()` + - `onColumnChange()` - `undo()` ### Changed @@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Forbid assigning a fresh foreign model - `validateHook()` only receives the data to be validated - Person methods +- Rename Hook to Event ### Deprecated diff --git a/README.md b/README.md index 68d58eb..57bc274 100644 --- a/README.md +++ b/README.md @@ -28,7 +28,7 @@ Index: - [SOFT_DELETE] - [SOFT_DELETE_MODE] - [Advanced] - - [Hooks] + - [Events] - [ModelManager] - [Changelog] @@ -190,7 +190,7 @@ Useful methods that are available: You can also add custom methods in your models, to automatically get some data in a format, or for doing a specific task. -> There are also [hook methods][hooks] that are automatically called by some +> There are also [event methods][events] that are automatically called by some > base methods. @@ -359,21 +359,19 @@ Possible value | When not deleted | When deleted # Advanced -## Hooks +## Events -There is a Hook concept in this framework, where you can add specific methods -which are automatically called by default methods. It makes easier to extend -some functionalities. +There are some methods that can be extended by overriding event methods. It +makes easier to extend some functionalities. -Currently, these hooks are available: +Currently, these events are available: -- `onColumnChangeHook()`: Called when a column is changed. Useful to filter data +- `onColumnChange()`: Called when a column is changed. Useful to filter data before storing in the model -- `onFirstSaveHook()`: Called on the first time a model is saved -- `onSaveHook()`: Called every time a model is saved -- `validateHook()`: Use it to validate the data before sending to the Database. - Make sure your code can validate some columns or all of them, depending on the - `$full` argument. +- `onFirstSave()`: Called on the first time a model is saved +- `onSave()`: Called every time a model is saved +- `onValidate()`: Called when data needs to be validated, before storig in the + Database ## ModelManager @@ -415,7 +413,7 @@ this class or in the model. [SOFT_DELETE]: #soft_delete [SOFT_DELETE_MODE]: #soft_delete_mode [Advanced]: #advanced -[Hooks]: #hooks +[Events]: #events [ModelManager]: #modelmanager [config_example]: config/example.php diff --git a/src/Model.php b/src/Model.php index 436a28e..592ed00 100644 --- a/src/Model.php +++ b/src/Model.php @@ -256,7 +256,7 @@ public function __set($column, $value) throw new UnknownColumnException(); } - $value = $this->onColumnChangeHook($column, $value); + $value = $this->onColumnChange($column, $value); if (array_key_exists($column, static::FOREIGN_KEYS)) { $foreign_map = static::FOREIGN_KEYS[$column]; @@ -323,8 +323,8 @@ public function save() $is_fresh = $this->isFresh(); - if (($is_fresh && !$this->onFirstSaveHook()) - || !$this->onSaveHook() + if (($is_fresh && !$this->onFirstSave()) + || !$this->onSave() || empty($this->changes) ) { return false; @@ -1049,7 +1049,7 @@ protected static function validate($data, $full) /* * Expanded validation */ - $result = static::validateHook($data); + $result = static::onValidate($data); if ($result === false) { throw new \UnexpectedValueException('Invalid data'); } elseif (is_array($result)) { @@ -1062,7 +1062,7 @@ protected static function validate($data, $full) } /* - * Hook methods + * Events methods * ========================================================================= */ @@ -1073,7 +1073,7 @@ protected static function validate($data, $full) * * @return mixed New column value */ - protected function onColumnChangeHook($column, $value) + protected function onColumnChange($column, $value) { return $value; } @@ -1083,7 +1083,7 @@ protected function onColumnChangeHook($column, $value) * * @return boolean for success or failure */ - protected function onFirstSaveHook() + protected function onFirstSave() { return true; } @@ -1093,7 +1093,7 @@ protected function onFirstSaveHook() * * @return boolean for success or failure */ - protected function onSaveHook() + protected function onSave() { return true; } @@ -1109,7 +1109,7 @@ protected function onSaveHook() * @return mixed[] For success with a validation patch to $data * @return boolean For success or failure */ - protected static function validateHook($data) + protected static function onValidate($data) { return true; } diff --git a/src/Models/Person.php b/src/Models/Person.php index c15a6db..9175fbc 100644 --- a/src/Models/Person.php +++ b/src/Models/Person.php @@ -61,7 +61,7 @@ public static function documentFormat($document, $prepend = false) * * @return mixed New column value */ - protected function onColumnChangeHook($column, $value) + protected function onColumnChange($column, $value) { if ($column == 'document') { $value = static::documentValidate($value)['valid'] ?? $value; From a813d67fca0313b1c30b5eebe741ce01b4ab452b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Sat, 17 Feb 2018 10:10:50 -0300 Subject: [PATCH 18/28] Fix DocBlocks --- src/Model.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Model.php b/src/Model.php index 592ed00..eb4d20b 100644 --- a/src/Model.php +++ b/src/Model.php @@ -173,9 +173,9 @@ abstract class Model implements \JsonSerializable * * @param mixed $where @see load(). If null, a fresh model is created * + * @throws \InvalidArgumentException If could not load from Database * @throws \InvalidArgumentException @see load() * @throws ForeignConstraintException @see load() - * @throws \InvalidArgumentException If could not load from Database */ public function __construct($where = null) { @@ -282,7 +282,7 @@ public function __set($column, $value) * * @see __set() * - * @param [type] $column A known column + * @param string $column A known column * * @throws ReadOnlyModelException * @throws UnknownColumnException From 0a71c89077176807208b88df3f4319b141cc752a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Sat, 17 Feb 2018 11:18:48 -0300 Subject: [PATCH 19/28] Improve exceptions --- CHANGELOG.md | 1 + src/Exceptions/NotForeignColumnException.php | 12 +++- src/MedooConnection.php | 2 +- src/Model.php | 63 ++++++++++++-------- src/Traits/ColumnsException.php | 15 +++-- 5 files changed, 58 insertions(+), 35 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 7599183..c313c9e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,6 +25,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - `validateHook()` only receives the data to be validated - Person methods - Rename Hook to Event +- Improve exceptions ### Deprecated diff --git a/src/Exceptions/NotForeignColumnException.php b/src/Exceptions/NotForeignColumnException.php index 3553fce..6af0ca1 100644 --- a/src/Exceptions/NotForeignColumnException.php +++ b/src/Exceptions/NotForeignColumnException.php @@ -15,4 +15,14 @@ * @link https://www.github.com/aryelgois/Medools */ class NotForeignColumnException extends \InvalidArgumentException -{} +{ + public function __construct( + string $model, + string $column, + Throwable $previous = null + ) { + $message = "$model (`$column`) has no Foreign Key constraint"; + + parent::__construct($message, 0, $previous); + } +} diff --git a/src/MedooConnection.php b/src/MedooConnection.php index 13e5f51..b219299 100644 --- a/src/MedooConnection.php +++ b/src/MedooConnection.php @@ -88,7 +88,7 @@ public static function getInstance($database, $anonymous = false) throw new \BadMethodCallException('Medools config was not loaded'); } if (!array_key_exists($database, self::$config['databases'])) { - throw new \RuntimeException('Unknown database'); + throw new \RuntimeException("Unknown database '$database'"); } if ($anonymous || !array_key_exists($database, self::$instances)) { diff --git a/src/Model.php b/src/Model.php index eb4d20b..01cc033 100644 --- a/src/Model.php +++ b/src/Model.php @@ -180,7 +180,8 @@ abstract class Model implements \JsonSerializable public function __construct($where = null) { if ($where !== null && !$this->load($where)) { - throw new \InvalidArgumentException('Could not load from Database'); + $message = 'Could not load ' . static::class . ' from Database'; + throw new \InvalidArgumentException($message); } } @@ -199,7 +200,7 @@ public function __construct($where = null) public function __get($column) { if (!in_array($column, static::COLUMNS)) { - throw new UnknownColumnException(); + throw new UnknownColumnException(static::class, $column); } if (array_key_exists($column, $this->changes) @@ -250,10 +251,10 @@ public function __isset($column) public function __set($column, $value) { if (static::READ_ONLY) { - throw new ReadOnlyModelException(); + throw new ReadOnlyModelException(static::class); } if (!in_array($column, static::COLUMNS)) { - throw new UnknownColumnException(); + throw new UnknownColumnException(static::class, $column); } $value = $this->onColumnChange($column, $value); @@ -318,7 +319,7 @@ public function __wakeup() public function save() { if (static::READ_ONLY) { - throw new ReadOnlyModelException(); + throw new ReadOnlyModelException(static::class); } $is_fresh = $this->isFresh(); @@ -420,10 +421,11 @@ public function load($where) public function update($columns) { if (static::READ_ONLY) { - throw new ReadOnlyModelException(); + throw new ReadOnlyModelException(static::class); } if ($this->isFresh()) { - throw new \LogicException('Can not update a fresh Model'); + $message = 'Can not update fresh Model: ' . static::class; + throw new \LogicException($message); } $this->updateStampColumns($columns); @@ -463,7 +465,7 @@ public function update($columns) public function delete() { if (static::READ_ONLY) { - throw new ReadOnlyModelException(); + throw new ReadOnlyModelException(static::class); } $database = self::getDatabase(); @@ -483,9 +485,11 @@ public function delete() break; default: - throw new \LogicException( - "Unknown mode '" . static::SOFT_DELETE_MODE . "'" - ); + throw new \LogicException(sprintf( + "%s has invalid SOFT_DELETE_MODE mode: '%s'", + static::class, + static::SOFT_DELETE_MODE + )); break; } return $this->update($column); @@ -517,7 +521,7 @@ public static function dump($where = [], $columns = []) if (empty($columns)) { $columns = static::COLUMNS; } elseif (!empty($invalid = array_diff($columns, static::COLUMNS))) { - throw new UnknownColumnException($invalid); + throw new UnknownColumnException(static::class, $invalid); } $database = self::getDatabase(); @@ -692,10 +696,11 @@ public function toArray() public function undelete() { if (static::READ_ONLY) { - throw new ReadOnlyModelException(); + throw new ReadOnlyModelException(static::class); } if (static::SOFT_DELETE === null) { - throw new \LogicException('Model is not soft-deletable'); + $message = 'Model ' . static::class . ' is not soft-deletable'; + throw new \LogicException($message); } $database = self::getDatabase(); @@ -715,9 +720,11 @@ public function undelete() break; default: - throw new \LogicException( - "Unknown mode '" . static::SOFT_DELETE_MODE . "'" - ); + throw new \LogicException(sprintf( + "%s has invalid SOFT_DELETE_MODE mode: '%s'", + static::class, + static::SOFT_DELETE_MODE + )); break; } @@ -740,7 +747,7 @@ public function undo(string $column = null) $this->changes = []; } else { if (!in_array($column, static::COLUMNS)) { - throw new UnknownColumnException(); + throw new UnknownColumnException(static::class, $column); } unset($this->changes[$column]); } @@ -841,10 +848,10 @@ public function jsonSerialize() protected function loadForeign($column, $value) { if (!in_array($column, static::COLUMNS)) { - throw new UnknownColumnException(); + throw new UnknownColumnException(static::class, $column); } if (!array_key_exists($column, static::FOREIGN_KEYS)) { - throw new NotForeignColumnException(); + throw new NotForeignColumnException(static::class, $column); } $foreign_map = static::FOREIGN_KEYS[$column]; @@ -946,7 +953,7 @@ final public static function processWhere($where) $where = @array_combine(static::PRIMARY_KEY, $where); if ($where === false) { throw new \InvalidArgumentException( - 'Could not solve Primary Key' + 'Could not solve Primary Key for ' . static::class ); } } @@ -1003,7 +1010,12 @@ public function updateStampColumns($subset = null) break; default: - throw new \LogicException("Unknown mode '$mode'"); + throw new \LogicException(sprintf( + "%s (`%s`) has invalid STAMP_COLUMNS mode: '%s'", + static::class, + $column, + $mode + )); break; } } @@ -1034,7 +1046,7 @@ protected static function validate($data, $full) if ($full) { $missing = array_diff(static::getRequiredColumns(), $columns); if (!empty($missing)) { - throw new MissingColumnException($missing); + throw new MissingColumnException(static::class, $missing); } } @@ -1043,7 +1055,7 @@ protected static function validate($data, $full) */ $unknown = array_diff($columns, static::COLUMNS); if (!empty($unknown)) { - throw new UnknownColumnException($unknown); + throw new UnknownColumnException(static::class, $unknown); } /* @@ -1051,7 +1063,8 @@ protected static function validate($data, $full) */ $result = static::onValidate($data); if ($result === false) { - throw new \UnexpectedValueException('Invalid data'); + $message = static::class . ' has invalid data'; + throw new \UnexpectedValueException($message); } elseif (is_array($result)) { $data = (empty(Utils::arrayUniqueDiffKey($data, $result))) ? $result diff --git a/src/Traits/ColumnsException.php b/src/Traits/ColumnsException.php index 7ecbfa5..8f89277 100644 --- a/src/Traits/ColumnsException.php +++ b/src/Traits/ColumnsException.php @@ -16,14 +16,13 @@ */ trait ColumnsException { - public function __construct($columns = [], Throwable $previous = null) - { - if (is_array($columns)) { - $columns = implode("', '", $columns); - } - $message = ($columns !== '') - ? "'" . $columns . "'" - : ''; + public function __construct( + string $model, + $columns, + Throwable $previous = null + ) { + $columns = implode("', '", (array) $columns); + $message = "$model does not have '$columns'"; parent::__construct($message, 0, $previous); } From 2c88b2e528691fa4f64f935f0f183ec468f9fb05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Sat, 17 Feb 2018 11:20:04 -0300 Subject: [PATCH 20/28] Fix delete fresh soft model --- CHANGELOG.md | 1 + src/Model.php | 3 +++ 2 files changed, 4 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index c313c9e..47e9072 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -34,6 +34,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Fixed - ModelIterator and ModelManager `__construct()`: Ensure a model class is used, and not a model instance +- Delete fresh soft model ### Security diff --git a/src/Model.php b/src/Model.php index 01cc033..33a4508 100644 --- a/src/Model.php +++ b/src/Model.php @@ -492,6 +492,9 @@ public function delete() )); break; } + if ($this->isFresh()) { + return true; + } return $this->update($column); } else { $stmt = $database->delete(static::TABLE, $this->getPrimaryKey()); From c3a9bdeb1ac637a12ba19d41a347106e4a565aef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Sat, 17 Feb 2018 11:21:17 -0300 Subject: [PATCH 21/28] Update delete() --- src/Model.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/Model.php b/src/Model.php index 33a4508..9bc0fa7 100644 --- a/src/Model.php +++ b/src/Model.php @@ -496,12 +496,11 @@ public function delete() return true; } return $this->update($column); - } else { - $stmt = $database->delete(static::TABLE, $this->getPrimaryKey()); - ModelManager::remove($this); - $this->reset(); - return ($stmt->rowCount() > 0); } + $stmt = $database->delete(static::TABLE, $this->getPrimaryKey()); + ModelManager::remove($this); + $this->reset(); + return ($stmt->rowCount() > 0); } /* From 0bce27b8afafe4adeacbbc2bff0e23229796e0c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Sat, 17 Feb 2018 11:22:31 -0300 Subject: [PATCH 22/28] Fix processWhere() Do not modify argument, for better exception message --- src/Model.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/Model.php b/src/Model.php index 9bc0fa7..de055ae 100644 --- a/src/Model.php +++ b/src/Model.php @@ -950,16 +950,16 @@ final public static function processWhere($where) if ($where === null) { throw new \InvalidArgumentException('Primary Key can not be null'); } - $where = (array) $where; - if (!Utils::arrayIsAssoc($where)) { - $where = @array_combine(static::PRIMARY_KEY, $where); - if ($where === false) { + $result = (array) $where; + if (!Utils::arrayIsAssoc($result)) { + $result = @array_combine(static::PRIMARY_KEY, $result); + if ($result === false) { throw new \InvalidArgumentException( 'Could not solve Primary Key for ' . static::class ); } } - return $where; + return $result; } /** From a5792da6db858a1ecb980cd15e3bc6cf8688eeaf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Sat, 17 Feb 2018 11:24:25 -0300 Subject: [PATCH 23/28] Fix DocBlock --- src/Model.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Model.php b/src/Model.php index de055ae..94fe875 100644 --- a/src/Model.php +++ b/src/Model.php @@ -938,7 +938,8 @@ final protected static function normalizeColumnList($list, $default = null) * * @param mixed $where Value for Primary Key or \Medoo\Medoo where clause * - * @return boolean For success or failure + * @return mixed For success + * @return false For failure * * @throws \InvalidArgumentException If $where is null * @throws \InvalidArgumentException If could not solve Primary Key: From 25d5ebef2f82a6ecb2bc24466ae3b354b2e9bad5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Sat, 17 Feb 2018 11:33:38 -0300 Subject: [PATCH 24/28] Add unreleased change --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 47e9072..1e62a99 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -30,6 +30,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Deprecated ### Removed +- Remove setMultiple() ### Fixed - ModelIterator and ModelManager `__construct()`: Ensure a model class is used, From 339b80d493aa14c61f2a37cfb540f75e4435ee7c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Sat, 17 Feb 2018 11:53:41 -0300 Subject: [PATCH 25/28] Add checkUnknownColumn() --- CHANGELOG.md | 1 + src/Model.php | 56 ++++++++++++++++++++++++++------------------------- 2 files changed, 30 insertions(+), 27 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e62a99..ecb380b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ### Added - Model `fill()` example - Model methods: + - `checkUnknownColumn()` - `getIterator()` - `getRequiredColumns()` - `isFresh()` diff --git a/src/Model.php b/src/Model.php index a12b464..bc82857 100644 --- a/src/Model.php +++ b/src/Model.php @@ -194,14 +194,12 @@ public function __construct($where = null) * * @return mixed * - * @throws UnknownColumnException + * @throws UnknownColumnException @see checkUnknownColumn() * @throws ForeignConstraintException @see loadForeign() */ public function __get($column) { - if (!in_array($column, static::COLUMNS)) { - throw new UnknownColumnException(static::class, $column); - } + static::checkUnknownColumn($column); if (array_key_exists($column, $this->changes) && $this->changes[$column] === null @@ -245,7 +243,7 @@ public function __isset($column) * @param mixed $value The new value * * @throws ReadOnlyModelException - * @throws UnknownColumnException + * @throws UnknownColumnException @see checkUnknownColumn() * @throws ForeignConstraintException */ public function __set($column, $value) @@ -253,9 +251,7 @@ public function __set($column, $value) if (static::READ_ONLY) { throw new ReadOnlyModelException(static::class); } - if (!in_array($column, static::COLUMNS)) { - throw new UnknownColumnException(static::class, $column); - } + static::checkUnknownColumn($column); $value = $this->onColumnChange($column, $value); @@ -286,7 +282,7 @@ public function __set($column, $value) * @param string $column A known column * * @throws ReadOnlyModelException - * @throws UnknownColumnException + * @throws UnknownColumnException @see __set() * @throws ForeignConstraintException */ public function __unset($column) @@ -517,13 +513,14 @@ public function delete() * @return array[] * * @throws UnknownColumnException If any item in $columns is invalid + * @see checkUnknownColumn() */ public static function dump($where = [], $columns = []) { if (empty($columns)) { $columns = static::COLUMNS; - } elseif (!empty($invalid = array_diff($columns, static::COLUMNS))) { - throw new UnknownColumnException(static::class, $invalid); + } else { + static::checkUnknownColumn($columns); } $database = self::getDatabase(); @@ -721,16 +718,14 @@ public function undelete() * * @param string $column Which column to undo * - * @throws UnknownColumnException + * @throws UnknownColumnException @see checkUnknownColumn() */ public function undo(string $column = null) { if ($column === null) { $this->changes = []; } else { - if (!in_array($column, static::COLUMNS)) { - throw new UnknownColumnException(static::class, $column); - } + static::checkUnknownColumn($column); unset($this->changes[$column]); } } @@ -740,6 +735,21 @@ public function undo(string $column = null) * ========================================================================= */ + /** + * Tests if model has columns + * + * @param string|string[] $columns List of columns to test + * + * @throws UnknownColumnException + */ + final public static function checkUnknownColumn($columns) + { + $unknown = array_diff((array) $columns, static::COLUMNS); + if (!empty($unknown)) { + throw new UnknownColumnException(static::class, $unknown); + } + } + /** * Cleans data keys, removing unwanted columns * @@ -823,15 +833,13 @@ public function jsonSerialize() * @param string $column A column in FOREIGN_KEYS keys * @param mixed $value A value in the foreign table * - * @throws UnknownColumnException + * @throws UnknownColumnException @see checkUnknownColumn() * @throws NotForeignColumnException * @throws ForeignConstraintException */ protected function loadForeign($column, $value) { - if (!in_array($column, static::COLUMNS)) { - throw new UnknownColumnException(static::class, $column); - } + static::checkUnknownColumn($column); if (!array_key_exists($column, static::FOREIGN_KEYS)) { throw new NotForeignColumnException(static::class, $column); } @@ -1016,7 +1024,7 @@ public function updateStampColumns($subset = null) * @return mixed[] Valid data * * @throws MissingColumnException - * @throws UnknownColumnException + * @throws UnknownColumnException @see checkUnknownColumn() * @throws \UnexpectedValueException If Invalid data is found */ protected static function validate($data, $full) @@ -1033,13 +1041,7 @@ protected static function validate($data, $full) } } - /* - * Check unknown columns - */ - $unknown = array_diff($columns, static::COLUMNS); - if (!empty($unknown)) { - throw new UnknownColumnException(static::class, $unknown); - } + static::checkUnknownColumn($columns); /* * Expanded validation From 8498b5d57746405c5e4ef6051a64816f7bb77770 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Sat, 17 Feb 2018 11:58:47 -0300 Subject: [PATCH 26/28] Add checkReadOnly() --- CHANGELOG.md | 1 + src/Model.php | 44 +++++++++++++++++++++++--------------------- 2 files changed, 24 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ecb380b..b6af5c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Model `fill()` example - Model methods: - `checkUnknownColumn()` + - `checkReadOnly()` - `getIterator()` - `getRequiredColumns()` - `isFresh()` diff --git a/src/Model.php b/src/Model.php index bc82857..18c287d 100644 --- a/src/Model.php +++ b/src/Model.php @@ -242,15 +242,13 @@ public function __isset($column) * @param string $column A known column * @param mixed $value The new value * - * @throws ReadOnlyModelException + * @throws ReadOnlyModelException @see checkReadOnly() * @throws UnknownColumnException @see checkUnknownColumn() * @throws ForeignConstraintException */ public function __set($column, $value) { - if (static::READ_ONLY) { - throw new ReadOnlyModelException(static::class); - } + static::checkReadOnly(); static::checkUnknownColumn($column); $value = $this->onColumnChange($column, $value); @@ -281,7 +279,7 @@ public function __set($column, $value) * * @param string $column A known column * - * @throws ReadOnlyModelException + * @throws ReadOnlyModelException @see __set() * @throws UnknownColumnException @see __set() * @throws ForeignConstraintException */ @@ -310,13 +308,11 @@ public function __wakeup() * * @return boolean For success or failure * - * @throws ReadOnlyModelException + * @throws ReadOnlyModelException @see checkReadOnly() */ public function save() { - if (static::READ_ONLY) { - throw new ReadOnlyModelException(static::class); - } + static::checkReadOnly(); $is_fresh = $this->isFresh(); @@ -411,14 +407,12 @@ public function load($where) * * @return boolean For success or failure * - * @throws ReadOnlyModelException + * @throws ReadOnlyModelException @see checkReadOnly() * @throws \LogicException If trying to update a fresh Model */ public function update($columns) { - if (static::READ_ONLY) { - throw new ReadOnlyModelException(static::class); - } + static::checkReadOnly(); if ($this->isFresh()) { $message = 'Can not update fresh Model: ' . static::class; throw new \LogicException($message); @@ -455,14 +449,12 @@ public function update($columns) * * @return boolean For success or failure * - * @throws ReadOnlyModelException + * @throws ReadOnlyModelException @see checkReadOnly() * @throws \LogicException If SOFT_DELETE_MODE is unknown */ public function delete() { - if (static::READ_ONLY) { - throw new ReadOnlyModelException(static::class); - } + static::checkReadOnly(); $database = self::getDatabase(); $column = static::SOFT_DELETE; @@ -668,15 +660,13 @@ public function toArray() * * @return boolean For success or failure * - * @throws ReadOnlyModelException + * @throws ReadOnlyModelException @see checkReadOnly() * @throws \LogicException If the Model is not soft-deletable * @throws \LogicException If SOFT_DELETE_MODE is unknown */ public function undelete() { - if (static::READ_ONLY) { - throw new ReadOnlyModelException(static::class); - } + static::checkReadOnly(); if (static::SOFT_DELETE === null) { $message = 'Model ' . static::class . ' is not soft-deletable'; throw new \LogicException($message); @@ -735,6 +725,18 @@ public function undo(string $column = null) * ========================================================================= */ + /** + * Tests if model is READ_ONLY + * + * @throws ReadOnlyModelException + */ + final public static function checkReadOnly() + { + if (static::READ_ONLY) { + throw new ReadOnlyModelException(static::class); + } + } + /** * Tests if model has columns * From 4b0d3dc81e2da1177988729deeadbe3b95669197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Sat, 17 Feb 2018 12:01:40 -0300 Subject: [PATCH 27/28] Add new lines --- src/Model.php | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Model.php b/src/Model.php index 18c287d..c904ce9 100644 --- a/src/Model.php +++ b/src/Model.php @@ -413,6 +413,7 @@ public function load($where) public function update($columns) { static::checkReadOnly(); + if ($this->isFresh()) { $message = 'Can not update fresh Model: ' . static::class; throw new \LogicException($message); @@ -667,6 +668,7 @@ public function toArray() public function undelete() { static::checkReadOnly(); + if (static::SOFT_DELETE === null) { $message = 'Model ' . static::class . ' is not soft-deletable'; throw new \LogicException($message); @@ -842,6 +844,7 @@ public function jsonSerialize() protected function loadForeign($column, $value) { static::checkUnknownColumn($column); + if (!array_key_exists($column, static::FOREIGN_KEYS)) { throw new NotForeignColumnException(static::class, $column); } From 86b296f70f2d36cb3a8153008134da82c08bbbcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Aryel=20Mota=20G=C3=B3is?= Date: Sat, 17 Feb 2018 12:20:03 -0300 Subject: [PATCH 28/28] Prepare 4.0.0 Fix Removed section --- CHANGELOG.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b6af5c1..7f08ddd 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] + +## [4.0.0] - 2018-02-17 + ### Added - Model `fill()` example - Model methods: @@ -29,18 +32,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Rename Hook to Event - Improve exceptions -### Deprecated - ### Removed -- Remove setMultiple() +- `setMultiple()` ### Fixed - ModelIterator and ModelManager `__construct()`: Ensure a model class is used, and not a model instance - Delete fresh soft model -### Security - ## [3.1.1] - 2018-02-09 @@ -173,7 +172,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - DatabaseObject.php -[Unreleased]: https://github.com/aryelgois/Medools/compare/v3.1.1...develop +[Unreleased]: https://github.com/aryelgois/Medools/compare/v4.0.0...develop +[4.0.0]: https://github.com/aryelgois/Medools/compare/v3.1.0...v4.0.0 [3.1.1]: https://github.com/aryelgois/Medools/compare/v3.1.0...v3.1.1 [3.1.0]: https://github.com/aryelgois/Medools/compare/v3.0...v3.1.0 [3.0]: https://github.com/aryelgois/Medools/compare/v3.0-alpha...v3.0