1: <?php
2: /**
3: * This file is part of the PHPLucidFrame library.
4: * Seeder takes care of the initial seeding of your database with default or sample data.
5: *
6: * @package PHPLucidFrame\Core
7: * @since PHPLucidFrame v 1.14.0
8: * @copyright Copyright (c), PHPLucidFrame.
9: * @link http://phplucidframe.com
10: * @license http://www.opensource.org/licenses/mit-license.php MIT License
11: *
12: * This source file is subject to the MIT license that is bundled
13: * with this source code in the file LICENSE
14: */
15:
16: namespace LucidFrame\Core;
17:
18: /**
19: * Database Seeder
20: */
21: class Seeder
22: {
23: /** @var string The namespace for the database */
24: private $dbNamespace;
25: /** @var string Directory path to the files of seeding definition */
26: private $path;
27: /** @var array Seeding data */
28: private $data = array();
29: /** @var array Foreign key table data */
30: private static $references = array();
31: /** @var array Tables */
32: private $tables;
33:
34: /**
35: * Constructor
36: * @param string $namespace The database namespace
37: */
38: public function __construct($namespace = 'default')
39: {
40: $this->dbNamespace = $namespace;
41: $this->path = DB . 'seed' . _DS_;
42: }
43:
44: /**
45: * Setter for $dbNamespace
46: * @param string $namespace The database namespace
47: */
48: public function setDbNamespace($namespace)
49: {
50: $this->dbNamespace = $namespace;
51: }
52:
53: /**
54: * Getter for $dbNamespace
55: * @return string The database namespace
56: */
57: public function getDbNamespace()
58: {
59: return $this->dbNamespace;
60: }
61:
62: /**
63: * Set reference key
64: * @param string $key The reference key
65: * @return string
66: */
67: public static function getReference($key)
68: {
69: return __CLASS__ . '::' . $key;
70: }
71:
72: /**
73: * Get reference field value
74: * @param string $key The reference key
75: * @return mixed The value
76: */
77: public static function getReferenceValue($key)
78: {
79: return isset(self::$references[$key]) ? self::$references[$key] : null;
80: }
81:
82: /**
83: * Run seeding
84: * @param array $entities The array of entity names to be executed only
85: * @return boolean TRUE if seeded; otherwise FALSE
86: */
87: public function run(array $entities = array())
88: {
89: if ($this->load($entities)) {
90: # Purge before insert
91: db_disableForeignKeyCheck();
92:
93: if (count($entities)) {
94: $this->tables = array_filter($entities, function($table) {
95: return in_array($table, $this->tables);
96: });
97: }
98:
99: foreach ($this->tables as $table) {
100: db_truncate($table);
101: }
102:
103: $tableDone = '';
104:
105: # Arrange data to insert
106: foreach ($this->data as $reference => $record) {
107: if (!isset($record['__TABLE__'])) {
108: continue;
109: }
110:
111: $table = $record['__TABLE__'];
112: unset($record['__TABLE__']);
113:
114: if ($table != $tableDone) {
115: if ($tableDone) {
116: _writeln('%s is seeded.', $tableDone);
117: }
118: $tableDone = $table;
119: }
120:
121: $slug = null;
122: $data = array();
123: foreach ($record as $field => $value) {
124: if ($field == 'slug') {
125: $slug = $value;
126: unset($record['slug']);
127: }
128:
129: # Get foreign key field reference
130: if (is_string($value) && strpos($value, __CLASS__ . '::') === 0) {
131: $refKeyName = explode('::', $value);
132: $refKey = end($refKeyName);
133: $data[$field] = self::getReferenceValue($refKey);
134: } else {
135: $data[$field] = $value;
136: }
137: }
138:
139: # Make slug field at the start
140: if ($slug) {
141: $data = array('slug' => $slug) + $data;
142: }
143:
144: if ($insertId = db_insert($table, $data)) {
145: self::$references[$reference] = $insertId;
146: }
147: }
148:
149: if ($tableDone) {
150: _writeln('%s is seeded.', $tableDone);
151: }
152:
153: db_enableForeignKeyCheck();
154:
155: return true;
156: } else {
157: return false;
158: }
159: }
160:
161: /**
162: * Load seeding data
163: * @param array $entities The array of entity names to be executed only
164: * @return boolean TRUE if it is load; FALSE if nothing loaded
165: */
166: private function load(array $entities = array())
167: {
168: $_DB = _app('db');
169:
170: $entities = array_map(function($entity) {
171: $entity .= '.php';
172: return $entity;
173: }, $entities);
174:
175: $dir = $this->path . $this->dbNamespace;
176: if (is_dir($dir) && is_object($_DB)) {
177: $seeding = array();
178: $files = scandir($dir);
179: foreach ($files as $fileName) {
180: if (count($entities) && !in_array($fileName, $entities)) {
181: continue;
182: }
183:
184: $dir = rtrim(rtrim($dir, '/'), '\\');
185: $file = $dir . _DS_ . $fileName;
186:
187: if ($fileName === '.' || $fileName === '..' || $fileName === '.gitkeep' || !is_file($file)) {
188: continue;
189: }
190:
191: $table = substr($fileName, 0, -4);
192: if (file_exists($file) && $_DB->schemaManager->hasTable($table)) {
193: $data = include($file);
194: $order = $data['order'];
195: unset($data['order']);
196:
197: # prepend table name in data array
198: array_walk($data, function (&$value, $key, $table) {
199: $value = array('__TABLE__' => $table) + $value;
200: }, $table);
201:
202: $seeding[$order] = $data;
203: $this->tables[] = $table;
204: }
205: }
206:
207: ksort($seeding);
208:
209: foreach ($seeding as $data) {
210: $this->data += $data;
211: }
212: }
213:
214: return (bool) count($this->data);
215: }
216: }
217: