Completed
Push — master ( fc22f7...cd662c )
by Filipe
02:57
created

BelongsTo::getFromMap()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 10
Code Lines 7

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 10
ccs 0
cts 10
cp 0
rs 9.4285
cc 2
eloc 7
nc 2
nop 1
crap 6
1
<?php
2
3
/**
4
 * This file is part of slick/orm package
5
 *
6
 * For the full copyright and license information, please view the LICENSE
7
 * file that was distributed with this source code.
8
 */
9
10
namespace Slick\Orm\Mapper\Relation;
11
12
use Slick\Orm\Descriptor\Field\FieldDescriptor;
13
use Slick\Orm\Entity\EntityCollection;
14
use Slick\Orm\EntityInterface;
15
use Slick\Orm\Event\Select;
16
use Slick\Orm\Mapper\RelationInterface;
17
use Slick\Orm\Orm;
18
19
/**
20
 * BelongsTo (Many-To-On) relation
21
 *
22
 * @package Slick\Orm\Mapper\Relation
23
 * @author  Filipe Silva <[email protected]>
24
 */
25
class BelongsTo extends AbstractRelation implements RelationInterface
26
{
27
    /**
28
     * Relations utility methods
29
     */
30
    use RelationsUtilityMethods;
31
32
    /**
33
     * BelongsTo relation
34
     *
35
     * @param array|object $options The parameters from annotation
36
     */
37
    public function __construct($options)
38
    {
39
        /** @var \Slick\Orm\Annotations\BelongsTo $annotation */
40
        $annotation = $options['annotation'];
41
        unset($options['annotation']);
42
        $options['foreignKey'] = $annotation->getParameter('foreignKey');
43
        $options['parentEntity'] = $annotation->getValue();
44
45
        parent::__construct($options);
46
47
        $this->registerListeners();
48
    }
49
50
    /**
51
     * Handles the before select callback
52
     *
53
     * @param Select $event
54
     */
55
    public function beforeSelect(Select $event)
56
    {
57
        $fields = $this->getFieldsPrefixed();
58
        $table = $this->entityDescriptor->getTableName();
59
        $relateTable = $this->getParentTableName();
60
        $pmk = $this->getParentPrimaryKey();
61
62
        $onClause = "{$table}.{$this->getForeignKey()} = ".
63
            "{$relateTable}.{$pmk}";
64
65
        $query = $event->getQuery();
66
        $query->join($relateTable, $onClause, $fields, $relateTable);
67
    }
68
69
    /**
70
     * Handles the after select callback
71
     *
72
     * @param Select $event
73
     */
74
    public function afterSelect(Select $event)
75
    {
76
        foreach ($event->getEntityCollection() as $index => $entity) {
77
            $row = $event->getData()[$index];
78
            $entity->{$this->propertyName} = $this->getFromMap($row);
79
        }
80
    }
81
82
    /**
83
     * Registers the listener for before select event
84
     */
85
    private function registerListeners()
86
    {
87
        Orm::addListener(
88
            $this->entityDescriptor->className(),
89
            Select::ACTION_BEFORE_SELECT,
90
            [$this, 'beforeSelect']
91
        );
92
93
        Orm::addListener(
94
            $this->entityDescriptor->className(),
95
            Select::ACTION_AFTER_SELECT,
96
            [$this, 'afterSelect']
97
        );
98
    }
99
100
    /**
101
     * Prefixed fields for join
102
     *
103
     * @return array
104
     */
105
    private function getFieldsPrefixed()
106
    {
107
        $table = $this->getParentTableName();
108
        $data = [];
109
110
        foreach ($this->getParentFields() as $field) {
111
            $data[] = "{$field->getField()} AS ".
112
                "{$table}_{$field->getField()}";
113
        }
114
        return $data;
115
    }
116
117
    /**
118
     * Check if entity is already loaded and uses it.
119
     *
120
     * If not loaded the entity will be created and loaded to the repository's
121
     * identity map so that it can be reused next time.
122
     *
123
     * @param array $dataRow
124
     *
125
     * @return null|EntityCollection|EntityInterface|EntityInterface[]
126
     */
127
    private function getFromMap($dataRow)
128
    {
129
        $entity = $this->getParentRepository()
130
            ->getIdentityMap()
131
            ->get($dataRow[$this->getForeignKey()], false);
132
        if (false === $entity) {
133
            $entity = $this->map($dataRow);
134
        }
135
        return $entity;
136
    }
137
138
    /**
139
     * Creates and maps related entity
140
     *
141
     * @param array $dataRow
142
     *
143
     * @return null|EntityCollection|EntityInterface|EntityInterface[]
144
     */
145
    private function map($dataRow)
146
    {
147
        $data = $this->getData($dataRow);
148
        $pmk = $this->getParentPrimaryKey();
149
        return (isset($data[$pmk]) && $data[$pmk])
150
            ? $this->getParentEntityMapper()->createFrom($data)
151
            : null;
152
    }
153
154
    /**
155
     * Gets a data array with fields and values for parent entity creation
156
     *
157
     * @param array $dataRow
158
     *
159
     * @return array
160
     */
161
    private function getData($dataRow)
162
    {
163
        $data = [];
164
        $relateTable = $this->getParentTableName();
165
        $regexp = "/{$relateTable}_(?P<name>.+)/i";
166
        foreach ($dataRow as $field => $value) {
167
            if (preg_match($regexp, $field, $matched)) {
168
                $data[$matched['name']] = $value;
169
            }
170
        }
171
        return $data;
172
    }
173
}