Completed
Push — master ( 632b2b...e22e45 )
by Peter
08:08
created

ImmutableValidator   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 121
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 12

Test Coverage

Coverage 89.29%

Importance

Changes 1
Bugs 0 Features 0
Metric Value
wmc 10
c 1
b 0
f 0
lcom 1
cbo 12
dl 0
loc 121
ccs 25
cts 28
cp 0.8929
rs 10

1 Method

Rating   Name   Duplication   Size   Complexity  
C isValid() 0 61 10
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\Validators\BuiltIn;
15
16
use Maslosoft\Addendum\Interfaces\AnnotatedInterface;
17
use Maslosoft\Mangan\Criteria;
18
use Maslosoft\Mangan\Finder;
19
use Maslosoft\Mangan\Helpers\PkManager;
20
use Maslosoft\Mangan\Interfaces\Validators\ValidatorInterface;
21
use Maslosoft\Mangan\Meta\ManganMeta;
22
use Maslosoft\Mangan\ScenarioManager;
23
use Maslosoft\Mangan\Validators\Traits\AllowEmpty;
24
use Maslosoft\Mangan\Validators\Traits\Messages;
25
use Maslosoft\Mangan\Validators\Traits\OnScenario;
26
use Maslosoft\Mangan\Validators\Traits\Safe;
27
use Maslosoft\Mangan\Validators\Traits\SkipOnError;
28
use Maslosoft\Mangan\Validators\Traits\When;
29
30
/**
31
 * ImmutableValidator validates that the attribute value
32
 * is same as in the stored in database, if it was stored already.
33
 *
34
 * @author Florian Fackler <[email protected]>
35
 * @version $Id$
36
 * @package system.validators
37
 * @since 1.0
38
 */
39
class ImmutableValidator implements ValidatorInterface
40
{
41
42
	use AllowEmpty,
43
	  SkipOnError,
44
	  Messages,
45
	  OnScenario,
46
	  Safe,
47
	  When;
48
49
	/**
50
	 * Set this value to check against trueish value stored in database.
51
	 * If empty this will check for validated attribute.
52
	 *
53
	 * @var string
54
	 */
55
	public $against = '';
56
57
	/**
58
	 * @var string the document class name that should be used to
59
	 * look for the attribute value being validated. Defaults to null, meaning using
60
	 * the class of the object currently being validated.
61
	 *
62
	 * @see attributeName
63
	 * @since 1.0.8
64
	 */
65
	public $className;
66
67
	/**
68
	 * @var string the ActiveRecord class attribute name that should be
69
	 * used to look for the attribute value being validated. Defaults to null,
70
	 * meaning using the name of the attribute being validated.
71
	 *
72
	 * @see className
73
	 * @since 1.0.8
74
	 */
75
	public $attributeName;
76
77
	/**
78
	 * @var array additional query criteria. This will be combined with the condition
79
	 * that checks if the attribute value exists in the corresponding table column.
80
	 * This array will be used to instantiate a {@link Criteria} object.
81
	 * @since 1.0.8
82
	 */
83
	public $criteria = [];
84
85
	/**
86
	 * @Label('{attribute} cannot be changed once set')
87
	 * @var string
88
	 */
89
	public $msgImmutable = '';
90
91
	/**
92
	 * Validates the attribute of the object.
93
	 * If there is any error, the error message is added to the object.
94
	 * @param AnnotatedInterface $model the object being validated
95
	 * @param string $attribute the attribute being validated
96
	 */
97 4
	public function isValid(AnnotatedInterface $model, $attribute)
98
	{
99 4
		if (!$this->whenValidate($model))
100
		{
101
			return true;
102
		}
103 4
		$value = $model->$attribute;
104 4
		if ($this->allowEmpty && empty($value))
105
		{
106
			return true;
107
		}
108
109 4
		$className = empty($this->className) ? get_class($model) : $this->className;
110
111 4
		$compareModel = new $className;
112
113 4
		$pk = PkManager::getFromModel($model);
114 4
		PkManager::applyToModel($compareModel, $pk);
115 4
		$criteria = PkManager::prepareFromModel($compareModel);
116
117 4
		if ($this->criteria !== [])
118
		{
119
			$criteria->mergeWith($this->criteria);
120
		}
121 4
		ScenarioManager::setScenario($compareModel, ValidatorInterface::ScenarioValidate);
122 4
		$finder = new Finder($compareModel);
123
124 4
		$found = $finder->find($criteria);
125
126
		// Not found entirely
127 4
		if (null === $found)
128
		{
129 3
			return true;
130
		}
131
132
		// Decide against which field to check
133 3
		if (empty($this->against))
134
		{
135 2
			$against = $attribute;
136
		}
137
		else
138
		{
139 1
			$against = $this->against;
140
		}
141
142
		// Not stored in DB
143 3
		if (empty($found->$against))
144
		{
145 1
			return true;
146
		}
147
148
		// Stored in DB, but value is same
149 3
		if ($found->$attribute === $model->$attribute)
150
		{
151 2
			return true;
152
		}
153
154 3
		$label = ManganMeta::create($model)->field($attribute)->label;
155 3
		$this->addError('msgImmutable', ['{attribute}' => $label, '{value}' => $value]);
156 3
		return false;
157
	}
158
159
}
160