Completed
Push — 2.0 ( 7b1d29...a1f3e1 )
by Christopher
02:43
created

EavToolbox::getBundle()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 2
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 4
rs 10
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\Cache\Cache;
15
use Cake\Collection\CollectionInterface;
16
use Cake\Database\Type;
17
use Cake\Datasource\EntityInterface;
18
use Cake\ORM\Query;
19
use Cake\ORM\Table;
20
use Cake\ORM\TableRegistry;
21
22
/**
23
 * Support class for EAV behavior.
24
 */
25
class EavToolbox
26
{
27
28
    /**
29
     * List of accepted value types.
30
     *
31
     * @var array
32
     */
33
    public static $types = [
34
        'biginteger',
35
        'binary',
36
        'date',
37
        'float',
38
        'decimal',
39
        'integer',
40
        'time',
41
        'datetime',
42
        'timestamp',
43
        'uuid',
44
        'string',
45
        'text',
46
        'boolean',
47
    ];
48
49
    /**
50
     * The table being managed.
51
     *
52
     * @var \Cake\ORM\Table
53
     */
54
    protected $_table = null;
55
56
    /**
57
     * Attributes index by bundle, and by name within each bundle.
58
     *
59
     * ```php
60
     * [
61
     *     'administrator' => [
62
     *         'admin-address' => [
63
     *             'type' => 'varchar',
64
     *             'searchable' => false
65
     *         ],
66
     *         'admin-phone' => [
67
     *             'type' => 'varchar',
68
     *             'searchable' => true
69
     *         ]
70
     *     ],
71
     *     'editor' => [
72
     *         'editor-last-login' => [
73
     *             'type' => 'datetime',
74
     *             'searchable' => false,
75
     *         ]
76
     *     ]
77
     * ]
78
     * ```
79
     *
80
     * @var array
81
     */
82
    protected $_attributes = [];
83
84
    /**
85
     * Constructor.
86
     *
87
     * @param \Cake\ORM\Table $table The table being handled
88
     */
89
    public function __construct(Table $table)
90
    {
91
        $this->_table = $table;
92
    }
93
94
    /**
95
     * Gets a clean column name from query expression.
96
     *
97
     * ### Example:
98
     *
99
     * ```php
100
     * EavToolbox::columnName('Tablename.some_column');
101
     * // returns "some_column"
102
     *
103
     * EavToolbox::columnName('my_column');
104
     * // returns "my_column"
105
     * ```
106
     *
107
     * @param string $column Column name from query
108
     * @return string
109
     */
110
    public static function columnName($column)
111
    {
112
        list($tableName, $fieldName) = pluginSplit((string)$column);
113
        if (!$fieldName) {
114
            $fieldName = $tableName;
115
        }
116
        $fieldName = preg_replace('/\s{2,}/', ' ', $fieldName);
117
        list($fieldName, ) = explode(' ', trim($fieldName));
118
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\Datasource\EntityInterface $entity The entity to check
127
     * @param string $property The property name
128
     * @return bool True if exists
129
     */
130
    public function propertyExists(EntityInterface $entity, $property)
131
    {
132
        $visibleProperties = $entity->visibleProperties();
133
134
        return in_array($property, $visibleProperties);
135
    }
136
137
    /**
138
     * Marshalls flat data into PHP objects.
139
     *
140
     * @param mixed $value The value to convert
141
     * @param string $type Type identifier, `integer`, `float`, etc
142
     * @return mixed Converted value
143
     */
144
    public function marshal($value, $type)
145
    {
146
        return Type::build($type)->marshal($value);
147
    }
148
149
    /**
150
     * Gets all attributes added to this table.
151
     *
152
     * @param string|null $bundle Get attributes within given bundle, or all of them
153
     *  regardless of the bundle if not provided
154
     * @return array List of attributes indexed by name (virtual column name)
155
     */
156
    public function attributes($bundle = null)
157
    {
158
        $key = empty($bundle) ? '@all' : $bundle;
159
        if (isset($this->_attributes[$key])) {
160
            return $this->_attributes[$key];
161
        }
162
163
        $this->_attributes[$key] = [];
164
        $cacheKey = $this->_table->table() . '_' . $key;
0 ignored issues
show
Deprecated Code introduced by
The method Cake\ORM\Table::table() has been deprecated with message: 3.4.0 Use setTable()/getTable() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
165
        $attrs = Cache::read($cacheKey, 'eav_table_attrs');
166
167
        if (empty($attrs)) {
168
            $conditions = ['EavAttributes.table_alias' => $this->_table->table()];
0 ignored issues
show
Deprecated Code introduced by
The method Cake\ORM\Table::table() has been deprecated with message: 3.4.0 Use setTable()/getTable() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
169
            if (!empty($bundle)) {
170
                $conditions['EavAttributes.bundle'] = $bundle;
171
            }
172
173
            $attrs = TableRegistry::get('Eav.EavAttributes')
174
                ->find()
175
                ->where($conditions)
176
                ->all()
177
                ->toArray();
178
179
            Cache::write($cacheKey, $attrs, 'eav_table_attrs');
180
        }
181
182
        foreach ($attrs as $attr) {
183
            $this->_attributes[$key][$attr->get('name')] = $attr;
184
        }
185
186
        return $this->attributes($bundle);
187
    }
188
189
    /**
190
     * Gets a list of attribute names.
191
     *
192
     * @param string $bundle Filter by bundle name
193
     * @return array
194
     */
195
    public function getAttributeNames($bundle = null)
196
    {
197
        $attributes = $this->attributes($bundle);
198
199
        return array_keys($attributes);
200
    }
201
202
    /**
203
     * Gets a list of attribute IDs.
204
     *
205
     * @param string $bundle Filter by bundle name
206
     * @return array
207
     */
208
    public function getAttributeIds($bundle = null)
209
    {
210
        $attributes = $this->attributes($bundle);
211
        $ids = [];
212
213
        foreach ($attributes as $name => $info) {
214
            $ids[] = $info['id'];
215
        }
216
217
        return $ids;
218
    }
219
220
    /**
221
     * Given a collection of entities gets the ID of all of them.
222
     *
223
     * This method iterates the given set and invokes `getEntityId()` for every
224
     * entity in the set.
225
     *
226
     * @param \Cake\Collection\CollectionInterface $results Set of entities
227
     * @return array List of entity ids suitable for EAV logic
228
     */
229
    public function extractEntityIds(CollectionInterface $results)
230
    {
231
        $entityIds = [];
232
        $results->each(function ($entity) use (&$entityIds) {
233
            if ($entity instanceof EntityInterface) {
234
                $entityIds[] = $this->getEntityId($entity);
235
            }
236
        });
237
238
        return $entityIds;
239
    }
240
241
    /**
242
     * Calculates entity's primary key.
243
     *
244
     * If PK is composed of multiple columns they will be merged with `:` symbol.
245
     * For example, consider `Users` table with composed PK <nick, email>, then for
246
     * certain User entity this method could return:
247
     *
248
     *     john-locke:[email protected]
249
     *
250
     * @param \Cake\Datasource\EntityInterface $entity The entity
251
     * @return string
252
     */
253
    public function getEntityId(EntityInterface $entity)
254
    {
255
        $pk = [];
256
        $keys = $this->_table->primaryKey();
0 ignored issues
show
Deprecated Code introduced by
The method Cake\ORM\Table::primaryKey() has been deprecated with message: 3.4.0 Use setPrimaryKey()/getPrimaryKey() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
257
        $keys = !is_array($keys) ? [$keys] : $keys;
258
        foreach ($keys as $key) {
259
            $pk[] = $entity->get($key);
260
        }
261
262
        return implode(':', $pk);
263
    }
264
265
    /**
266
     * Gets attribute's EAV type.
267
     *
268
     * @param string $attrName Attribute name
269
     * @return string Attribute's EAV type
270
     * @see \Eav\Model\Behavior\EavBehavior::_mapType()
271
     */
272
    public function getType($attrName)
273
    {
274
        return $this->mapType($this->attributes()[$attrName]->get('type'));
275
    }
276
277
    /**
278
     * Gets attribute's bundle.
279
     *
280
     * @param string $attrName Attribute name
281
     * @return string|null
282
     */
283
    public function getBundle($attrName)
284
    {
285
        return $this->attributes()[$attrName]->get('bundle');
286
    }
287
288
    /**
289
     * Whether the given attribute can be used in WHERE clauses.
290
     *
291
     * @param string $attrName Attribute name
292
     * @return bool
293
     */
294
    public function isSearchable($attrName)
295
    {
296
        return (bool)$this->attributes()[$attrName]->get('searchable');
297
    }
298
299
    /**
300
     * Maps schema data types to EAV's supported types.
301
     *
302
     * @param string $type A schema type. e.g. "string", "integer"
303
     * @return string A EAV type. Possible values are `datetime`, `binary`, `time`,
304
     *  `date`, `float`, `intreger`, `biginteger`, `text`, `string`, `boolean` or
305
     *  `uuid`
306
     */
307
    public function mapType($type)
308
    {
309
        switch ($type) {
310
            case 'float':
311
            case 'decimal':
312
                return 'float';
313
            case 'timestamp':
314
                return 'datetime';
315
            default:
316
                return $type;
317
        }
318
    }
319
320
    /**
321
     * Gets the name of the class driver used by the given $query to access the DB.
322
     *
323
     * @param \Cake\ORM\Query $query The query to inspect
324
     * @return string Lowercased drive name. e.g. `mysql`
325
     */
326
    public function driver(Query $query)
327
    {
328
        $conn = $query->connection(null);
0 ignored issues
show
Deprecated Code introduced by
The method Cake\Database\Query::connection() has been deprecated with message: 3.4.0 Use setConnection()/getConnection() instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
329
        list(, $driver) = namespaceSplit(strtolower(get_class($conn->driver())));
330
331
        return $driver;
332
    }
333
}
334