forked from UnionOfRAD/lithium
/
DocumentSchema.php
131 lines (111 loc) · 3.62 KB
/
DocumentSchema.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
<?php
/**
* li₃: the most RAD framework for PHP (http://li3.me)
*
* Copyright 2011, Union of RAD. All rights reserved. This source
* code is distributed under the terms of the BSD 3-Clause License.
* The full license text can be found in the LICENSE.txt file.
*/
namespace lithium\data;
use lithium\core\Libraries;
class DocumentSchema extends \lithium\data\Schema {
protected $_classes = [
'entity' => 'lithium\data\entity\Document',
'set' => 'lithium\data\collection\DocumentSet'
];
protected $_handlers = [];
protected function _init() {
$this->_autoConfig[] = 'handlers';
parent::_init();
}
public function cast($object, $key, $data, array $options = []) {
$defaults = [
'parent' => null,
'pathKey' => null,
'model' => null,
'wrap' => true,
'asContent' => false,
'first' => false
];
$options += $defaults;
$basePathKey = $options['pathKey'];
$classes = $this->_classes;
$fieldName = is_int($key) ? null : $key;
$pathKey = $basePathKey;
if ($fieldName) {
$pathKey = $basePathKey ? "{$basePathKey}.{$fieldName}" : $fieldName;
}
if ($data instanceof $classes['set'] || $data instanceof $classes['entity']) {
return $data;
}
if (is_object($data) && !$this->is('array', $pathKey) && !$options['asContent']) {
return $data;
}
return $this->_castArray($object, $data, $pathKey, $options, $defaults);
}
protected function _castArray($object, $val, $pathKey, $options, $defaults) {
$isArray = (
$this->is('array', $pathKey) &&
!$options['asContent'] &&
(!$object instanceof $this->_classes['set'])
);
$isObject = ($this->type($pathKey) === 'object');
$valIsArray = is_array($val);
$numericArray = false;
$class = 'entity';
if (!$valIsArray && !$isArray) {
return $this->_castType($val, $pathKey);
}
if ($valIsArray) {
$numericArray = !$val || array_keys($val) === range(0, count($val) - 1);
}
if ($isArray || ($numericArray && !$isObject)) {
$val = $valIsArray ? $val : [$val];
$class = 'set';
}
if ($options['wrap']) {
$config = [
'parent' => $options['parent'],
'model' => (!$options['model'] && $object) ? $object->model() : $options['model'],
'schema' => $this
];
$config += compact('pathKey') + array_diff_key($options, $defaults);
if (!$pathKey && $model = $options['model']) {
$exists = is_object($object) ? $object->exists() : false;
$config += ['class' => $class, 'exists' => $exists, 'defaults' => false];
$val = $model::create($val, $config);
} else {
$config['data'] = $val;
$val = Libraries::instance(null, $class, $config, $this->_classes);
}
} elseif ($class === 'set') {
$val = $val ?: [];
foreach ($val as &$value) {
$value = $this->_castType($value, $pathKey);
}
}
return $val;
}
/**
* Casts a scalar (non-object/array) value to its corresponding database-native value or custom
* value object based on a handler assigned to `$field`'s data type.
*
* @param mixed $value The value to be cast.
* @param string $field The name of the field that `$value` is or will be stored in. If it is a
* nested field, `$field` should be the full dot-separated path to the
* sub-object's field.
* @return mixed Returns the result of `$value`, modified by a matching handler data type
* handler, if available.
*/
protected function _castType($value, $field) {
if ($this->is('null', $field) && ($value === null || $value === "")) {
return null;
}
if (!is_scalar($value)) {
return $value;
}
$type = $this->type($field);
return isset($this->_handlers[$type]) ? $this->_handlers[$type]($value) : $value;
}
}
?>