Completed
Pull Request — develop (#455)
by Lucas
37:54 queued 31:44
created

ReadOnlyFieldConstraint   A

Complexity

Total Complexity 11

Size/Duplication

Total Lines 78
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 3

Test Coverage

Coverage 0%

Importance

Changes 4
Bugs 0 Features 2
Metric Value
wmc 11
lcom 1
cbo 3
dl 0
loc 78
ccs 0
cts 42
cp 0
rs 10
c 4
b 0
f 2

2 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 5 1
C checkReadOnlyFields() 0 50 10
1
<?php
2
/**
3
 * Schema constraint that validates if readOnly: true fields are manipulated and rejects changes on those.
4
 */
5
6
namespace Graviton\SchemaBundle\Constraint;
7
8
use Graviton\JsonSchemaBundle\Validator\Constraint\Event\ConstraintEventSchema;
9
use Symfony\Component\PropertyAccess\PropertyAccess;
10
11
/**
12
 * @author   List of contributors <https://github.com/libgraviton/graviton/graphs/contributors>
13
 * @license  http://opensource.org/licenses/gpl-license.php GNU Public License
14
 * @link     http://swisscom.ch
15
 */
16
class ReadOnlyFieldConstraint
17
{
18
19
    /**
20
     * @var array
21
     */
22
    private $fieldMap;
23
24
    /**
25
     * ReadOnlyFieldConstraint constructor.
26
     *
27
     * @param ConstraintUtils $utils             Utils
28
     * @param array           $readOnlyFieldsMap field map from compiler pass
29
     */
30
    public function __construct(ConstraintUtils $utils, array $readOnlyFieldsMap)
31
    {
32
        $this->utils = $utils;
33
        $this->fieldMap = $readOnlyFieldsMap;
34
    }
35
36
    /**
37
     * Checks the readOnly fields and sets error in event if needed
38
     *
39
     * @param ConstraintEventSchema $event event class
40
     *
41
     * @return void
42
     */
43
    public function checkReadOnlyFields(ConstraintEventSchema $event)
44
    {
45
        $schema = $event->getSchema();
46
        $data = $event->getElement();
47
48
        if (!isset($schema->{'x-documentClass'}) || !isset($data->id)) {
49
            return;
50
        }
51
52
        $documentClass = $schema->{'x-documentClass'};
53
54
        if (!isset($this->fieldMap[$documentClass])) {
55
            return;
56
        }
57
58
        $readOnlyFields = $this->fieldMap[$documentClass];
59
60
        // get the current record
61
        $currentRecord = $this->utils->getCurrentEntity();
62
63
        if (is_null($currentRecord)) {
64
            return;
65
        }
66
67
        // compare fields in both objects
68
        $accessor = PropertyAccess::createPropertyAccessor();
69
        foreach ($readOnlyFields as $fieldName) {
70
            $storedValue = null;
71
            if ($accessor->isReadable($currentRecord, $fieldName)) {
72
                $storedValue = $accessor->getValue($currentRecord, $fieldName);
73
            }
74
75
            if (is_object($storedValue)) {
76
                // skip objects as a whole, we will test their readOnly properties instead
77
                continue;
78
            }
79
80
            $setValue = null;
81
            if ($accessor->isReadable($data, $fieldName)) {
82
                $setValue = $accessor->getValue($data, $fieldName);
83
            }
84
85
            if ($storedValue != $setValue) {
86
                $event->addError(
87
                    sprintf('The value %s is read only.', json_encode($accessor->getValue($currentRecord, $fieldName))),
88
                    $fieldName
89
                );
90
            }
91
        }
92
    }
93
}
94