MigrationsBase.php 34 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905
  1. <?php
  2. namespace MigrationsBundle\Migrations;
  3. use Doctrine\DBAL\Migrations\AbstractMigration;
  4. use Doctrine\DBAL\Schema\Schema;
  5. use Symfony\Component\DependencyInjection\ContainerAwareInterface;
  6. use Symfony\Component\DependencyInjection\ContainerInterface;
  7. use Symfony\Component\Yaml\Yaml;
  8. /**
  9. * Clase de migracion de base.
  10. * Orden de ejecucion de metodos.
  11. * 1- preUp
  12. * 2- up
  13. * 3- postUp
  14. * 4- preDown
  15. * 5- down
  16. * 6- postDown
  17. */
  18. class MigrationsBase extends AbstractMigration implements ContainerAwareInterface
  19. {
  20. /**
  21. * Tipo de senetencia sql insert.
  22. */
  23. const INSERT = "INSERT";
  24. /**
  25. * Tipo de sentencia sql update.
  26. */
  27. const UPDATE = "UPDATE";
  28. /**
  29. * Tipo de sentenca sql delete.
  30. */
  31. const DELETE = "DELETE";
  32. /**
  33. * Tipo de sentenca sql replace.
  34. */
  35. const REPLACE = "REPLACE";
  36. /**
  37. * Tipo de sentenca sql insert or update.
  38. */
  39. const INSERTORUPDATE = "INSERTORUPDATE";
  40. /**
  41. * Tipo de sentenca sql insert ignore.
  42. */
  43. const INSERTIGNORE = "INSERTIGNORE";
  44. /**
  45. * @var int $line Contiene el numero de linea que estoy ejecutando.
  46. */
  47. private $line = 0;
  48. /**
  49. * @var bool Me dice si tengo que mostrar los parametros en las consultas.
  50. */
  51. private $showParameters = false;
  52. /**
  53. * @var array $errorLineExecution Contiene una descripcion del error que ocaciono una linea del script YAML.
  54. */
  55. private $errorLineExecution = array();
  56. /**
  57. * @var array $lineExecution Contiene una descripcion de como se ejecuto cada linea del script YAML.
  58. */
  59. private $lineExecution = array();
  60. /**
  61. * @var ContainerInterface $container Contiene el contenedor.
  62. */
  63. private $container;
  64. /**
  65. * @param ContainerInterface|null $container Contiene un objeto que implementa "ContainerInterface".
  66. * @return ContainerInterface Retorna un objeto que implementa la interfaz "ContainerInterface".
  67. */
  68. public function setContainer(ContainerInterface $container = null)
  69. {
  70. $this->container = $container;
  71. return $this->container;
  72. }
  73. /**
  74. * @return ContainerInterface Retorna un objeto que implementa la interfaz "ContainerInterface".
  75. */
  76. public function getContainer()
  77. {
  78. return $this->container;
  79. }
  80. /**
  81. * @return bool Retorna el valor de la variable showParameters.
  82. */
  83. public function isShowParameters()
  84. {
  85. return $this->showParameters;
  86. }
  87. /**
  88. * @param bool $showParameters Si esta en TRUE muestra los parametros en las consultas.
  89. */
  90. public function setShowParameters($showParameters)
  91. {
  92. $this->showParameters = $showParameters;
  93. }
  94. /**
  95. * @return int Retorna el numero de linea que estoy analizando.
  96. */
  97. public function getLine()
  98. {
  99. return $this->line;
  100. }
  101. /**
  102. * @param int $line Setea el numero de linea.
  103. */
  104. private function setLine($line)
  105. {
  106. $this->line = $line;
  107. }
  108. /**
  109. * Funcion que suma 1 a la variable line.
  110. */
  111. private function sumLine()
  112. {
  113. $this->line = $this->line + 1;
  114. }
  115. /**
  116. * @return array Retorna un array con las lineas que produjeron errores.
  117. */
  118. public function getErrorLineExecution()
  119. {
  120. return $this->errorLineExecution;
  121. }
  122. /**
  123. * @param array $errorLineExecution Setea un array con las lineas que produjeron errores.
  124. */
  125. public function setErrorLineExecution($errorLineExecution)
  126. {
  127. $this->errorLineExecution = $errorLineExecution;
  128. }
  129. /**
  130. * Agrega una linea de error.
  131. * @param string $type Contiene el tipo de sentencia sql.
  132. * @param \Throwable $ex Contiene una excepcion.
  133. */
  134. private function addErrorLineExecution($type, \Throwable $ex)
  135. {
  136. if (!array_key_exists($type, $this->errorLineExecution)) {
  137. $this->errorLineExecution[$type] = array();
  138. }
  139. array_push($this->errorLineExecution[$type], "Line: " . $this->getLine() . " => [" . $ex->getCode() . "] = " . $ex->getMessage());
  140. }
  141. /**
  142. * @return array Retorna una array con el valor de la ejecucion de cada linea.
  143. */
  144. public function getLineExecution()
  145. {
  146. return $this->lineExecution;
  147. }
  148. /**
  149. * @param array $lineExecution Setea un array con las lineas de ejecucion.
  150. */
  151. public function setLineExecution($lineExecution)
  152. {
  153. $this->lineExecution = $lineExecution;
  154. }
  155. /**
  156. * Agrega el valor de la ejecucion.
  157. * @param string $type Contiene el tipo de sentencia sql.
  158. * @param string $value Contiene el valor de la ejecucion.
  159. */
  160. private function addLineExecution($type, $value)
  161. {
  162. if (!array_key_exists($type, $this->lineExecution)) {
  163. $this->lineExecution[$type] = array();
  164. }
  165. array_push($this->lineExecution[$type], "Line: " . $this->getLine() . " => " . $value);
  166. }
  167. /**
  168. * Realiza un up de la modificaciones DDL. Siempre son agregados.
  169. * Para realizar sentencias DML utilizarlos metodos preUp y postUp.
  170. * @param Schema $schema Contiene el objeto esquema.
  171. */
  172. public function up(Schema $schema)
  173. {
  174. }
  175. /**
  176. * Realiza un up de la modificaciones DDL. Siempre son eliminacion.
  177. * Para realizar sentencias DML utilizarlos metodos preDown y postDown.
  178. * @param Schema $schema Contiene el objeto esquema.
  179. */
  180. public function down(Schema $schema)
  181. {
  182. }
  183. /**
  184. * Procesa un yaml para generar las sentencias DML que luego seran ejecutadas en la base de datos.
  185. * El directorio origen es <code>app/DoctrineMigrations</code> en adelante. SE UTILIZA EN LA
  186. * FUNCION "up" o "down". NO FUNCIONA EN LAS FUNCIONES "pre" y "post".
  187. * @param string $dir Contiene el nombre del directorio a leer.
  188. * @param string $fileName Contiene el nombre del archivo a incorporar.
  189. */
  190. public function interpretYaml($dir, $fileName)
  191. {
  192. $dir = trim($dir);
  193. if (!(substr($dir, count($dir) - 2, count($dir) - 2) == "\\" ||
  194. substr($dir, count($dir) - 2, count($dir) - 2) == "/")
  195. ) {
  196. $dir = $dir . "/";
  197. }
  198. // leo el yaml
  199. $value = $this->readYaml($dir, $fileName);
  200. if ($value != null && count($value) > 0) {
  201. // paso las key a mayusculas
  202. foreach ($value as $key => $val) {
  203. unset($value[$key]);
  204. $value[strtoupper($key)] = $val;
  205. }
  206. // reemplazo las keys que poseen importkey
  207. $value = $this->replaceImportsKey($dir, $value);
  208. // reemplazo los valores que poseen import
  209. $value = $this->replaceImportsValue($dir, $value);
  210. // lo hago de esta forma para que se ejecuten de acuerdo a como se escribe el yaml.
  211. $this->setLine(0);
  212. foreach ($value as $key => $val) {
  213. if (strtoupper($key) === MigrationsBase::INSERT) {
  214. $this->createInserts($value[MigrationsBase::INSERT]);
  215. } else if (strtoupper($key) === MigrationsBase::UPDATE) {
  216. $this->createUpdates($value[MigrationsBase::UPDATE]);
  217. } else if (strtoupper($key) === MigrationsBase::DELETE) {
  218. $this->createDeletes($value[MigrationsBase::DELETE]);
  219. } else if (strtoupper($key) === MigrationsBase::REPLACE) {
  220. $this->createReplace($value[MigrationsBase::REPLACE]);
  221. } else if (strtoupper($key) === MigrationsBase::INSERTORUPDATE) {
  222. $this->createInsertOrUpdate($value[MigrationsBase::INSERTORUPDATE]);
  223. } else if (strtoupper($key) === MigrationsBase::INSERTIGNORE) {
  224. $this->createInsertIgnore($value[MigrationsBase::INSERTIGNORE]);
  225. } else {
  226. throw new Exception("Los valores permitidos son: insert, insertorupdate, insertignore, update, delete.");
  227. }
  228. }
  229. }
  230. }
  231. /**
  232. * Crea los insert a partir de una estructura yaml.
  233. * @param array $arrayInsert Contiene la estructura yaml para los insert.
  234. */
  235. private function createInserts($arrayInsert)
  236. {
  237. foreach ($arrayInsert as $table => $inserts) {
  238. // recorro las tablas
  239. foreach ($inserts as $key => $valueKey) {
  240. // recorro cada uno de los insert que quiero hacer
  241. // almacena los campos
  242. $fields = "";
  243. // almacena el valor de los campos
  244. $valuesFields = "";
  245. // me dice si tengo que utilizar la palabra ignore
  246. $ignore = " ";
  247. // contiene la primer palabra de la sentencia (INSERT/REPLACE)
  248. $insert = "INSERT";
  249. // me dice si es un insert or update
  250. $orUpdate = false;
  251. // contiene los valores del insert or update
  252. $orUpdateValues = "";
  253. // contiene los valores para el bind del stament
  254. $arrayPrepare = array();
  255. foreach ($valueKey as $field => $value) {
  256. // recorro los datos a insertar
  257. $field = strtolower(trim($field));
  258. $value = trim($value);
  259. if (strlen($field) > 0 && strlen($value) > 0) {
  260. if ($field === 'ignore') {
  261. $value = strtolower($value);
  262. if ($value === '1' || $value === 'true') {
  263. if ($insert === 'INSERT') {
  264. $ignore = " IGNORE ";
  265. }
  266. }
  267. } else if ($field === 'orupdate') {
  268. $value = strtolower($value);
  269. if ($value === '1' || $value === 'true') {
  270. $orUpdate = true;
  271. $ignore = " ";
  272. $insert = "INSERT";
  273. }
  274. } else {
  275. $arrayPrepare[':' . $field] = $value;
  276. $fields = $fields . $field . ", ";
  277. $valuesFields = $valuesFields . ":" . $field . ", ";
  278. }
  279. }
  280. }
  281. if (strlen($fields) > 1) {
  282. $fields = substr($fields, 0, strlen($fields) - 2);
  283. }
  284. if (strlen($valuesFields) > 1) {
  285. $valuesFields = substr($valuesFields, 0, strlen($valuesFields) - 2);
  286. }
  287. if (strlen($fields) > 1 && strlen($valuesFields) > 1) {
  288. $sql = $insert . $ignore . "INTO " . $table . " (" . $fields . ") VALUES (" . $valuesFields . ");";
  289. $this->executeSQL($sql, MigrationsBase::INSERT, $arrayPrepare);
  290. }
  291. }
  292. }
  293. }
  294. /**
  295. * Crea los insert ignore a partir de una estructura yaml.
  296. * @param array $arrayInsert Contiene la estructura yaml para los insert.
  297. */
  298. private function createInsertIgnore($arrayInsert)
  299. {
  300. foreach ($arrayInsert as $table => $inserts) {
  301. // recorro las tablas
  302. foreach ($inserts as $key => $valueKey) {
  303. // recorro cada uno de los insert que quiero hacer
  304. // almacena los campos
  305. $fields = "";
  306. // almacena el valor de los campos
  307. $valuesFields = "";
  308. // contiene la primer palabra de la sentencia (INSERT/REPLACE)
  309. $insert = "INSERT IGNORE ";
  310. // contiene los valores del insert or update
  311. $orUpdateValues = "";
  312. // contiene los valores para el bind del stament
  313. $arrayPrepare = array();
  314. foreach ($valueKey as $field => $value) {
  315. // recorro los datos a insertar
  316. $field = strtolower(trim($field));
  317. $value = trim($value);
  318. if (strlen($field) > 0 && strlen($value) > 0) {
  319. $arrayPrepare[':' . $field] = $value;
  320. $fields = $fields . $field . ", ";
  321. $valuesFields = $valuesFields . ":" . $field . ", ";
  322. }
  323. }
  324. if (strlen($fields) > 1) {
  325. $fields = substr($fields, 0, strlen($fields) - 2);
  326. }
  327. if (strlen($valuesFields) > 1) {
  328. $valuesFields = substr($valuesFields, 0, strlen($valuesFields) - 2);
  329. }
  330. if (strlen($fields) > 1 && strlen($valuesFields) > 1) {
  331. $sql = $insert . "INTO " . $table . " (" . $fields . ") VALUES (" . $valuesFields . ");";
  332. $this->executeSQL($sql, MigrationsBase::INSERT, $arrayPrepare);
  333. }
  334. }
  335. }
  336. }
  337. /**
  338. * Crea los insert or update a partir de una estructura yaml.
  339. * @param array $arrayInsert Contiene la estructura yaml para los insert.
  340. */
  341. private function createInsertOrUpdate($arrayInsert)
  342. {
  343. foreach ($arrayInsert as $table => $inserts) {
  344. // recorro las tablas
  345. foreach ($inserts as $key => $valueKey) {
  346. // recorro cada uno de los insert que quiero hacer
  347. // almacena los campos
  348. $fields = "";
  349. // almacena el valor de los campos
  350. $valuesFields = "";
  351. // contiene la primer palabra de la sentencia INSERT
  352. $insert = "INSERT";
  353. // contiene los valores del insert or update
  354. $orUpdateValues = "";
  355. // contiene los valores para el bind del stament
  356. $arrayPrepare = array();
  357. foreach ($valueKey as $field => $value) {
  358. // recorro los datos a insertar
  359. $field = strtolower(trim($field));
  360. $value = trim($value);
  361. if (strlen($field) > 0 && strlen($value) > 0) {
  362. $arrayPrepare[':' . $field] = $value;
  363. $fields = $fields . $field . ", ";
  364. $valuesFields = $valuesFields . ":" . $field . ", ";
  365. $orUpdateValues = $orUpdateValues . $field . " = " . ":" . $field . ", ";
  366. }
  367. }
  368. if (strlen($fields) > 1) {
  369. $fields = substr($fields, 0, strlen($fields) - 2);
  370. }
  371. if (strlen($valuesFields) > 1) {
  372. $valuesFields = substr($valuesFields, 0, strlen($valuesFields) - 2);
  373. }
  374. if (strlen($orUpdateValues) > 1) {
  375. $orUpdateValues = substr($orUpdateValues, 0, strlen($orUpdateValues) - 2);
  376. }
  377. if (strlen($fields) > 1 && strlen($valuesFields) > 1) {
  378. $sql = $insert . " INTO " . $table . " (" . $fields . ") VALUES (" . $valuesFields . ")";
  379. $sql .= " ON DUPLICATE KEY UPDATE " . $orUpdateValues . ";";
  380. $this->executeSQL($sql, MigrationsBase::INSERT, $arrayPrepare);
  381. }
  382. }
  383. }
  384. }
  385. /**
  386. * Crea los replace a partir de una estructura yaml.
  387. * @param array $arrayInsert Contiene la estructura yaml para los insert.
  388. */
  389. private function createReplace($arrayInsert)
  390. {
  391. foreach ($arrayInsert as $table => $inserts) {
  392. // recorro las tablas
  393. foreach ($inserts as $key => $valueKey) {
  394. // recorro cada uno de los insert que quiero hacer
  395. // almacena los campos
  396. $fields = "";
  397. // almacena el valor de los campos
  398. $valuesFields = "";
  399. // contiene la primer palabra de la sentencia INSERT
  400. $insert = "REPLACE";
  401. // contiene los valores para el bind del stament
  402. $arrayPrepare = array();
  403. foreach ($valueKey as $field => $value) {
  404. // recorro los datos a insertar
  405. $field = strtolower(trim($field));
  406. $value = trim($value);
  407. if (strlen($field) > 0 && strlen($value) > 0) {
  408. $arrayPrepare[':' . $field] = $value;
  409. $fields = $fields . $field . ", ";
  410. $valuesFields = $valuesFields . ":" . $field . ", ";
  411. }
  412. }
  413. if (strlen($fields) > 1) {
  414. $fields = substr($fields, 0, strlen($fields) - 2);
  415. }
  416. if (strlen($valuesFields) > 1) {
  417. $valuesFields = substr($valuesFields, 0, strlen($valuesFields) - 2);
  418. }
  419. if (strlen($fields) > 1 && strlen($valuesFields) > 1) {
  420. $sql = $insert . " INTO " . $table . " (" . $fields . ") VALUES (" . $valuesFields . ");";
  421. $this->executeSQL($sql, MigrationsBase::INSERT, $arrayPrepare);
  422. }
  423. }
  424. }
  425. }
  426. /**
  427. * Crea los update a partir de una estructura yaml.
  428. * @param array $arrayInsert Contiene la estructura yaml para los insert.
  429. */
  430. private function createUpdates($arrayInsert)
  431. {
  432. foreach ($arrayInsert as $table => $inserts) {
  433. // recorro las tablas
  434. foreach ($inserts as $key => $valueKey) {
  435. // recorro cada uno de los insert que quiero hacer
  436. $set = "";
  437. $where = "";
  438. // contiene los valores para el bind del stament
  439. $arrayPrepare = array();
  440. foreach ($valueKey as $field => $value) {
  441. // recorro los datos a realizar un update
  442. if (strlen(trim($field)) > 0 && strlen(trim($value)) > 0) {
  443. if ($field === "where") {
  444. $where = $value;
  445. } else {
  446. $arrayPrepare[':' . $field] = $value;
  447. $set = $set . $field . " = :" . $field . ", ";
  448. }
  449. }
  450. }
  451. if (strlen($set) > 1) {
  452. $set = substr($set, 0, strlen($set) - 2);
  453. }
  454. if (strlen($set) > 1) {
  455. $sql = "UPDATE " . $table . " SET " . $set . " WHERE " . $where . ";";
  456. $this->executeSQL($sql, MigrationsBase::UPDATE, $arrayPrepare);
  457. }
  458. }
  459. }
  460. }
  461. /**
  462. * Crea los delete a partir de una estructura yaml.
  463. * @param array $arrayInsert Contiene la estructura yaml para los insert.
  464. */
  465. private function createDeletes($arrayInsert)
  466. {
  467. foreach ($arrayInsert as $table => $inserts) {
  468. // recorro las tablas
  469. foreach ($inserts as $key => $valueKey) {
  470. // recorro cada uno de los insert que quiero hacer
  471. $where = "";
  472. foreach ($valueKey as $field => $value) {
  473. // recorro los datos a realizar un update
  474. if (strlen(trim($field)) > 0 && strlen(trim($value)) > 0) {
  475. if ($field === "where") {
  476. $where = $value;
  477. }
  478. }
  479. }
  480. $sql = "DELETE FROM " . $table . " WHERE " . $where . ";";
  481. $this->executeSQL($sql, MigrationsBase::DELETE);
  482. }
  483. }
  484. }
  485. /**
  486. * Obtiene el contenido de un archivo yaml.
  487. * @param string $dir Contiene el directorio de trabajo. Por defecto "DoctrineMigrations".
  488. * @param string $archivo Contiene el nombre del archivo a incorporar.
  489. * @return bool|string Retorna el contenido del archivo.
  490. */
  491. private function readYaml($dir, $archivo)
  492. {
  493. return Yaml::parse(file_get_contents($dir . $archivo));
  494. }
  495. /**
  496. * Obtiene el contenido de un archivo.
  497. * @param string $dir Contiene el directorio de trabajo. Por defecto "DoctrineMigrations".
  498. * @param string $archivo Contiene el nombre del archivo a incorporar.
  499. * @return bool|string Retorna el contenido del archivo.
  500. */
  501. private function readImportInValues($dir, $archivo)
  502. {
  503. return file_get_contents($dir . $archivo);
  504. }
  505. /**
  506. * Reemplaza el contenido de los imports dentro de los values.
  507. * @param string $dir Contiene el directorio de trabajo. Por defecto "DoctrineMigrations".
  508. * @param array $valores Contiene el array el contenido del yaml.
  509. * @return array Retorna el array con los valores cambiados.
  510. */
  511. private function replaceImportsValue($dir, $valores)
  512. {
  513. try {
  514. foreach ($valores as $key => $value) {
  515. if (is_array($value)) {
  516. if (count($value) == 1 && array_key_exists("import", $value)) {
  517. if (file_exists($dir . $value["import"])) {
  518. $valores[$key] = $this->readImportInValues($dir, $value["import"]);
  519. } else {
  520. $valores[$key] = "FILE NOT FOUND";
  521. }
  522. } else {
  523. $valores[$key] = $this->replaceImportsValue($dir, $value);
  524. }
  525. }
  526. }
  527. } catch (\Symfony\Component\Debug\Exception\ContextErrorException $e) {
  528. var_export($e);
  529. }
  530. return $valores;
  531. }
  532. /**
  533. * Reemplaza el contenido de los imports dentro de las key.
  534. * @param string $dir Contiene el directorio de trabajo. Por defecto "DoctrineMigrations".
  535. * @param array $valores Contiene el array el contenido del yaml.
  536. * @return array Retorna el array con los valores cambiados.
  537. */
  538. private function replaceImportsKey($dir, $valores)
  539. {
  540. try {
  541. foreach ($valores as $key => $value) {
  542. if (is_array($value)) {
  543. $valores[$key] = $this->replaceImportsKey($dir, $value);
  544. } else {
  545. if (trim($key) === "importkey") {
  546. if (file_exists($dir . $value)) {
  547. $valores = $this->readYaml($dir, $value);
  548. } else {
  549. $valores[$key] = "FILE NOT FOUND";
  550. }
  551. }
  552. }
  553. }
  554. } catch (\Symfony\Component\Debug\Exception\ContextErrorException $e) {
  555. var_export($e);
  556. }
  557. return $valores;
  558. }
  559. /**
  560. * Funcion ejecuta el YAML en la base de datos dentro de una transaccion.
  561. * @param string $dir Contiene el path del directorio donde se encuentra el archio a leer.
  562. * @param string $file Contiene el nombre de archivo a procesar.
  563. */
  564. public function executeYaml($dir, $file)
  565. {
  566. try {
  567. $tmp = explode("\\", get_class($this));
  568. if ($tmp != null && count($tmp) > 0) {
  569. $version = $tmp[count($tmp) - 1];
  570. } else {
  571. $version = "";
  572. }
  573. echo "\n\tInicio del procesamiento de la migracion: " . $version;
  574. try {
  575. $this->interpretYaml($dir, $file);
  576. if (count($this->getErrorLineExecution()) > 0) {
  577. echo "\n\t\tSe produjeron errores de sql.\n";
  578. } else {
  579. echo "\n\t\tMigracion correcta.\n";
  580. }
  581. } catch (\Throwable $ex) {
  582. $this->connection->rollBack();
  583. echo "\n\t\tSe produjeron errores por una excepcion. " . $ex->getMessage() . "\n";
  584. }
  585. } catch (\Throwable $e) {
  586. echo "\n\t\tSe produjeron errores genericos. " . $e->getMessage() . "\n";
  587. }
  588. }
  589. /**
  590. * Funcion que ejecuta una sentencia sql.
  591. * @param string $sql Contiene el sql a ejecutar.
  592. * @param string $type Contiene el tipo de sentencia.
  593. * @param array $arrayPrepare Contiene un array con los valores. La key contiene el valor a
  594. * buscar en la sentencia sql y el value es el valor.
  595. */
  596. public function executeSQL($sql, $type, $arrayPrepare = null)
  597. {
  598. $this->addSql($sql, (array)$arrayPrepare);
  599. $this->sumLine();
  600. }
  601. /**
  602. * Funcion que obtiene el numero de version.
  603. * @param mixed $obj Contiene el objeto de ejecucion.
  604. * @return string Retorna el numero de version que estoy ejecutando.
  605. */
  606. public function getMigrationNumber($obj)
  607. {
  608. $arr = explode("\\", get_class($obj));
  609. return str_ireplace("version", "", $arr[count($arr) - 1]);
  610. }
  611. /**
  612. * Borra la migracion de la tabla de migraciones.
  613. * @param string $obj Contiene el objeto this.
  614. */
  615. public function deleteMigrationsVersion($obj)
  616. {
  617. if ($this->existTable("migration_versions")) {
  618. $this->connection->beginTransaction();
  619. $stmt = $this->connection->prepare(
  620. "DELETE FROM migration_versions " .
  621. "WHERE migration_versions.version = '" . $this->getMigrationNumber($obj) . "'");
  622. $stmt->execute();
  623. $this->connection->commit();
  624. }
  625. }
  626. /**
  627. * Verifica si la migracion ya se incorporo.
  628. * @param string $obj Contiene el objeto this.
  629. * @return bool Retorna TRUE si ya se realizo la migracion.
  630. */
  631. public function verifyMigrationsVersion($obj)
  632. {
  633. $existe = false;
  634. try {
  635. if ($this->existTable("migration_versions")) {
  636. $nroVersion = $this->getMigrationNumber($obj);
  637. $base = $this->getDataBaseName();
  638. $sql =
  639. "SELECT ifnull(version, '') as nombre " .
  640. "FROM migration_versions " .
  641. "WHERE " .
  642. $base . ".migration_versions.version = '" . $nroVersion . "';";
  643. $stmt = $this->connection->prepare($sql);
  644. $stmt->execute();
  645. $resp = $stmt->fetchAll();
  646. foreach ($resp as $key => $value) {
  647. if (strtolower($value["nombre"]) === strtolower($nroVersion)) {
  648. $existe = true;
  649. break;
  650. }
  651. }
  652. }
  653. return $existe;
  654. } catch (\Throwable $e) {
  655. return $existe;
  656. }
  657. }
  658. /**
  659. * Funcion que muestra por pantalla el resultado de la ejecucion y de los errores.
  660. */
  661. public function showResult()
  662. {
  663. if (count($this->getLineExecution()) > 0) {
  664. echo "-----------------------------------------------\n";
  665. echo " EJECUCIONES\n";
  666. echo "-----------------------------------------------\n";
  667. foreach ($this->getLineExecution() as $key => $value) {
  668. echo $key . "\n";
  669. foreach ($this->getLineExecution()[$key] as $k => $v) {
  670. echo "\t" . $v . "\n";
  671. }
  672. }
  673. }
  674. if (count($this->getErrorLineExecution()) > 0) {
  675. echo "-----------------------------------------------\n";
  676. echo " ERRORES\n";
  677. echo "-----------------------------------------------\n";
  678. foreach ($this->getErrorLineExecution() as $key => $value) {
  679. echo $key . "\n";
  680. foreach ($this->getErrorLineExecution()[$key] as $k => $v) {
  681. echo "\t" . $v . "\n";
  682. }
  683. }
  684. }
  685. }
  686. /**
  687. * Funcion que verifica si existe un campo de una tabla.
  688. * @param string $table Contiene el nombre de la tabla.
  689. * @param string $field Contiene el nombre el campo.
  690. * @return bool Retorna true si el campo existe.
  691. */
  692. public function existFieldInTable($table, $field)
  693. {
  694. $existe = false;
  695. try {
  696. $base = $this->getDataBaseName();
  697. $sql = "SELECT ifnull(COLUMN_NAME, '') as nombre " .
  698. "FROM information_schema.columns " .
  699. "WHERE TABLE_SCHEMA = '" . $base . "' AND " .
  700. " TABLE_NAME = '" . $table . "' AND " .
  701. " COLUMN_NAME = '" . $field . "'; ";
  702. $stmt = $this->connection->prepare($sql);
  703. $stmt->execute();
  704. $resp = $stmt->fetchAll();
  705. foreach ($resp as $key => $value) {
  706. if (strtolower($value["nombre"]) === strtolower($field)) {
  707. $existe = true;
  708. break;
  709. }
  710. }
  711. return $existe;
  712. } catch (\Throwable $e) {
  713. return $existe;
  714. }
  715. }
  716. /**
  717. * Funcion que verifica si existe un valor dentro de una tabla.
  718. * @param string $table Contiene el nombre de la tabla.
  719. * @param string $field Contiene el/los campos a mostrar.
  720. * @param string $where Contiene el where de la consulta. Solo los campos con los valores. SIN
  721. * LA PALABRA CLAVE.
  722. * @return array Retorna el array con los datos encontrados. O NULL en caso de error.
  723. */
  724. public function existValueInTable($table, $field, $where)
  725. {
  726. try {
  727. $sql = "SELECT " . $field . " " .
  728. "FROM " . $table . " " .
  729. "WHERE " . $where . "; ";
  730. $stmt = $this->connection->prepare($sql);
  731. $stmt->execute();
  732. $resp = $stmt->fetchAll();
  733. return $resp;
  734. } catch (\Throwable $e) {
  735. return null;
  736. }
  737. }
  738. /**
  739. * Funcion que verifica si existe un campo de una tabla.
  740. * @param string $table Contiene el nombre de la tabla.
  741. * @param string $field Contiene el nombre el campo.
  742. * @param string $type Contiene el typo de dato.
  743. * @return bool Retorna true si el campo existe.
  744. */
  745. public function existFieldType($table, $field, $type)
  746. {
  747. $existe = false;
  748. try {
  749. $base = $this->getDataBaseName();
  750. $sql = "SELECT ifnull(DATA_TYPE, '') as nombre " .
  751. "FROM information_schema.columns " .
  752. "WHERE TABLE_SCHEMA = '" . $base . "' AND " .
  753. " TABLE_NAME = '" . $table . "' AND " .
  754. " COLUMN_NAME = '" . $field . "' " .
  755. "LIMIT 1;";
  756. $stmt = $this->connection->prepare($sql);
  757. $stmt->execute();
  758. $resp = $stmt->fetchAll();
  759. foreach ($resp as $key => $value) {
  760. if (strtolower($value["nombre"]) === strtolower($type)) {
  761. $existe = true;
  762. break;
  763. }
  764. }
  765. return $existe;
  766. } catch (\Throwable $e) {
  767. return $existe;
  768. }
  769. }
  770. /**
  771. * Funcion que verifica si existe una tabla.
  772. * @param string $table Contiene el nombre de la tabla.
  773. * @return bool Retorna true si la tabla existe.
  774. */
  775. public function existTable($table)
  776. {
  777. $existe = false;
  778. try {
  779. $base = $this->getDataBaseName();
  780. $sql = "SELECT ifnull(TABLE_NAME, '') as nombre " .
  781. "FROM information_schema.columns " .
  782. "WHERE TABLE_SCHEMA = '" . $base . "' AND " .
  783. " TABLE_NAME = '" . $table . "' " .
  784. "LIMIT 1;";
  785. $stmt = $this->connection->prepare($sql);
  786. $stmt->execute();
  787. $resp = $stmt->fetchAll();
  788. foreach ($resp as $key => $value) {
  789. if (strtolower($value["nombre"]) === strtolower($table)) {
  790. $existe = true;
  791. break;
  792. }
  793. }
  794. return $existe;
  795. } catch (\Throwable $e) {
  796. return $existe;
  797. }
  798. }
  799. /**
  800. * Funcion que obtiene el nombre de la base de datos a la cual estoy conectado.
  801. * @return string Retorna el nombre de la base de datos o NULL en caso de error.
  802. */
  803. public function getDataBaseName()
  804. {
  805. $resp = null;
  806. try {
  807. $stmt = $this->connection->prepare("SELECT DATABASE() as base;");
  808. $stmt->execute();
  809. $resp = $stmt->fetchAll();
  810. foreach ($resp as $key => $value) {
  811. $resp = $value["base"];
  812. break;
  813. }
  814. return $resp;
  815. } catch (\Throwable $e) {
  816. return $resp;
  817. }
  818. }
  819. /**
  820. * Funcion que obtiene el valor del auto_increment.
  821. * @param string $table Contiene el nombre de la tabla.
  822. * @return array Retorna el array con los datos encontrados. O NULL en caso de error.
  823. */
  824. public function getAutoIncrementValue($table)
  825. {
  826. $autoIncrement = 1;
  827. try {
  828. $base = $this->getDataBaseName();
  829. $sql = "SELECT `AUTO_INCREMENT` " .
  830. "FROM INFORMATION_SCHEMA.TABLES " .
  831. "WHERE TABLE_SCHEMA = '" . $base . "' AND " .
  832. " TABLE_NAME = '" . $table . "';";
  833. $stmt = $this->connection->prepare($sql);
  834. $stmt->execute();
  835. $resp = $stmt->fetchAll();
  836. foreach ($resp as $key => $value) {
  837. if (isset($value["AUTO_INCREMENT"])) {
  838. $autoIncrement = $value["AUTO_INCREMENT"];
  839. }
  840. }
  841. } catch (\Throwable $e) {
  842. }
  843. return $autoIncrement;
  844. }
  845. /**
  846. * Funcion que setea el valor del auto_increment.
  847. * @param string $table Contiene el nombre de la tabla.
  848. * @param int $value Contiene el proximo numero autilizar.
  849. */
  850. public function setAutoIncrementValue($table, $value)
  851. {
  852. try {
  853. $base = $this->getDataBaseName();
  854. $stmt = $this->connection->prepare("ALTER TABLE " . $base . "." . $table . " AUTO_INCREMENT=" . $value . ";");
  855. $stmt->execute();
  856. } catch (\Throwable $e) {
  857. }
  858. }
  859. }