Passed
Push — master ( 4b954d...b01812 )
by Gabor
03:38
created

AbstractDataCoupler::setDependency()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 30
Code Lines 18

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 18
CRAP Score 4

Importance

Changes 0
Metric Value
dl 0
loc 30
ccs 18
cts 18
cp 1
rs 8.5806
c 0
b 0
f 0
cc 4
eloc 18
nc 4
nop 2
crap 4
1
<?php
2
/**
3
 * WebHemi.
4
 *
5
 * PHP version 5.6
6
 *
7
 * @copyright 2012 - 2016 Gixx-web (http://www.gixx-web.com)
8
 * @license   https://opensource.org/licenses/MIT The MIT License (MIT)
9
 *
10
 * @link      http://www.gixx-web.com
11
 */
12
namespace WebHemi\Data\Coupler;
13
14
use InvalidArgumentException;
15
use RuntimeException;
16
use WebHemi\Adapter\Data\DataAdapterInterface;
17
use WebHemi\Data\Entity\DataEntityInterface;
18
19
/**
20
 * Class AbstractDataCoupler.
21
 */
22
abstract class AbstractDataCoupler implements DataCouplerInterface
23
{
24
    /** @var DataAdapterInterface */
25
    private $defaultAdapter;
26
    /** @var array<DataEntityInterface> */
27
    protected $dataEntityPrototypes = [];
28
    /** @var string */
29
    protected $connectorIdKey;
30
    /** @var string */
31
    protected $connectorDataGroup;
32
    /** @var array */
33
    protected $dependentDataGroups;
34
35
    /**
36
     * AbstractDataCoupler constructor.
37
     *
38
     * @param DataAdapterInterface $defaultAdapter
39
     * @param DataEntityInterface  $dataEntityPrototypeA
40
     * @param DataEntityInterface  $dataEntityPrototypeB
41
     */
42 7
    public function __construct(
43
        DataAdapterInterface $defaultAdapter,
44
        DataEntityInterface $dataEntityPrototypeA,
45
        DataEntityInterface $dataEntityPrototypeB
46
    ) {
47 7
        $entityClassA = get_class($dataEntityPrototypeA);
48 7
        $entityClassB = get_class($dataEntityPrototypeB);
49
50 7
        if (!isset($this->dependentDataGroups[$entityClassA])
51 7
            || !isset($this->dependentDataGroups[$entityClassB])
52 7
            || (count(array_keys($this->dependentDataGroups)) == 2 && $entityClassA == $entityClassB)
53 7
        ) {
54 4
            throw new InvalidArgumentException(
55 4
                sprintf(
56 4
                    'This coupler requires data entity instances from the following classes: %s; %s and %s are given.',
57 4
                    implode(', ', array_keys($this->dependentDataGroups)),
58 4
                    $entityClassA,
59
                    $entityClassB
60 4
                ),
61
                1000
62 4
            );
63
        }
64
65 7
        $this->defaultAdapter = $defaultAdapter;
66 7
        $this->dataEntityPrototypes[$entityClassA] = $dataEntityPrototypeA;
67 7
        $this->dataEntityPrototypes[$entityClassB] = $dataEntityPrototypeB;
68 7
    }
69
70
    /**
71
     * Returns the DataAdapter instance.
72
     *
73
     * @return DataAdapterInterface
74
     */
75 5
    public function getDataAdapter()
76
    {
77 5
        return $this->defaultAdapter;
78
    }
79
80
    /**
81
     * Gets all the entities those are depending from the given entity.
82
     *
83
     * @param DataEntityInterface $entity
84
     * @throws RuntimeException
85
     * @return array<DataEntityInterface>
86
     */
87 4
    public function getEntityDependencies(DataEntityInterface $entity)
88
    {
89 4
        $entityClass = get_class($entity);
90 4
        if (!isset($this->dataEntityPrototypes[$entityClass])) {
91 1
            throw new RuntimeException(
92 1
                sprintf('Cannot use this coupler class to find dependencies for %s.', $entityClass),
93
                1001
94 1
            );
95
        }
96
97 4
        $entityList = [];
98 4
        $dataList = $this->getEntityDataSet($entity);
99
100 4
        foreach ($dataList as $entityData) {
101 4
            $entityList[] = $this->getDependingEntity($entity, $entityData);
102 4
        }
103
104 4
        return $entityList;
105
    }
106
107
    /**
108
     * Sets dependency for the entities
109
     *
110
     * @param DataEntityInterface $entityA
111
     * @param DataEntityInterface $entityB
112
     * @return mixed The ID of the saved entity in the storage
113
     */
114 1
    public function setDependency(DataEntityInterface $entityA, DataEntityInterface $entityB)
115
    {
116 1
        $entityClassA = get_class($entityA);
117 1
        if (!isset($this->dataEntityPrototypes[$entityClassA])) {
118 1
            throw new InvalidArgumentException(sprintf('Cannot use this coupler class for %s.', $entityClassA), 1002);
119
        }
120
121 1
        $entityClassB = get_class($entityB);
122 1
        if (!isset($this->dataEntityPrototypes[$entityClassB])) {
123 1
            throw new InvalidArgumentException(sprintf('Cannot use this coupler class for %s.', $entityClassB), 1003);
124
        }
125
126 1
        if ($entityClassA == $entityClassB) {
127 1
            throw new InvalidArgumentException(
128 1
                sprintf('Cannot set dependency for the same type of entity %s.', $entityClassB),
129
                1004
130 1
            );
131
        }
132
133
        $data = [
134 1
            $this->dependentDataGroups[$entityClassA]['source_key'] => $entityA->getKeyData(),
135 1
            $this->dependentDataGroups[$entityClassB]['source_key'] => $entityB->getKeyData(),
136 1
        ];
137
138
        // Point the data adapter to the connector group
139 1
        return $this->getDataAdapter()
140 1
            ->setDataGroup($this->connectorDataGroup)
141 1
            ->setIdKey($this->connectorIdKey)
142 1
            ->saveData(null, $data);
143
    }
144
145
    /**
146
     * Gets a DataEntityInterface instance from the provided data according to the reference entity.
147
     *
148
     * @param DataEntityInterface $referenceEntity
149
     * @param array               $entityData
150
     * @return DataEntityInterface
151
     */
152
    abstract protected function getDependingEntity(DataEntityInterface $referenceEntity, array $entityData);
153
154
    /**
155
     * Returns a new instance of the required entity.
156
     *
157
     * @param string $entityClassName
158
     * @throws RuntimeException
159
     * @return DataEntityInterface
160
     */
161 5
    protected function getNewEntityInstance($entityClassName)
162
    {
163 5
        return clone $this->dataEntityPrototypes[$entityClassName];
164
    }
165
166
    /**
167
     * Gets raw depending entity data list for the given entity.
168
     *
169
     * @param DataEntityInterface $entity
170
     * @return array
171
     */
172 3
    protected function getEntityDataSet(DataEntityInterface $entity)
173
    {
174 3
        $entityClassName = get_class($entity);
175 3
        $entityDataSet = [];
176 3
        $identifiers = [];
177
178 3
        $this->getDataAdapter()->setDataGroup($this->connectorDataGroup)
179 3
            ->setIdKey($this->connectorIdKey);
180
181 3
        $dataList = $this->getDataAdapter()->getDataSet([
182 3
            $this->dependentDataGroups[$entityClassName]['source_key'].' = ?' => $entity->getKeyData()
183 3
        ]);
184
185 3
        foreach ($dataList as $rowData) {
186 3
            $identifiers[] = $rowData[$this->dependentDataGroups[$entityClassName]['connector_key']];
187 3
        }
188
189 3
        if (!empty($identifiers)) {
190 3
            $this->getDataAdapter()->setDataGroup($this->dependentDataGroups[$entityClassName]['depending_group'])
191 3
                ->setIdKey($this->dependentDataGroups[$entityClassName]['depending_id_key']);
192
193 3
            $entityDataSet = $this->getDataAdapter()->getDataSet([
194 3
                $this->dependentDataGroups[$entityClassName]['depending_id_key'].' IN (?)' => $identifiers
195 3
            ]);
196 3
        }
197
198 3
        return $entityDataSet;
199
    }
200
}
201