Skip to content

Commit

Permalink
[update] move Scope class to Model NS (#672)
Browse files Browse the repository at this point in the history
  • Loading branch information
georgehristov authored Jul 24, 2020
1 parent 2f89724 commit 120d748
Show file tree
Hide file tree
Showing 6 changed files with 72 additions and 79 deletions.
123 changes: 58 additions & 65 deletions docs/conditions.rst
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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);
Expand All @@ -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
-------------------------------

Expand Down
2 changes: 1 addition & 1 deletion src/Action/Iterator.php
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
20 changes: 10 additions & 10 deletions src/Model/Scope/Scope.php → src/Model/Scope.php
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -11,7 +11,7 @@
/**
* @property AbstractScope[] $elements
*/
class Scope extends AbstractScope
class Scope extends Scope\AbstractScope
{
use ContainerTrait;

Expand All @@ -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)
{
Expand All @@ -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);
Expand All @@ -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);
Expand All @@ -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()
{
Expand Down Expand Up @@ -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();
Expand Down
2 changes: 1 addition & 1 deletion src/Model/Scope/RootScope.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion src/Persistence/Sql.php
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
2 changes: 1 addition & 1 deletion tests/ScopeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 120d748

Please sign in to comment.