Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Мove Scope class to Model NS #672

Merged
merged 1 commit into from
Jul 24, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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