Completed
Pull Request — master (#615)
by Filippo
14:02 queued 03:29
created

UniqueObject::__construct()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 27
Code Lines 17

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 14
CRAP Score 6.0106

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 27
ccs 14
cts 15
cp 0.9333
rs 8.439
cc 6
eloc 17
nc 5
nop 1
crap 6.0106
1
<?php
2
3
namespace DoctrineModule\Validator;
4
5
use Doctrine\Common\Persistence\ObjectManager;
6
use Zend\Validator\Exception;
7
8
/**
9
 * Class that validates if objects exist in a given repository with a given list of matched fields only once.
10
 *
11
 * @license MIT
12
 * @link    http://www.doctrine-project.org/
13
 * @author  Oskar Bley <[email protected]>
14
 */
15
class UniqueObject extends ObjectExists
16
{
17
    /**
18
     * Error constants
19
     */
20
    const ERROR_OBJECT_NOT_UNIQUE = 'objectNotUnique';
21
22
    /**
23
     * @var array Message templates
24
     */
25
    protected $messageTemplates = [
26
        self::ERROR_OBJECT_NOT_UNIQUE => "There is already another object matching '%value%'",
27
    ];
28
29
    /**
30
     * @var ObjectManager
31
     */
32
    protected $objectManager;
33
34
    /**
35
     * @var boolean
36
     */
37
    protected $useContext;
38
39
    /***
40
     * Constructor
41
     *
42
     * @param array $options required keys are `object_repository`, which must be an instance of
43
     *                       Doctrine\Common\Persistence\ObjectRepository, `object_manager`, which
44
     *                       must be an instance of Doctrine\Common\Persistence\ObjectManager,
45
     *                       and `fields`, with either a string or an array of strings representing
46
     *                       the fields to be matched by the validator.
47
     * @throws Exception\InvalidArgumentException
48
     */
49 12
    public function __construct(array $options)
50
    {
51 12
        parent::__construct($options);
52
53 12
        if (! isset($options['object_manager']) || ! $options['object_manager'] instanceof ObjectManager) {
54 2
            if (! array_key_exists('object_manager', $options)) {
55 1
                $provided = 'nothing';
56
            } else {
57 1
                if (is_object($options['object_manager'])) {
58 1
                    $provided = get_class($options['object_manager']);
59
                } else {
60
                    $provided = getType($options['object_manager']);
61
                }
62
            }
63
64 2
            throw new Exception\InvalidArgumentException(
65 2
                sprintf(
66
                    'Option "object_manager" is required and must be an instance of'
67 2
                    . ' Doctrine\Common\Persistence\ObjectManager, %s given',
68 2
                    $provided
69
                )
70
            );
71
        }
72
73 10
        $this->objectManager = $options['object_manager'];
74 10
        $this->useContext    = isset($options['use_context']) ? (boolean) $options['use_context'] : false;
75 10
    }
76
77
    /**
78
     * Returns false if there is another object with the same field values but other identifiers.
79
     *
80
     * @param  mixed $value
81
     * @param  array $context
82
     * @return boolean
83
     */
84 10
    public function isValid($value, $context = null)
85
    {
86 10
        if (! $this->useContext) {
87 5
            $context = (array) $value;
88
        }
89
90 10
        $cleanedValue = $this->cleanSearchValue($value);
91 10
        $match        = $this->objectRepository->findOneBy($cleanedValue);
92
93 10
        if (! is_object($match)) {
94 2
            return true;
95
        }
96
97 8
        $expectedIdentifiers = $this->getExpectedIdentifiers($context);
98 5
        $foundIdentifiers    = $this->getFoundIdentifiers($match);
99
100 5
        if (count(array_diff_assoc($expectedIdentifiers, $foundIdentifiers)) == 0) {
101 3
            return true;
102
        }
103
104 2
        $this->error(self::ERROR_OBJECT_NOT_UNIQUE, $value);
105 2
        return false;
106
    }
107
108
    /**
109
     * Gets the identifiers from the matched object.
110
     *
111
     * @param object $match
112
     * @return array
113
     * @throws Exception\RuntimeException
114
     */
115 5
    protected function getFoundIdentifiers($match)
116
    {
117 5
        return $this->objectManager
118 5
                    ->getClassMetadata($this->objectRepository->getClassName())
119 5
                    ->getIdentifierValues($match);
120
    }
121
122
    /**
123
     * Gets the identifiers from the context.
124
     *
125
     * @param  array|object $context
126
     * @return array
127
     * @throws Exception\RuntimeException
128
     */
129 8
    protected function getExpectedIdentifiers($context = null)
130
    {
131 8
        if ($context === null) {
132 1
            throw new Exception\RuntimeException(
133 1
                'Expected context to be an array but is null'
134
            );
135
        }
136
137 7
        $className = $this->objectRepository->getClassName();
138
139 7
        if ($context instanceof $className) {
140 1
            return $this->objectManager
141 1
                        ->getClassMetadata($this->objectRepository->getClassName())
142 1
                        ->getIdentifierValues($context);
143
        }
144
145 6
        $result = [];
146 6
        foreach ($this->getIdentifiers() as $identifierField) {
147 6
            if (! isset($context[$identifierField])) {
148 2
                throw new Exception\RuntimeException(\sprintf('Expected context to contain %s', $identifierField));
149
            }
150
151 4
            $result[$identifierField] = $context[$identifierField];
152
        }
153 4
        return $result;
154
    }
155
156
157
    /**
158
     * @return array the names of the identifiers
159
     */
160 6
    protected function getIdentifiers()
161
    {
162 6
        return $this->objectManager
163 6
                    ->getClassMetadata($this->objectRepository->getClassName())
164 6
                    ->getIdentifierFieldNames();
165
    }
166
}
167