PageRenderTime 54ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/src/Jrenton/LaravelScaffold/Model.php

https://github.com/mosoahmed/laravel-scaffold
PHP | 421 lines | 260 code | 60 blank | 101 comment | 51 complexity | 10167ce4340e29ee61e97cd3eafe252a MD5 | raw file
  1. <?php namespace Jrenton\LaravelScaffold;
  2. use Illuminate\Console\Command;
  3. class Model extends BaseModel
  4. {
  5. /**
  6. * @Illuminate\Console\Command
  7. */
  8. private $command;
  9. /**
  10. * @var string
  11. */
  12. private $propertiesStr = "";
  13. /**
  14. * @var array
  15. */
  16. private $propertiesToRemove = array();
  17. /**
  18. * @var string
  19. */
  20. private $inputProperties;
  21. /**
  22. * @var bool
  23. */
  24. private $namespaceGlobal = false;
  25. /**
  26. * @var array
  27. */
  28. private $oldModelFile;
  29. /**
  30. * @var bool
  31. */
  32. public $exists = false;
  33. /**
  34. * @var array
  35. */
  36. private $relationshipsToRemove = array();
  37. /**
  38. * @var bool
  39. */
  40. private $isPivotTable;
  41. /**
  42. * @param Command $command
  43. * @param array $oldModelFile
  44. */
  45. public function __construct(Command $command, $oldModelFile, $globalNamespace)
  46. {
  47. $this->command = $command;
  48. $this->oldModelFile = $oldModelFile;
  49. if(!empty($globalNamespace))
  50. {
  51. $this->namespace = $globalNamespace;
  52. $this->namespaceGlobal = true;
  53. }
  54. }
  55. /**
  56. * Generate a model from the specified input
  57. *
  58. * @param $modelAndProperties
  59. */
  60. public function generateModel($modelAndProperties)
  61. {
  62. $modelNameCollision = false;
  63. if($modelNameCollision)
  64. $modelAndProperties = $this->command->ask($this->upper() ." is already in the global namespace. Please namespace your class or provide a different name: ");
  65. $this->inputProperties = preg_split('/\s+/', $modelAndProperties);
  66. $modelWithNamespace = array_shift($this->inputProperties);
  67. if(!$this->namespaceGlobal)
  68. $this->namespace = $this->getNamespaceFromInput($modelWithNamespace);
  69. $this->getModel($modelWithNamespace);
  70. }
  71. /**
  72. * Generate properties
  73. *
  74. * @return bool
  75. */
  76. public function generateProperties()
  77. {
  78. if( !empty($this->inputProperties) )
  79. {
  80. $this->getModelsWithRelationships($this->inputProperties);
  81. $this->propertiesArr = $this->getPropertiesFromInput($this->inputProperties);
  82. $this->propertiesToRemove = $this->generatePropertiesToRemove();
  83. if($this->propertiesArr === false)
  84. return false;
  85. $this->propertiesStr .= implode(",", array_keys($this->propertiesArr));
  86. }
  87. return true;
  88. }
  89. /**
  90. * Return the properties that have been removed
  91. *
  92. * @return array
  93. */
  94. public function getPropertiesToRemove()
  95. {
  96. return $this->propertiesToRemove;
  97. }
  98. /**
  99. * Return the relationships that have been removed
  100. *
  101. * @return Relation[]
  102. */
  103. public function getRelationshipsToRemove()
  104. {
  105. return $this->relationshipsToRemove;
  106. }
  107. /**
  108. * Get relationships for the model from input
  109. *
  110. * @param $values
  111. */
  112. private function getModelsWithRelationships(&$values)
  113. {
  114. if($this->nextArgumentIsRelation($values[0]))
  115. {
  116. $relationship = $values[0];
  117. $relatedTable = trim($values[1], ',');
  118. $namespace = $this->namespace;
  119. if(strpos($relatedTable, "\\"))
  120. $model = substr(strrchr($relatedTable, "\\"), 1);
  121. else
  122. $model = $relatedTable;
  123. if(!$this->namespaceGlobal)
  124. {
  125. $namespace = $this->getNamespace($relatedTable);
  126. }
  127. $i = 2;
  128. $this->relationship = array();
  129. array_push($this->relationship, new Relation($relationship, new BaseModel($model, $namespace)));
  130. while($i < count($values) && $this->nextArgumentIsRelation($values[$i]))
  131. {
  132. if(strpos($values[$i], ",") === false)
  133. {
  134. $next = $i + 1;
  135. if($this->isLastRelation($values, $next))
  136. {
  137. $relationship = $values[$i];
  138. $relatedTable = trim($values[$next], ',');
  139. $i++;
  140. unset($values[$next]);
  141. }
  142. else
  143. {
  144. $relatedTable = $values[$i];
  145. }
  146. }
  147. else
  148. {
  149. $relatedTable = trim($values[$i], ',');
  150. }
  151. $namespace = $this->namespace;
  152. if(strpos($relatedTable, "\\"))
  153. $model = substr(strrchr($relatedTable, "\\"), 1);
  154. else
  155. $model = $relatedTable;
  156. if(!$this->namespaceGlobal)
  157. {
  158. $namespace = $this->getNamespace($relatedTable);
  159. }
  160. array_push($this->relationship, new Relation($relationship, new BaseModel($model, $namespace)));
  161. unset($values[$i]);
  162. $i++;
  163. }
  164. unset($values[0]);
  165. unset($values[1]);
  166. }
  167. $this->relationshipsToRemove = $this->generateRelationshipsToRemove();
  168. }
  169. /**
  170. * Get the namespace of the model
  171. *
  172. * @param $modelWithNamespace
  173. * @return string
  174. */
  175. private function getNamespaceFromInput($modelWithNamespace)
  176. {
  177. return substr($modelWithNamespace, 0, strrpos($modelWithNamespace, "\\"));
  178. }
  179. /**
  180. * Get the model name
  181. *
  182. * @param $modelWithNamespace
  183. */
  184. private function getModel($modelWithNamespace)
  185. {
  186. if(strpos($modelWithNamespace, "\\"))
  187. $model = substr(strrchr($modelWithNamespace, "\\"), 1);
  188. else
  189. $model = $modelWithNamespace;
  190. $this->generateModelName($model, $this->namespace);
  191. }
  192. /**
  193. * Check to see if input is the last relation
  194. *
  195. * @param $values
  196. * @param $next
  197. * @return bool
  198. */
  199. private function isLastRelation($values, $next)
  200. {
  201. return ($next < count($values) && $this->nextArgumentIsRelation($values[$next]));
  202. }
  203. /**
  204. * Check to see if the argument is a relation
  205. *
  206. * @param $value
  207. * @return bool
  208. */
  209. private function nextArgumentIsRelation($value)
  210. {
  211. return strpos($value, ":") === false && strpos($value, "(") === false;
  212. }
  213. /**
  214. * Get properties from the specified input
  215. *
  216. * @param $fieldNames
  217. * @return array|bool
  218. */
  219. private function getPropertiesFromInput($fieldNames)
  220. {
  221. $bundled = false;
  222. $fieldName = "";
  223. $type = "";
  224. $properties = array();
  225. foreach($fieldNames as $field)
  226. {
  227. $skip = false;
  228. $colonLocation = strrpos($field, ":");
  229. if ($colonLocation !== false && !$bundled)
  230. {
  231. $type = substr($field, $colonLocation+1);
  232. $fieldName = substr($field, 0, $colonLocation);
  233. }
  234. else if(strpos($field, '(') !== false)
  235. {
  236. $type = substr($field, 0, strpos($field, '('));
  237. $bundled = true;
  238. $skip = true;
  239. }
  240. else if($bundled)
  241. {
  242. if($colonLocation !== false && strpos($field, ")") === false)
  243. {
  244. $fieldName = substr($field, $colonLocation+1);
  245. $num = substr($field, 0, $colonLocation);
  246. }
  247. else if(strpos($field, ")") !== false)
  248. {
  249. $skip = true;
  250. $bundled = false;
  251. }
  252. else
  253. {
  254. $fieldName = $field;
  255. }
  256. }
  257. else if (strpos($field, "-") !== false)
  258. {
  259. $option = substr($field, strpos($field, "-")+1, strlen($field) - (strpos($field, "-")+1));
  260. if($option == "nt")
  261. {
  262. $this->timestamps = false;
  263. $skip = true;
  264. }
  265. else if($option == "sd")
  266. {
  267. $this->softDeletes = true;
  268. $skip = true;
  269. }
  270. else if($option == "pivot")
  271. {
  272. $this->isPivotTable = true;
  273. $skip = true;
  274. }
  275. }
  276. $fieldName = trim($fieldName, ",");
  277. $type = strtolower($type);
  278. if(!$skip && !empty($fieldName)) {
  279. if(!array_key_exists($type, $this->validTypes)) {
  280. $this->command->error($type. " is not a valid property type! ");
  281. return false;
  282. }
  283. $properties[$fieldName] = $type;
  284. }
  285. }
  286. return $properties;
  287. }
  288. /**
  289. * Compare new models definition file with old file to return
  290. * a list of the relationships that have been removed
  291. *
  292. * @return array
  293. */
  294. private function generateRelationshipsToRemove()
  295. {
  296. $relationships = array();
  297. if (array_key_exists($this->getTableName(), $this->oldModelFile)) {
  298. if (array_key_exists("relationships", $this->oldModelFile[$this->getTableName()])) {
  299. foreach ($this->oldModelFile[$this->getTableName()]["relationships"] as $oldRelation) {
  300. $found = false;
  301. foreach ($this->relationship as $relation) {
  302. if (isset($relation->model->tableName) && $relation->model->tableName == $oldRelation->model->tableName) {
  303. $found = true;
  304. break;
  305. }
  306. }
  307. if (!$found) {
  308. array_push($relationships, $oldRelation);
  309. }
  310. }
  311. }
  312. }
  313. return $relationships;
  314. }
  315. /**
  316. * Generates properties to remove based on properties that
  317. * have been removed since the last model definition file
  318. *
  319. * @return array
  320. */
  321. private function generatePropertiesToRemove()
  322. {
  323. $properties = array();
  324. if (array_key_exists($this->getTableName(), $this->oldModelFile)) {
  325. if (array_key_exists("properties", $this->oldModelFile[$this->getTableName()])) {
  326. foreach ($this->oldModelFile[$this->getTableName()]["properties"] as $property => $type) {
  327. if (!array_key_exists($property, $this->propertiesArr)) {
  328. $properties[$property] = $type;
  329. } else if ($this->oldModelFile[$this->getTableName()]["properties"][$property] != $this->propertiesArr[$property]) {
  330. $properties[$property] = $this->propertiesArr[$property];
  331. }
  332. }
  333. }
  334. }
  335. return $properties;
  336. }
  337. /**
  338. * @var array
  339. */
  340. public $validTypes = array(
  341. 'biginteger'=>'bigInteger',
  342. 'binary'=>'binary',
  343. 'boolean'=>'boolean',
  344. 'date'=>'date',
  345. 'datetime'=>'dateTime',
  346. 'decimal'=>'decimal',
  347. 'double'=>'double',
  348. 'enum'=>'enum',
  349. 'float'=>'float',
  350. 'integer'=>'integer',
  351. 'longtext'=>'longText',
  352. 'mediumtext'=>'mediumText',
  353. 'smallinteger'=>'smallInteger',
  354. 'tinyinteger'=>'tinyInteger',
  355. 'string'=>'string',
  356. 'text'=>'text',
  357. 'time'=>'time',
  358. 'timestamp'=>'timestamp',
  359. 'morphs'=>'morphs',
  360. 'bigincrements'=>'bigIncrements');
  361. }