Completed
Push — master ( b6905f...386860 )
by Peter
07:45
created

AbstractScopeManager::apply()   B

Complexity

Conditions 6
Paths 18

Size

Total Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 19
CRAP Score 6

Importance

Changes 0
Metric Value
dl 0
loc 31
ccs 19
cts 19
cp 1
rs 8.8017
c 0
b 0
f 0
cc 6
nc 18
nop 1
crap 6
1
<?php
2
3
/**
4
 * This software package is licensed under AGPL or Commercial license.
5
 *
6
 * @package maslosoft/mangan
7
 * @licence AGPL or Commercial
8
 * @copyright Copyright (c) Piotr Masełkowski <[email protected]>
9
 * @copyright Copyright (c) Maslosoft
10
 * @copyright Copyright (c) Others as mentioned in code
11
 * @link https://maslosoft.com/mangan/
12
 */
13
14
namespace Maslosoft\Mangan\Abstracts;
15
16
use Maslosoft\Mangan\Criteria;
17
use Maslosoft\Mangan\Document;
18
use Maslosoft\Mangan\Interfaces\Criteria\DecoratableInterface;
19
use Maslosoft\Mangan\Interfaces\CriteriaAwareInterface;
20
use Maslosoft\Mangan\Interfaces\CriteriaInterface;
21
use Maslosoft\Mangan\Interfaces\ModelAwareInterface;
22
use Maslosoft\Mangan\Interfaces\ScopeInterface;
23
use Maslosoft\Mangan\Interfaces\ScopeManagerInterface;
24
use Maslosoft\Mangan\Interfaces\WithCriteriaInterface;
25
use Maslosoft\Mangan\Meta\ManganMeta;
26
use Maslosoft\Mangan\Traits\ModelAwareTrait;
27
28
/**
29
 * Base class for implementing scope managers
30
 *
31
 * @see ScopeManagerInterface
32
 * @author Piotr Maselkowski <pmaselkowski at gmail.com>
33
 */
34
abstract class AbstractScopeManager implements ModelAwareInterface
35
{
36
37
	use ModelAwareTrait;
38
39
	/**
40
	 *
41
	 * @var CriteriaInterface
42
	 */
43
	private $criteria = null;
44
45
	/**
46
	 * Returns the declaration of named scopes.
47
	 * A named scope represents a query criteria that can be chained together with
48
	 * other named scopes and applied to a query. This method should be overridden
49
	 * by child classes to declare named scopes for the particular document classes.
50
	 * For example, the following code declares two named scopes: 'recently' and
51
	 * 'published'.
52
	 * <pre>
53
	 * return array(
54
	 * 	'published'=>array(
55
	 * 		'conditions'=>array(
56
	 * 				'status'=>array('==', 1),
57
	 * 		),
58
	 * 	),
59
	 * 	'recently'=>array(
60
	 * 		'sort'=>array('create_time'=>Criteria::SortDesc),
61
	 * 		'limit'=>5,
62
	 * 	),
63
	 * );
64
	 * </pre>
65
	 * If the above scopes are declared in a 'Post' model, we can perform the following
66
	 * queries:
67
	 * <pre>
68
	 * $posts=Post::model()->published()->findAll();
69
	 * $posts=Post::model()->published()->recently()->findAll();
70
	 * $posts=Post::model()->published()->published()->recently()->find();
71
	 * </pre>
72
	 *
73
	 * @return array the scope definition. The array keys are scope names; the array
74
	 * values are the corresponding scope definitions. Each scope definition is represented
75
	 * as an array whose keys must be properties of {@link Criteria}.
76
	 * @since v1.0
77
	 */
78
	public function scopes()
79
	{
80
		return [];
81
	}
82
83
	/**
84
	 * Returns the default named scope that should be implicitly applied to all queries for this model.
85
	 * Note, default scope only applies to SELECT queries. It is ignored for INSERT, UPDATE and DELETE queries.
86
	 * The default implementation simply returns an empty array. You may override this method
87
	 * if the model needs to be queried with some default criteria (e.g. only active records should be returned).
88
	 * @return array the mongo criteria. This will be used as the parameter to the constructor
89
	 * of {@link Criteria}.
90
	 * @since v1.2.2
91
	 */
92
	public function defaultScope()
93
	{
94
		return [];
95
	}
96
97
	/**
98
	 * Resets all scopes and criteria applied including default scope.
99
	 *
100
	 * @return Document
101
	 * @since v1.0
102
	 */
103
	public function resetScope()
104
	{
105
		$this->criteria = $this->getNewCriteria();
106
		return $this;
107
	}
108
109
	/**
110
	 * Apply scopes to criteria, will create criteria object if not provided and pass it by reference
111
	 * @param CriteriaInterface|Criteria|array|null $criteria
112
	 * @return CriteriaInterface|Criteria
113
	 */
114 122
	public function apply(&$criteria = null)
115
	{
116 122
		if (null === $criteria)
117
		{
118 33
			$criteria = $this->getModelCriteria();
119
		}
120 116
		elseif (is_array($criteria))
121
		{
122 1
			$criteria = $this->getNewCriteria($criteria);
123
		}
124 122
		$criteria->mergeWith($this->criteria);
125 122
		$criteria->mergeWith($this->getModelCriteria());
126 122
		if ($criteria instanceof DecoratableInterface)
127
		{
128 122
			$criteria->decorateWith($this->getModel());
129
		}
130 122
		$scopesClasses = ManganMeta::create($this->getModel())->type()->scopes;
131 122
		foreach($scopesClasses as $scopesClass)
132
		{
133 2
			$scope = new $scopesClass;
134 2
			if($scope instanceof ModelAwareInterface)
135
			{
136 2
				$scope->setModel($this->getModel());
137
			}
138 2
			assert($scope instanceof ScopeInterface);
139 2
			$scopeCriteria = $scope->getCriteria();
140 2
			assert($scopeCriteria instanceof CriteriaInterface);
141 2
			$criteria->mergeWith($scopeCriteria);
142
		}
143 122
		return $criteria;
144
	}
145
146
	public function reset()
147
	{
148
		$this->criteria = $this->getNewCriteria();
149
		return $this;
150
	}
151
152 122
	protected function getModelCriteria()
153
	{
154 122
		$criteria = null;
155 122
		if ($this->model instanceof WithCriteriaInterface)
156
		{
157 45
			$criteria = $this->model->getDbCriteria();
158
		}
159 77
		elseif ($this->model instanceof CriteriaAwareInterface)
160
		{
161
			$criteria = $this->model->getCriteria();
162
		}
163 122
		if (empty($criteria))
164
		{
165 77
			return $this->getNewCriteria();
166
		}
167 45
		return $criteria;
168
	}
169
170
	abstract public function getNewCriteria($criteria = null);
171
}
172