diff --git a/docs/conditions.rst b/docs/conditions.rst index aedaa8f7d..4409984d6 100644 --- a/docs/conditions.rst +++ b/docs/conditions.rst @@ -268,44 +268,6 @@ This method provides access to the model scope enabling conditions to be added:: $contact->scope()->addCondition($condition); // adding condition to a model -.. php:namespace:: atk4\data\Model\Scope - -.. php:class:: Condition - -Condition represents a simple condition in a form [field, operation, value], similar to the functionality of the -Model::addCondition method - -.. php:method:: __construct($key, $operator = null, $value = null); - -Creates condition object based on provided arguments. It acts similar to Model::addCondition - -$key can be Model field name, Field object, Expression object, FALSE (interpreted as Expression('false')), TRUE (interpreted as empty condition) or an array in the form of [$key, $operator, $value] -$operator can be one of the supported operators >, <, >=, <=, !=, in, not in, like, not like, regexp, not regexp -$value can be Field object, Expression object, array (interpreted as 'any of the values') or other scalar value - -If $value is omitted as argument then $operator is considered as $value and '=' is used as operator - -.. php:method:: negate(); - -Negates the condition, e.g:: - - // results in 'name is not John' - $condition = (new Condition('name', 'John'))->negate(); - -.. php:method:: on(Model $model); - -Sets the model of Condition to a clone of $model to avoid changes to the original object.:: - - // uses the $contact model to conver the condition to human readable words - $condition->toWords($contact); - -.. php:method:: toWords($asHtml = false); - -Converts the condition object to human readable words. Model must be set first:: - - // results in 'Contact where Name is John' - (new Condition('name', 'John'))->toWords($contactModel); - .. php:class:: Scope Scope object has a single defined junction (AND or OR) and can contain multiple nested Condition and/or Scope objects referred to as nested conditions. @@ -315,52 +277,52 @@ e.g ((Name like 'ABC%' and Country = 'US') or (Name like 'CDE%' and (Country = ' Scope can be created using new Scope() statement from an array or joining Condition objects or condition arguments arrays:: // $condition1 will be used as nested condition - $condition1 = new Condition('name', 'like', 'ABC%'); + $condition1 = new Condition('name', 'like', 'ABC%'); // $condition2 will converted to Condtion object and used as nested condition - $condition2 = ['country', 'US']; - + $condition2 = ['country', 'US']; + // $scope1 is created using AND as junction and $condition1 and $condition2 as nested conditions - $scope1 = Scope::createAnd($condition1, $condition2); - - $condition3 = new Condition('country', 'DE'); - $condition4 = ['surname', 'XYZ']; - + $scope1 = Scope::createAnd($condition1, $condition2); + + $condition3 = new Condition('country', 'DE'); + $condition4 = ['surname', 'XYZ']; + // $scope2 is created using OR as junction and $condition3 and $condition4 as nested conditions - $scope2 = Scope::createOr($condition3, $condition4); + $scope2 = Scope::createOr($condition3, $condition4); - $condition5 = new Condition('name', 'like', 'CDE%'); - + $condition5 = new Condition('name', 'like', 'CDE%'); + // $scope3 is created using AND as junction and $condition5 and $scope2 as nested conditions - $scope3 = Scope::createAnd($condition5, $scope2); + $scope3 = Scope::createAnd($condition5, $scope2); // $scope is created using OR as junction and $scope1 and $scope3 as nested conditions - $scope = Scope::createOr($scope1, $scope3); - - + $scope = Scope::createOr($scope1, $scope3); + + Scope is an independent object not related to any model. Applying scope to model is using the Model::scope()->add($condition) method:: - $contact->scope()->add($condition); // adding condition to a model - $contact->scope()->add($conditionXYZ); // adding more conditions - + $contact->scope()->add($condition); // adding condition to a model + $contact->scope()->add($conditionXYZ); // adding more conditions + .. php:method:: __construct($nestedConditions = [], $junction = Scope::AND); Creates a Scope object from an array:: - // below will create 2 conditions and nest them in a compound conditions with AND junction - $scope1 = new Scope([ - ['name', 'like', 'ABC%'], - ['country', 'US'] - ]); - + // below will create 2 conditions and nest them in a compound conditions with AND junction + $scope1 = new Scope([ + ['name', 'like', 'ABC%'], + ['country', 'US'] + ]); + .. php:method:: negate(); Negate method has behind the full map of conditions so any condition object can be negated, e.g negating '>=' results in '<', etc. For compound conditionss this method is using De Morgan's laws, e.g:: - // using $scope1 defined above - // results in "(Name not like 'ABC%') or (Country does not equal 'US')" - $scope1->negate(); + // using $scope1 defined above + // results in "(Name not like 'ABC%') or (Country does not equal 'US')" + $scope1->negate(); .. php:method:: createAnd(...$conditions); @@ -386,6 +348,37 @@ Checks if scope components are joined by OR Checks if scope components are joined by AND +.. php:namespace:: atk4\data\Model\Scope + +.. php:class:: Condition + +Condition represents a simple condition in a form [field, operation, value], similar to the functionality of the +Model::addCondition method + +.. php:method:: __construct($key, $operator = null, $value = null); + +Creates condition object based on provided arguments. It acts similar to Model::addCondition + +$key can be Model field name, Field object, Expression object, FALSE (interpreted as Expression('false')), TRUE (interpreted as empty condition) or an array in the form of [$key, $operator, $value] +$operator can be one of the supported operators >, <, >=, <=, !=, in, not in, like, not like, regexp, not regexp +$value can be Field object, Expression object, array (interpreted as 'any of the values') or other scalar value + +If $value is omitted as argument then $operator is considered as $value and '=' is used as operator + +.. php:method:: negate(); + +Negates the condition, e.g:: + + // results in 'name is not John' + $condition = (new Condition('name', 'John'))->negate(); + +.. php:method:: toWords(Model $model = null); + +Converts the condition object to human readable words. Condition must be assigned to a model or model argument provided:: + + // results in 'Contact where Name is John' + (new Condition('name', 'John'))->toWords($contactModel); + Conditions on Referenced Models ------------------------------- diff --git a/src/Action/Iterator.php b/src/Action/Iterator.php index 3e28426ef..9ad0d649c 100644 --- a/src/Action/Iterator.php +++ b/src/Action/Iterator.php @@ -123,7 +123,7 @@ protected function match(array $row, Model\Scope\AbstractScope $condition) } // nested conditions - if ($condition instanceof Model\Scope\Scope) { + if ($condition instanceof Model\Scope) { $matches = []; foreach ($condition->getNestedConditions() as $nestedCondition) { diff --git a/src/Model/Scope/Scope.php b/src/Model/Scope.php similarity index 88% rename from src/Model/Scope/Scope.php rename to src/Model/Scope.php index e83eca250..742f65bf8 100644 --- a/src/Model/Scope/Scope.php +++ b/src/Model/Scope.php @@ -2,7 +2,7 @@ declare(strict_types=1); -namespace atk4\data\Model\Scope; +namespace atk4\data\Model; use atk4\core\ContainerTrait; use atk4\data\Exception; @@ -11,7 +11,7 @@ /** * @property AbstractScope[] $elements */ -class Scope extends AbstractScope +class Scope extends Scope\AbstractScope { use ContainerTrait; @@ -29,7 +29,7 @@ class Scope extends AbstractScope /** * Create a Scope from array of condition objects or condition arrays. * - * @param AbstractScope[]|array[] $nestedConditions + * @param Scope\AbstractScope[]|array[] $nestedConditions */ public function __construct(array $nestedConditions = [], string $junction = self::AND) { @@ -41,13 +41,13 @@ public function __construct(array $nestedConditions = [], string $junction = sel $this->junction = $junction; foreach ($nestedConditions as $nestedCondition) { - if ($nestedCondition instanceof AbstractScope) { + if ($nestedCondition instanceof Scope\AbstractScope) { $condition = $nestedCondition; } else { if (!is_array($nestedCondition)) { $nestedCondition = [$nestedCondition]; } - $condition = new Condition(...$nestedCondition); + $condition = new Scope\Condition(...$nestedCondition); } $this->add($condition); @@ -70,12 +70,12 @@ public function __clone() */ public function addCondition($field, $operator = null, $value = null) { - if (func_num_args() === 1 && $field instanceof AbstractScope) { + if (func_num_args() === 1 && $field instanceof Scope\AbstractScope) { $condition = $field; } elseif (func_num_args() === 1 && is_array($field)) { $condition = static::createAnd(func_get_args()); } else { - $condition = new Condition(...func_get_args()); + $condition = new Scope\Condition(...func_get_args()); } $this->add($condition); @@ -86,7 +86,7 @@ public function addCondition($field, $operator = null, $value = null) /** * Return array of nested conditions. * - * @return AbstractScope[] + * @return Scope\AbstractScope[] */ public function getNestedConditions() { @@ -146,13 +146,13 @@ public function clear() return $this; } - public function simplify(): AbstractScope + public function simplify(): Scope\AbstractScope { if (count($this->elements) !== 1) { return $this; } - /** @var AbstractScope $component */ + /** @var Scope\AbstractScope $component */ $component = reset($this->elements); return $component->simplify(); diff --git a/src/Model/Scope/RootScope.php b/src/Model/Scope/RootScope.php index 5bf65cba1..88048dbe4 100644 --- a/src/Model/Scope/RootScope.php +++ b/src/Model/Scope/RootScope.php @@ -12,7 +12,7 @@ * All other conditions of the Model object are elements of the root scope * Scope elements are joined only using AND junction. */ -class RootScope extends Scope +class RootScope extends Model\Scope { /** * @var Model diff --git a/src/Persistence/Sql.php b/src/Persistence/Sql.php index a60606e25..e628a6a06 100644 --- a/src/Persistence/Sql.php +++ b/src/Persistence/Sql.php @@ -371,7 +371,7 @@ public function initQueryConditions(Model $model, Query $query, Model\Scope\Abst } // nested conditions - if ($condition instanceof Model\Scope\Scope) { + if ($condition instanceof Model\Scope) { $expression = $condition->isOr() ? $query->orExpr() : $query->andExpr(); foreach ($condition->getNestedConditions() as $nestedCondition) { diff --git a/tests/ScopeTest.php b/tests/ScopeTest.php index c9d865b49..bf13a8922 100644 --- a/tests/ScopeTest.php +++ b/tests/ScopeTest.php @@ -5,8 +5,8 @@ namespace atk4\data\tests; use atk4\data\Model; +use atk4\data\Model\Scope; use atk4\data\Model\Scope\Condition; -use atk4\data\Model\Scope\Scope; use atk4\dsql\Expression; class SCountry extends Model