container = $container; return $this->container; } /** * @return ContainerInterface Retorna un objeto que implementa la interfaz "ContainerInterface". */ public function getContainer() { return $this->container; } /** * @return bool Retorna el valor de la variable showParameters. */ public function isShowParameters() { return $this->showParameters; } /** * @param bool $showParameters Si esta en TRUE muestra los parametros en las consultas. */ public function setShowParameters($showParameters) { $this->showParameters = $showParameters; } /** * @return int Retorna el numero de linea que estoy analizando. */ public function getLine() { return $this->line; } /** * @param int $line Setea el numero de linea. */ private function setLine($line) { $this->line = $line; } /** * Funcion que suma 1 a la variable line. */ private function sumLine() { $this->line = $this->line + 1; } /** * @return array Retorna un array con las lineas que produjeron errores. */ public function getErrorLineExecution() { return $this->errorLineExecution; } /** * @param array $errorLineExecution Setea un array con las lineas que produjeron errores. */ public function setErrorLineExecution($errorLineExecution) { $this->errorLineExecution = $errorLineExecution; } /** * Agrega una linea de error. * @param string $type Contiene el tipo de sentencia sql. * @param \Throwable $ex Contiene una excepcion. */ private function addErrorLineExecution($type, \Throwable $ex) { if (!array_key_exists($type, $this->errorLineExecution)) { $this->errorLineExecution[$type] = array(); } array_push($this->errorLineExecution[$type], "Line: " . $this->getLine() . " => [" . $ex->getCode() . "] = " . $ex->getMessage()); } /** * @return array Retorna una array con el valor de la ejecucion de cada linea. */ public function getLineExecution() { return $this->lineExecution; } /** * @param array $lineExecution Setea un array con las lineas de ejecucion. */ public function setLineExecution($lineExecution) { $this->lineExecution = $lineExecution; } /** * Agrega el valor de la ejecucion. * @param string $type Contiene el tipo de sentencia sql. * @param string $value Contiene el valor de la ejecucion. */ private function addLineExecution($type, $value) { if (!array_key_exists($type, $this->lineExecution)) { $this->lineExecution[$type] = array(); } array_push($this->lineExecution[$type], "Line: " . $this->getLine() . " => " . $value); } /** * Realiza un up de la modificaciones DDL. Siempre son agregados. * Para realizar sentencias DML utilizarlos metodos preUp y postUp. * @param Schema $schema Contiene el objeto esquema. */ public function up(Schema $schema) { } /** * Realiza un up de la modificaciones DDL. Siempre son eliminacion. * Para realizar sentencias DML utilizarlos metodos preDown y postDown. * @param Schema $schema Contiene el objeto esquema. */ public function down(Schema $schema) { } /** * Procesa un yaml para generar las sentencias DML que luego seran ejecutadas en la base de datos. * El directorio origen es DoctrineMigrations en adelante. * @param string $fileName Contiene el nombre del archivo a incorporar. */ protected function interpretYaml($fileName) { // obtengo el directorio de trabajo $dir = dirname(__DIR__) . "/DoctrineMigrations/"; // leo el yaml $value = $this->readYaml($dir, $fileName); if ($value != null && count($value) > 0) { // paso las key a mayusculas foreach ($value as $key => $val) { unset($value[$key]); $value[strtoupper($key)] = $val; } // reemplazo las keys que poseen importkey $value = $this->replaceImportsKey($dir, $value); // reemplazo los valores que poseen import $value = $this->replaceImportsValue($dir, $value); // lo hago de esta forma para que se ejecuten de acuerdo a como se escribe el yaml. //foreach ($value as $key => $val) { // $this->setLine(0); // if (strtoupper($key) === MigrationsBase::INSERT) { // $this->createInserts($value[MigrationsBase::INSERT]); // } else if (strtoupper($key) === MigrationsBase::UPDATE) { // $this->createUpdates($value[MigrationsBase::UPDATE]); // } else if (strtoupper($key) === MigrationsBase::DELETE) { // $this->createDeletes($value[MigrationsBase::DELETE]); // } //} if (array_key_exists(MigrationsBase::INSERT, $value)) { $this->setLine(0); $this->createInserts($value[MigrationsBase::INSERT]); } // creo los update if (array_key_exists(MigrationsBase::UPDATE, $value)) { $this->setLine(0); $this->createUpdates($value[MigrationsBase::UPDATE]); } // creo los delete if (array_key_exists(MigrationsBase::DELETE, $value)) { $this->setLine(0); $this->createDeletes($value[MigrationsBase::DELETE]); } } } /** * Crea los insert a partir de una estructura yaml. Se puede utilizar la palabra clave "ignore", "replace" o "orupdate". * El "replace" sobreescribe al "ignore" y el "orupdate" sobreescribe al "replace". * @param array $arrayInsert Contiene la estructura yaml para los insert. */ private function createInserts($arrayInsert) { foreach ($arrayInsert as $table => $inserts) { // recorro las tablas foreach ($inserts as $key => $valueKey) { // recorro cada uno de los insert que quiero hacer // almacena los campos $fields = ""; // almacena el valor de los campos $valuesFields = ""; // me dice si tengo que utilizar la palabra ignore $ignore = " "; // contiene la primer palabra de la sentencia (INSERT/REPLACE) $insert = "INSERT"; // me dice si es un insert or update $orUpdate = false; // contiene los valores del insert or update $orUpdateValues = ""; // contiene los valores para el bind del stament $arrayPrepare = array(); foreach ($valueKey as $field => $value) { // recorro los datos a insertar $field = strtolower(trim($field)); $value = trim($value); if (strlen($field) > 0 && strlen($value) > 0) { if ($field === 'ignore') { $value = strtolower($value); if ($value === '1' || $value === 'true') { if ($insert === 'INSERT') { $ignore = " IGNORE "; } } } else if ($field === 'replace') { $value = strtolower($value); if ($value === '1' || $value === 'true') { $insert = "REPLACE"; $ignore = " "; } } else if ($field === 'orupdate') { $value = strtolower($value); if ($value === '1' || $value === 'true') { $orUpdate = true; $ignore = " "; $insert = "INSERT"; } } else { $arrayPrepare[':' . $field] = $value; $fields = $fields . $field . ", "; $valuesFields = $valuesFields . ":" . $field . ", "; $orUpdateValues = $orUpdateValues . $field . " = " . ":" . $field . ", "; } } } if (strlen($fields) > 1) { $fields = substr($fields, 0, strlen($fields) - 2); } if (strlen($valuesFields) > 1) { $valuesFields = substr($valuesFields, 0, strlen($valuesFields) - 2); } if (strlen($orUpdateValues) > 1) { $orUpdateValues = substr($orUpdateValues, 0, strlen($orUpdateValues) - 2); } if (strlen($fields) > 1 && strlen($valuesFields) > 1) { $sql = $insert . $ignore . "INTO " . $table . " (" . $fields . ") VALUES (" . $valuesFields . ")"; if ($orUpdate) { $sql .= " ON DUPLICATE KEY UPDATE " . $orUpdateValues . ";"; } else { $sql .= ";"; } $this->executeSQL($sql, MigrationsBase::INSERT, $arrayPrepare); } } } } /** * Crea los update a partir de una estructura yaml. * @param array $arrayInsert Contiene la estructura yaml para los insert. */ private function createUpdates($arrayInsert) { foreach ($arrayInsert as $table => $inserts) { // recorro las tablas foreach ($inserts as $key => $valueKey) { // recorro cada uno de los insert que quiero hacer $set = ""; $where = ""; // contiene los valores para el bind del stament $arrayPrepare = array(); foreach ($valueKey as $field => $value) { // recorro los datos a realizar un update if (strlen(trim($field)) > 0 && strlen(trim($value)) > 0) { if ($field === "where") { $where = $value; } else { $arrayPrepare[':' . $field] = $value; $set = $set . $field . " = :" . $field . ", "; } } } if (strlen($set) > 1) { $set = substr($set, 0, strlen($set) - 2); } if (strlen($set) > 1) { $sql = "UPDATE " . $table . " SET " . $set . " WHERE " . $where . ";"; $this->executeSQL($sql, MigrationsBase::UPDATE, $arrayPrepare); } } } } /** * Crea los delete a partir de una estructura yaml. * @param array $arrayInsert Contiene la estructura yaml para los insert. */ private function createDeletes($arrayInsert) { foreach ($arrayInsert as $table => $inserts) { // recorro las tablas foreach ($inserts as $key => $valueKey) { // recorro cada uno de los insert que quiero hacer $where = ""; foreach ($valueKey as $field => $value) { // recorro los datos a realizar un update if (strlen(trim($field)) > 0 && strlen(trim($value)) > 0) { if ($field === "where") { $where = $value; } } } $sql = "DELETE FROM " . $table . " WHERE " . $where . ";"; $this->executeSQL($sql, MigrationsBase::DELETE); } } } /** * Obtiene el contenido de un archivo yaml. * @param string $dir Contiene el directorio de trabajo. Por defecto "DoctrineMigrations". * @param string $archivo Contiene el nombre del archivo a incorporar. * @return bool|string Retorna el contenido del archivo. */ private function readYaml($dir, $archivo) { return Yaml::parse(file_get_contents($dir . $archivo)); } /** * Obtiene el contenido de un archivo. * @param string $dir Contiene el directorio de trabajo. Por defecto "DoctrineMigrations". * @param string $archivo Contiene el nombre del archivo a incorporar. * @return bool|string Retorna el contenido del archivo. */ private function readImportInValues($dir, $archivo) { return file_get_contents($dir . $archivo); } /** * Reemplaza el contenido de los imports dentro de los values. * @param string $dir Contiene el directorio de trabajo. Por defecto "DoctrineMigrations". * @param array $valores Contiene el array el contenido del yaml. * @return array Retorna el array con los valores cambiados. */ private function replaceImportsValue($dir, $valores) { try { foreach ($valores as $key => $value) { if (is_array($value)) { if (count($value) == 1 && array_key_exists("import", $value)) { if (file_exists($dir . $value["import"])) { $valores[$key] = $this->readImportInValues($dir, $value["import"]); } else { $valores[$key] = "FILE NOT FOUND"; } } else { $valores[$key] = $this->replaceImportsValue($dir, $value); } } } } catch (\Symfony\Component\Debug\Exception\ContextErrorException $e) { var_dump($e); } return $valores; } /** * Reemplaza el contenido de los imports dentro de las key. * @param string $dir Contiene el directorio de trabajo. Por defecto "DoctrineMigrations". * @param array $valores Contiene el array el contenido del yaml. * @return array Retorna el array con los valores cambiados. */ private function replaceImportsKey($dir, $valores) { try { foreach ($valores as $key => $value) { if (is_array($value)) { $valores[$key] = $this->replaceImportsKey($dir, $value); } else { if (trim($key) === "importkey") { if (file_exists($dir . $value)) { $valores = $this->readYaml($dir, $value); } else { $valores[$key] = "FILE NOT FOUND"; } } } } } catch (\Symfony\Component\Debug\Exception\ContextErrorException $e) { var_dump($e); } return $valores; } /** * Funcion ejecuta el YAML en la base de datos dentro de una transaccion. * @param string $file Contiene el nombre de archivo a procesar. */ protected function executeYaml($file) { $this->connection->beginTransaction(); try { $this->interpretYaml($file); if (count($this->getErrorLineExecution()) > 0 ) { //se produjeron errores $this->connection->rollBack(); echo "Se produjeron errores."; } else { $this->connection->commit(); echo "Migracion correcta."; } } catch (\Throwable $e) { $this->connection->rollBack(); echo "Se produjeron errores."; } } /** * Funcion que ejecuta una sentencia sql. * @param string $sql Contiene el sql a ejecutar. * @param string $type Contiene el tipo de sentencia. * @param array $arrayPrepare Contiene un array con los valores. La key contiene el valor a * buscar en la sentencia sql y el value es el valor. */ private function executeSQL($sql, $type, $arrayPrepare = null) { $stmt = $this->connection->prepare($sql); $param = ""; if ($arrayPrepare != null && count($arrayPrepare) > 0) { foreach ($arrayPrepare as $keyPrepare => $valuePrepare) { $stmt->bindValue($keyPrepare, $valuePrepare); if ($this->isShowParameters()) { $param .= " [" . $keyPrepare . "]=" . $valuePrepare . " "; } } } if ($this->isShowParameters()) { if (strlen($param) > 4) { $param = " Parameters: " . substr($param, 0, strlen($param) - 4); } } try { $resp = $stmt->execute(); $this->addLineExecution($type, ($resp ? "OK - " : "ERROR - ") . $sql . $param); } catch (\Throwable $ex) { $this->addLineExecution($type, "????? - " . $sql . $param); $this->addErrorLineExecution($type, $ex); } $this->sumLine(); } /** * Borra la migracion de la tabla de migraciones. * @param string $obj Contiene el objeto this. */ protected function deleteMigrationsVersion($obj) { $arr = explode("\\", get_class($obj)); $this->connection->beginTransaction(); $stmt = $this->connection->prepare("DELETE FROM migration_versions WHERE migration_versions.version = '" . str_ireplace("version", "", $arr[count($arr) - 1]) . "'"); $stmt->execute(); $this->connection->commit(); } /** * Funcion que muestra por pantalla el resultado de la ejecucion y de los errores. */ protected function showResult() { if (count($this->getLineExecution()) > 0) { echo "-----------------------------------------------\n"; echo " EJECUCIONES\n"; echo "-----------------------------------------------\n"; foreach ($this->getLineExecution() as $key => $value) { echo $key . "\n"; foreach ($this->getLineExecution()[$key] as $k => $v) { echo "\t" . $v . "\n"; } } } if (count($this->getErrorLineExecution()) > 0) { echo "-----------------------------------------------\n"; echo " ERRORES\n"; echo "-----------------------------------------------\n"; foreach ($this->getErrorLineExecution() as $key => $value) { echo $key . "\n"; foreach ($this->getErrorLineExecution()[$key] as $k => $v) { echo "\t" . $v . "\n"; } } } } //----------------------------------------------------------------------------------------------- // EJEMPLOS DE COMO PUEDO REALIZAR CONSULTAR A LA BASE DE DATOS. // SE ACONSEJA HACERLO EN LOS preUp/preDown/postUp/preDown //----------------------------------------------------------------------------------------------- /** * Ejemplo de como hacer un select utilizando entidades. */ private function selectEntityManager() { $em = $this->container->get('doctrine.orm.entity_manager'); $users = $em->getRepository("BaseUserBundle:User")->findBy(array('enabled' => 1)); var_dump($users); } /** * Ejemplo de como realizar una consulta a la base de datos a travez de la conexion. */ private function selectConexion() { $users = $this->connection->executeQuery("SELECT * FROM user"); var_dump($users); } }