Completed
Pull Request — 2.0 (#161)
by Christopher
03:05
created

EavToolbox::extractEntityIds()   A

Complexity

Conditions 2
Paths 1

Size

Total Lines 11
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 0
Metric Value
cc 2
eloc 6
c 2
b 1
f 0
nc 1
nop 1
dl 0
loc 11
rs 9.4285
1
<?php
2
/**
3
 * Licensed under The GPL-3.0 License
4
 * For full copyright and license information, please see the LICENSE.txt
5
 * Redistributions of files must retain the above copyright notice.
6
 *
7
 * @since    2.0.0
8
 * @author   Christopher Castro <[email protected]>
9
 * @link     http://www.quickappscms.org
10
 * @license  http://opensource.org/licenses/gpl-3.0.html GPL-3.0 License
11
 */
12
namespace Eav\Model\Behavior;
13
14
use Cake\Datasource\EntityInterface;
15
use Cake\Database\Type;
16
use Cake\Datasource\ResultSetDecorator;
17
use Cake\ORM\Entity;
18
use Cake\ORM\ResultSet;
19
use Cake\ORM\Table;
20
use Cake\ORM\TableRegistry;
21
use Cake\Utility\Inflector;
22
23
/**
24
 * Support class for EAV behavior.
25
 */
26
class EavToolbox
27
{
28
29
    /**
30
     * List of accepted value types.
31
     *
32
     * @var array
33
     */
34
    public static $types = [
35
        'biginteger',
36
        'binary',
37
        'date',
38
        'float',
39
        'decimal',
40
        'integer',
41
        'time',
42
        'datetime',
43
        'timestamp',
44
        'uuid',
45
        'string',
46
        'text',
47
        'boolean',
48
    ];
49
50
    /**
51
     * The table being managed.
52
     *
53
     * @var \Cake\ORM\Table
54
     */
55
    protected $_table = null;
56
57
    /**
58
     * Attributes index by bundle, and by name within each bundle.
59
     *
60
     * ```php
61
     * [
62
     *     'administrator' => [
63
     *         'admin-address' => [
64
     *             'type' => 'varchar',
65
     *             'searchable' => false
66
     *         ],
67
     *         'admin-phone' => [
68
     *             'type' => 'varchar',
69
     *             'searchable' => true
70
     *         ]
71
     *     ],
72
     *     'editor' => [
73
     *         'editor-last-login' => [
74
     *             'type' => 'datetime',
75
     *             'searchable' => false,
76
     *         ]
77
     *     ]
78
     * ]
79
     * ```
80
     *
81
     * @var array
82
     */
83
    protected $_attributes = [];
84
85
    /**
86
     * Constructor.
87
     *
88
     * @param \Cake\ORM\Table $table The table being handled
89
     */
90
    public function __construct(Table $table)
91
    {
92
        $this->_table = $table;
93
    }
94
95
    /**
96
     * Gets a clean column name from query expression.
97
     *
98
     * ### Example:
99
     *
100
     * ```php
101
     * EavToolbox::columnName('Tablename.some_column');
102
     * // returns "some_column"
103
     *
104
     * EavToolbox::columnName('my_column');
105
     * // returns "my_column"
106
     * ```
107
     *
108
     * @param string $column Column name from query
109
     * @return string
110
     */
111
    public static function columnName($column)
112
    {
113
        list($tableName, $fieldName) = pluginSplit((string)$column);
114
        if (!$fieldName) {
115
            $fieldName = $tableName;
116
        }
117
        $fieldName = preg_replace('/\s{2,}/', ' ', $fieldName);
118
        list($fieldName, ) = explode(' ', trim($fieldName));
119
        return $fieldName;
120
    }
121
122
    /**
123
     * Checks if the provided entity has defined certain $property, regardless of
124
     * its value.
125
     *
126
     * @param \Cake\ORM\Entity $entity The entity to check
127
     * @param string $property The property name
128
     * @return bool True if exists
129
     */
130
    public function propertyExists(Entity $entity, $property)
131
    {
132
        $entityArray = $entity->toArray();
133
        return array_key_exists($property, $entityArray);
134
    }
135
136
    /**
137
     * Marshalls flat data into PHP objects.
138
     *
139
     * @param mixed $value The value to convert
140
     * @param string $type Type identifier, `integer`, `float`, etc
141
     * @return mixed Converted value
142
     */
143
    public function marshal($value, $type)
144
    {
145
        return Type::build($type)->marshal($value);
146
    }
147
148
    /**
149
     * Gets all attributes added to this table.
150
     *
151
     * @param string|null $bundle Get attributes within given bundle, or all of them
152
     *  regardless of the bundle if not provided
153
     * @return array List of attributes indexed by name (virtual column name)
154
     */
155
    public function attributes($bundle = null)
156
    {
157
        $key = empty($bundle) ? '@all' : $bundle;
158
        if (isset($this->_attributes[$key])) {
159
            return $this->_attributes[$key];
160
        }
161
162
        $this->_attributes[$key] = [];
163
        $conditions = ['EavAttributes.table_alias' => $this->_table->table()];
164
        if (!empty($bundle)) {
165
            $conditions['EavAttributes.bundle'] = $bundle;
166
        }
167
168
        $cacheKey = $this->_table->table() . '_' . $key;
169
        $attrs = TableRegistry::get('Eav.EavAttributes')
170
            ->find()
171
            ->cache($cacheKey, 'eav_table_attrs')
172
            ->where($conditions)
173
            ->all()
174
            ->toArray();
175
        foreach ($attrs as $attr) {
176
            $this->_attributes[$key][$attr->get('name')] = $attr;
177
        }
178
179
        return $this->attributes($bundle);
180
    }
181
182
    /**
183
     * Gets a list of attribute names.
184
     *
185
     * @param string $bundle Filter by bundle name
186
     * @return array
187
     */
188
    public function getAttributeNames($bundle = null)
189
    {
190
        $attributes = $this->attributes($bundle);
191
        return array_keys($attributes);
192
    }
193
194
    /**
195
     * Gets a list of attribute IDs.
196
     *
197
     * @param string $bundle Filter by bundle name
198
     * @return array
199
     */
200
    public function getAttributeIds($bundle = null)
201
    {
202
        $attributes = $this->attributes($bundle);
203
        $ids = [];
204
205
        foreach ($attributes as $name => $info) {
206
            $ids[] = $info['id'];
207
        }
208
209
        return $ids;
210
    }
211
212
    /**
213
     * Given a set of entities gets the ID of all of them.
214
     *
215
     * This method iterates the given set and invokes `getEntityId()` for every
216
     * entity in the set.
217
     *
218
     * @param \Cake\ORM\ResultSet $results Set of entities
219
     * @return array List of entity ids suitable for EAV logic
220
     */
221
    public function extractEntityIds(ResultSet $results)
222
    {
223
        $entityIds = [];
224
        $results->each(function ($entity) use(&$entityIds) {
225
            if ($entity instanceof EntityInterface) {
226
                $entityIds[] = $this->getEntityId($entity);
227
            }
228
        });
229
230
        return $entityIds;
231
    }
232
233
    /**
234
     * Calculates entity's primary key.
235
     *
236
     * If PK is composed of multiple columns they will be merged with `:` symbol.
237
     * For example, consider `Users` table with composed PK <nick, email>, then for
238
     * certain User entity this method could return:
239
     *
240
     *     john-locke:[email protected]
241
     *
242
     * @param \Cake\Datasource\EntityInterface $entity The entity
243
     * @return string
244
     */
245 View Code Duplication
    public function getEntityId(EntityInterface $entity)
246
    {
247
        $pk = [];
248
        $keys = $this->_table->primaryKey();
249
        $keys = !is_array($keys) ? [$keys] : $keys;
250
        foreach ($keys as $key) {
251
            $pk[] = $entity->get($key);
252
        }
253
        return implode(':', $pk);
254
    }
255
256
    /**
257
     * Gets attribute's EAV type.
258
     *
259
     * @param string $attrName Attribute name
260
     * @return string Attribute's EAV type
261
     * @see \Eav\Model\Behavior\EavBehavior::_mapType()
262
     */
263
    public function getType($attrName)
264
    {
265
        return $this->mapType($this->attributes()[$attrName]->get('type'));
266
    }
267
268
    /**
269
     * Gets attribute's bundle.
270
     *
271
     * @param string $attrName Attribute name
272
     * @return string|null
273
     */
274
    public function getBundle($attrName)
275
    {
276
        return $this->attributes()[$attrName]->get('bundle');
277
    }
278
279
    /**
280
     * Whether the given attribute can be used in WHERE clauses.
281
     *
282
     * @param string $attrName Attribute name
283
     * @return bool
284
     */
285
    public function isSearchable($attrName)
286
    {
287
        return (bool)$this->attributes()[$attrName]->get('searchable');
288
    }
289
290
    /**
291
     * Maps schema data types to EAV's supported types.
292
     *
293
     * @param string $type A schema type. e.g. "string", "integer"
294
     * @return string A EAV type. Possible values are `datetime`, `binary`, `time`,
295
     *  `date`, `float`, `intreger`, `biginteger`, `text`, `string`, `boolean` or
296
     *  `uuid`
297
     */
298
    public function mapType($type)
299
    {
300
        switch ($type) {
301
            case 'float':
302
            case 'decimal':
303
                return 'float';
304
            case 'timestamp':
305
                return 'datetime';
306
            default:
307
                return $type;
308
        }
309
    }
310
}
311