· 8 years ago · May 02, 2018, 08:28 PM
1<?php
2
3/**
4 * Adds some NoSQL flavour to any RDBMS that Cake supports
5 *
6 * Need to create a new table with the following schema...
7 *
8 * CREATE TABLE IF NOT EXISTS `options` (
9 * `id` int(11) NOT NULL auto_increment,
10 * `model` varchar(32) NOT NULL,
11 * `related_id` int(11) NOT NULL,
12 * `opt_key` varchar(32) NOT NULL,
13 * `opt_value` text NOT NULL,
14 * PRIMARY KEY (`id`),
15 * KEY `opt_key` (`opt_key`)
16 * );
17 */
18
19class OptionableBehavior extends ModelBehavior {
20
21 private $_settings = array();
22 private $_toSave = array();
23 private $_toFetch = array();
24 private $_toDelete = array();
25
26 public function setup(&$model, $settings = array()) {
27 $this->_settings[$model->alias] = array();
28
29 $defaults = array(
30 'model' => 'Option',
31 'fields' => array(),
32 'emptyFields' => true
33 );
34
35 $this->_settings[$model->alias] = $settings + $defaults;
36
37 $this->Model = ClassRegistry::init($this->_settings[$model->alias]['model']);
38 }
39
40 public function beforeFind(&$model, $query) {
41 $fetch = true;
42 $fields = $this->_settings[$model->alias]['fields'];
43
44 if (isset($query['options']) && $query['options'] == false) {
45 $fetch = false;
46 }
47
48 if ($fetch) {
49 if (isset($query['fields'])) {
50 foreach($fields as $field) {
51 if (in_array($field, (array) $query['fields'])) {
52 $this->_toFetch[] = $field;
53 } elseif (in_array($model->alias . '.' . $field, (array) $query['fields'])) {
54 $this->_toFetch[] = $field;
55 }
56 }
57
58 if (in_array('*', (array) $query['fields'])) {
59 $this->_toFetch += (array) $fields;
60 } elseif (in_array($model->alias . '.*', (array) $query['fields'])) {
61 $this->_toFetch += (array) $fields;
62 }
63
64 $this->_toFetch = array_unique($this->_toFetch);
65
66 if ($this->_toFetch) {
67 foreach ($query['fields'] as $k => $field) {
68 $field = (strpos($field, '.') === false)
69 ? $field
70 : str_replace($model->alias . '.', '', $field);
71
72 if (in_array($field, $this->_toFetch)) {
73 unset($query['fields'][$k]);
74 }
75 }
76 }
77
78 if (!in_array('id', (array) $query['fields'])
79 || !in_array($model->alias . '.id', (array) $query['fields'])) {
80 if (!is_array($query['fields'])) {
81 $query['fields'] = (array) $query['fields'];
82 }
83
84 $query['fields'][] = $model->alias . '.id';
85 }
86 } else {
87 $this->_toFetch = (array) $fields;
88 }
89 }
90
91 return $query;
92 }
93
94 public function afterFind(&$model, $results, $primary) {
95 if ($this->_toFetch) {
96 foreach ($results as $k => $result) {
97 if (isset($result[$model->alias])) {
98 $id = $result[$model->alias]['id'];
99 $return = $this->optGet($model, $id, $this->_toFetch);
100
101 $results[$k][$model->alias] += $return;
102 }
103 }
104
105 $this->_toFetch = array();
106 }
107
108 return $results;
109 }
110
111 public function beforeSave(&$model) {
112 $keysToSave = $toSave = $toDelete = array();
113
114 $fields = $this->_settings[$model->alias]['fields'];
115 $dataKeys = array_keys($model->data[$model->alias]);
116
117 $keysToSave = array_intersect($dataKeys, $fields);
118
119 if ($keysToSave) {
120 foreach ($keysToSave as $field) {
121 if (!empty($model->data[$model->alias][$field])) {
122 $toSave[$field] = $model->data[$model->alias][$field];
123 } else {
124 $toDelete[] = $field;
125 }
126 }
127 }
128
129 if ($toSave) {
130 $this->_toSave = $toSave;
131 }
132
133 if ($toDelete) {
134 $this->_toDelete = $toDelete;
135 }
136
137 return true;
138 }
139
140 public function afterSave(&$model, $created) {
141 $id = $model->id;
142
143 if (!$id) {
144 return;
145 }
146
147 if ($this->_toSave) {
148 $this->optSave($model, $id, $this->_toSave);
149 }
150
151 if ($this->_toDelete) {
152 $this->optDelete($model, $id, $this->_toDelete);
153 }
154
155 $this->_toSave = $this->_toDelete = array();
156 }
157
158 /*public function afterDelete(&$model) {
159 if ($model->id) {
160 return $this->Model->deleteAll(array(
161 'model' => $model->alias,
162 'related_id' => $model->id
163 ));
164 }
165 }*/
166
167 public function optGet(&$model, $id = null, $fields = array()) {
168 $return = array();
169
170 if (!$id && !$fields) {
171 $fields = $this->_settings[$model->alias]['fields'];
172 $id = $model->id;
173 }
174
175 if (is_array($id)) {
176 $fields = $id;
177 $id = $model->id;
178 }
179
180 if ($id && $fields) {
181 $conditions = array(
182 'related_id' => $id,
183 'model' => $model->alias,
184 'opt_key' => $fields
185 );
186
187 $options = $this->Model->find('all', compact('conditions'));
188
189 if ($options) {
190 foreach ($options as $opt) {
191 $return[$opt[$this->_settings[$model->alias]['model']]['opt_key']] = unserialize($opt[$this->_settings[$model->alias]['model']]['opt_value']);
192 }
193 }
194
195 if ($this->_settings[$model->alias]['emptyFields']) {
196 foreach ($fields as $field) {
197 if (!isset($return[$field])) {
198 $return[$field] = null;
199 }
200 }
201 }
202 }
203
204 return $return;
205 }
206
207 public function optSave(&$model, $id = null, $fields = array()) {
208 if (is_array($id)) {
209 $fields = $id;
210 $id = $model->id;
211 }
212
213 if ($id && $fields) {
214 foreach ($fields as $key => $value) {
215 $bypass = false;
216 $value = serialize($value);
217 $conditions = array(
218 'model' => $model->alias,
219 'related_id' => $id,
220 'opt_key' => $key
221 );
222 $data = $this->Model->find('first', compact('conditions'));
223
224 if ($data) {
225 if ($value === $data[$this->_settings[$model->alias]['model']]['opt_value']) {
226 $bypass = true;
227 } else {
228 $data[$this->_settings[$model->alias]['model']]['opt_value'] = $value;
229 }
230 } else {
231 $conditions['opt_value'] = $value;
232 $data = array($this->_settings[$model->alias]['model'] => $conditions);
233
234 $this->Model->create();
235 }
236
237 if (!$bypass) {
238 $this->Model->save($data);
239 }
240 }
241
242 return true;
243 }
244
245 return false;
246 }
247
248 public function optDelete(&$model, $id = null, $fields = array()) {
249 if (is_array($id)) {
250 $fields = $id;
251 $id = $model->id;
252 }
253
254 if ($id && $fields) {
255 return $this->Model->deleteAll(array(
256 'model' => $model->alias,
257 'related_id' => $id,
258 'opt_key' => $fields
259 ));
260 }
261
262 return false;
263 }
264}