· 7 years ago · Sep 05, 2018, 07:22 AM
1<?php
2
3class FixtureLoader
4{
5 const ACTION_SNAPSHOT_INIT = 'init';
6 const ACTION_SNAPSHOT_LOAD = 'load';
7 const ACTION_SNAPSHOT_CREATE = 'create';
8 const ACTION_SNAPSHOT_LIST = 'list';
9 const ACTION_CLEAR = 'clear';
10
11 const SNAPSHOT_TABLE_PREFIX = 'snapshot_fixture__';
12 const SNAPSHOT_FIELD_ID = 'snapshot_fixture__id';
13
14 /**
15 *
16 * @var Database connectino
17 */
18 protected $_conn = null;
19
20 /**
21 *
22 * @var array Tables list
23 */
24 protected $_tables = array();
25
26 /**
27 *
28 * @var array All tables fields
29 */
30 protected $_tableFields = array();
31
32 /**
33 *
34 * @var string Snapshot table prefix
35 */
36 protected $_snapshotTablePrefix = self::SNAPSHOT_TABLE_PREFIX;
37
38 /**
39 *
40 * @var string Snapshot table ID field name
41 */
42 protected $_snapshotFieldId = self::SNAPSHOT_FIELD_ID;
43
44
45 /**
46 * @var array Snapshot tables
47 */
48 protected $_snapshotTables = array();
49
50 /**
51 *
52 * @var Snapshots list
53 */
54 protected $_snapshots = array();
55
56 /**
57 *
58 * @var string Current snapshot loaded ID
59 */
60 protected $_currentSnapshot = null;
61
62 /**
63 * @var integer Snapshot sequence number
64 */
65 protected $_sequenceId = 0;
66
67
68 /**
69 * @var string
70 */
71 protected $_defaultSnapshotId = null;
72
73
74 /**
75 *
76 * @var array
77 */
78 protected static $_sqlActions = array(
79 self::ACTION_SNAPSHOT_INIT => 'CREATE TABLE IF NOT EXISTS {snapshot_table} AS
80 SELECT \'{snapshot_id}\' as {snapshot_field_id}, t.*
81 FROM (SELECT * FROM {table}) as t',
82
83 self::ACTION_SNAPSHOT_LOAD => 'INSERT INTO {table}
84 SELECT {fields}
85 FROM {snapshot_table}
86 WHERE {snapshot_field_id} = \'{snapshot_id}\'',
87
88 self::ACTION_SNAPSHOT_CREATE => 'INSERT INTO {snapshot_table}
89 SELECT \'{snapshot_id}\' as {snapshot_field_id}, t.*
90 FROM (SELECT * FROM {table}) as t',
91
92 self::ACTION_SNAPSHOT_LIST => 'SELECT DISTINCT {snapshot_field_id} FROM {snapshot_table}',
93
94 self::ACTION_CLEAR => 'DELETE FROM {table}'
95 );
96
97 /**
98 * @param Doctrine_Connection|PDO|null $conn
99 */
100 public function __construct($conn = null)
101 {
102 if (null == $conn) {
103 throw new InvalidArgumentException('You must provide a valid database connection');
104 }
105 $this->_conn = $conn;
106
107 $this->loadTables();
108
109 if (!$this->_defaultSnapshotId) {
110 $this->_defaultSnapshotId = md5(time() . uniqid());
111 }
112 $this->executeAction(self::ACTION_SNAPSHOT_INIT, $this->_defaultSnapshotId);
113 }
114
115 /**
116 * @return void
117 */
118 protected function loadTables()
119 {
120 $this->doLoadTables();
121
122 foreach ($this->_tables as $table) {
123 $this->_snapshotTables[$table] = sprintf($this->_snapshotTablePrefix . '_%s', $table);
124 }
125 }
126
127 /**
128 * @return void
129 */
130 protected function doLoadTables()
131 {
132 $models = Doctrine::getLoadedModels();
133
134 foreach ($models as $model) {
135 $table = Doctrine::getTable($model);
136 $this->_tableFields[$table->getTableName()] = $table->getColumnNames();
137 }
138 $this->_tables = array_keys($this->_tableFields);
139 }
140
141 /**
142 * @return array
143 */
144 public function getTables()
145 {
146 return $this->_tables;
147 }
148
149 /**
150 * @param string $path
151 *
152 * @return string The snapshot ID
153 */
154 public function loadData($path)
155 {
156 $id = md5($path);
157
158 if (false === $this->loadSnapshot($id)) {
159 $this->clearData();
160 $this->doLoadData($path);
161 $this->takeSnapshot($id, true, $path);
162 }
163
164 return $id;
165 }
166
167 /**
168 * @param string $path
169 */
170 protected function doLoadData($path)
171 {
172 Doctrine::loadData($path);
173 }
174
175 /**
176 * @return bool
177 */
178 public function clearData()
179 {
180 $this->executeAction(self::ACTION_CLEAR);
181 }
182
183 /**
184 * @return array
185 */
186 public function getSnapshots()
187 {
188 return $this->_snapshots;
189 }
190
191 /**
192 * @param string|null $id
193 * @param bool
194 *
195 * @return string The snapshot ID
196 *
197 */
198 public function takeSnapshot($id = null, $current = false, $value = true)
199 {
200 if (null == $id) {
201 $id = ++$this->_sequenceId;
202 }
203 $this->executeAction(self::ACTION_SNAPSHOT_CREATE, $id);
204
205 $this->_snapshots[$id] = $value;
206
207 if ($current) {
208 $this->_currentSnapshot = $id;
209 }
210
211 return $id;
212 }
213
214
215 /**
216 * @param string $id
217 *
218 * @return string The snapshot ID
219 */
220 public function loadSnapshot($id)
221 {
222 if (!$this->hasSnapshot($id)) {
223 return false;
224 }
225 $this->clearData();
226 $this->executeAction(self::ACTION_SNAPSHOT_LOAD, $id);
227
228 $this->_currentSnapshot = $id;
229
230 return $id;
231 }
232
233 /**
234 * @return string
235 */
236 public function getCurrentSnapshot()
237 {
238 return $this->_currentSnapshot;
239 }
240
241 /**
242 * @param type $id
243 *
244 * @return bool
245 */
246 public function hasSnapshot($id)
247 {
248 return isset($this->_snapshots[$id]);
249 }
250
251 /**
252 * @param type $action
253 * @param type $snapshotId
254 *
255 * @return PDOStatement
256 */
257 public function executeAction($action, $snapshotId = '')
258 {
259 $clauses = array();
260
261 foreach ($this->_tables as $table) {
262 $clauses[] = $this->buildTableSqlAction($table, $action, $snapshotId);
263 }
264 $sql = implode(";", $clauses);
265 $stmt = $this->_conn->exec($sql);
266
267 return $stmt;
268 }
269
270 /**
271 * @param string $table
272 * @param string $action
273 * @param string $snapshotId
274 *
275 * @return string
276 */
277 public function buildTableSqlAction($table, $action, $snapshotId = '')
278 {
279 $templateVars = $this->buildTableActionVars($table, $snapshotId);
280 $sql = $this->buildSqlAction($action, $templateVars);
281
282 return $sql;
283 }
284
285 /**
286 * @param string $table
287 * @param string $snapshotId
288 *
289 * @return array
290 */
291 public function buildTableActionVars($table, $snapshotId = '')
292 {
293 $snapshotTable = $this->_snapshotTables[$table];
294 $tableFields = '';
295
296 if (isset($this->_tableFields[$table])) {
297 $tableFields = implode(',', $this->_tableFields[$table]);
298 }
299 $templateVars = array(
300 'table' => $table,
301 'snapshot_id' => $snapshotId,
302 'snapshot_table' => $snapshotTable,
303 'snapshot_field_id' => $this->_snapshotFieldId,
304 'fields' => $tableFields
305 );
306
307 return $templateVars;
308 }
309
310 /**
311 * @param string $action
312 * @param string $vars
313 *
314 * @return string
315 */
316 public function buildSqlAction($action, $vars = array())
317 {
318 if (!isset(self::$_sqlActions[$action])) {
319 throw new InvalidArgumentException('Invalid action :' . $action);
320 }
321 $sql = self::$_sqlActions[$action];
322
323 foreach ($vars as $key => $val) {
324 $token = '{' . $key . '}';
325 $sql = str_replace($token, $val, $sql);
326 }
327 $sql = trim($sql);
328 $lns = explode("\n", $sql);
329
330 foreach ($lns as $k => $v) {
331 $lns[$k] = ltrim($v);
332 }
333 $sql = implode("", $lns);
334
335 return $sql;
336 }
337
338 /**
339 * Used for debug porpose, only
340 *
341 * @return array
342 */
343 public function retrieveAll()
344 {
345 $data = array();
346
347 foreach ($this->_tables as $table) {
348 $sql = 'SELECT * FROM ' . $table;
349 $stmt = $this->_conn->prepare($sql);
350 $stmt->execute();
351
352 $res = $stmt->fetchAll(PDO::FETCH_ASSOC);
353
354 if (count($res)) {
355 $data[] = $res;
356 }
357 }
358
359 return $data;
360 }
361
362 /**
363 * Used for debug porpose, only
364 *
365 * @param string|null $id
366 * @return array
367 */
368 public function retrieveAllInSnapshot($id = null)
369 {
370 $data = array();
371
372 foreach ($this->_snapshotTables as $table) {
373 $sql = 'SELECT * FROM ' . $table;
374 $stmt = $this->_conn->prepare($sql);
375 $stmt->execute();
376
377 $res = $stmt->fetchAll(PDO::FETCH_ASSOC);
378
379 if (count($res)) {
380 $data[] = $res;
381 }
382 }
383
384 return $data;
385 }
386}