PageRenderTime 42ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/library/Fisma/Cli/Doctrine.php

https://bitbucket.org/openfisma-ondemand/openfisma
PHP | 260 lines | 149 code | 33 blank | 78 comment | 40 complexity | fa8e3fd78ce6b603085d446eb72d28cb MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-2.1, GPL-3.0, Apache-2.0, EPL-1.0
  1. <?php
  2. /**
  3. * Copyright (c) 2011 Endeavor Systems, Inc.
  4. *
  5. * This file is part of OpenFISMA.
  6. *
  7. * OpenFISMA is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
  8. * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later
  9. * version.
  10. *
  11. * OpenFISMA is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
  12. * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  13. * details.
  14. *
  15. * You should have received a copy of the GNU General Public License along with OpenFISMA. If not, see
  16. * {@link http://www.gnu.org/licenses/}.
  17. */
  18. /**
  19. * Doctrine cli tasks dispatcher
  20. *
  21. * @author Mark E. Haase
  22. * @copyright (c) Endeavor Systems, Inc. 2011 {@link http://www.endeavorsystems.com}
  23. * @license http://www.openfisma.org/content/license GPLv3
  24. * @package Fisma
  25. * @subpackage Fisma_Cli
  26. */
  27. class Fisma_Cli_Doctrine extends Fisma_Cli_Abstract
  28. {
  29. /**
  30. * List of doctrine tasks
  31. *
  32. * @var array
  33. */
  34. private $_doctrineTasks = array(
  35. 'build' => 'build-all-load',
  36. 'rebuild' => 'build-all-reload',
  37. 'models' => 'generate-models-yaml',
  38. 'dql' => 'dql'
  39. );
  40. /**
  41. * Configure the arguments accepted for this CLI program
  42. *
  43. * @return array An array containing getopt long syntax
  44. */
  45. public function getArgumentsDefinitions()
  46. {
  47. return array(
  48. 'auto-yes|y' => "Automatically pick 'yes' for yes/no questions",
  49. 'auto-no|n' => "Automatically pick 'no' for yes/no questions",
  50. 'build|b' => "Create models, create tables, and load fixtures",
  51. 'rebuild|r' => "Drop existing tables (if they exist), then do --build",
  52. 'models|m' => "Create models (a different name for what we currently call generate-models-yaml)",
  53. 'sample-data|s' => "When building (or rebuilding) include sample data. Does not apply when not building",
  54. 'dql|q=s' => "Execute dql query and display the results",
  55. );
  56. }
  57. /**
  58. * Run the task with the passed arguments
  59. */
  60. protected function _run()
  61. {
  62. // Default doctrine script name
  63. $arguments[0] = 'doctrine.php';
  64. // The default doctrine cli task is the first argument
  65. $arguments[1] = $this->_getAvailableDoctrineTaskFromArguments();
  66. $dqlParameter = $this->getOption('dql');
  67. if ($dqlParameter) {
  68. array_push($arguments, $dqlParameter);
  69. }
  70. // Make sure that user does not use both arguments auto-yes and auto-no at the same time
  71. $autoYes = $this->getOption('auto-yes');
  72. $autoNo = $this->getOption('auto-no');
  73. if ($autoYes === true && $autoNo === true) {
  74. throw new Fisma_Zend_Exception_User("Cannot use auto-yes and auto-no at the same time!");
  75. } else if ($autoYes === true) {
  76. array_push($arguments, 'auto-yes');
  77. } else if ($autoNo === true) {
  78. array_push($arguments, 'auto-no');
  79. }
  80. Fisma::setNotificationEnabled(false);
  81. Fisma::setListenerEnabled(false);
  82. // Make sure the mysql supports InnoDB
  83. if (!Fisma_Cli_Abstract::checkInnoDb()) {
  84. throw new Fisma_Zend_Exception_User(
  85. 'The current Mysql server does not support InnoDB engine. InnoDB is required for OpenFisma!'
  86. );
  87. }
  88. /** @todo temporary hack to load large datasets */
  89. ini_set('memory_limit', '512M');
  90. // The CLI needs an in-memory configuration object, since it might drop and/or reload the configuration table
  91. $inMemoryConfig = new Fisma_Configuration_Array();
  92. $inMemoryConfig->setConfig('hash_type', 'sha1');
  93. Fisma::setConfiguration($inMemoryConfig, true);
  94. $configuration = Zend_Registry::get('doctrine_config');
  95. // Check to see if sample data was requested, e.g. `doctrine.php -r sample-data`
  96. if ($this->getOption('sample-data')) {
  97. $sampleDataBuildPath = Fisma::getPath('sampleDataBuild');
  98. $this->loadFixtureFilesWithSampleData($sampleDataBuildPath);
  99. // Point Doctrine data loader at the new directory
  100. $configuration['data_fixtures_path'] = $sampleDataBuildPath;
  101. }
  102. // Kick off the CLI
  103. $cli = new Fisma_Doctrine_Cli($configuration);
  104. $cli->run($arguments);
  105. // Remove sample data build directory if it exists
  106. if (isset($sampleDataBuildPath) && is_dir($sampleDataBuildPath)) {
  107. $this->getLog()->info("Removing Sample Data build directory");
  108. Fisma_FileSystem::recursiveDelete($sampleDataBuildPath);
  109. }
  110. }
  111. /**
  112. * Copy fixture YAML files to sample build directory, combine fixture files with sample data
  113. *
  114. * @param string $sampleDataBuildPath
  115. * @return void
  116. */
  117. protected function loadFixtureFilesWithSampleData($sampleDataBuildPath)
  118. {
  119. $this->getLog()->info("Using Sample Data");
  120. // If build directory already exists (e.g. from a failed prior run), then try removing it
  121. $sampleDataBuildPath = Fisma::getPath('sampleDataBuild');
  122. if (is_dir($sampleDataBuildPath)) {
  123. $result = Fisma_FileSystem::recursiveDelete($sampleDataBuildPath);
  124. if (!$result) {
  125. throw new Fisma_Zend_Exception_User("Could not remove directory for sample data build. Maybe it has"
  126. . " bad permissions? ($sampleDataBuildPath)");
  127. }
  128. }
  129. // Create a build directory
  130. if (!mkdir($sampleDataBuildPath)) {
  131. throw new Fisma_Zend_Exception_User('Could not create directory for sample data build. Maybe it has bad'
  132. . " permissions? ($sampleDataBuildPath)");
  133. }
  134. // Copy files from fixtures into build directory
  135. $fixturePath = Fisma::getPath('fixture');
  136. $fixtureDir = opendir($fixturePath);
  137. while ($fixtureFile = readdir($fixtureDir)) {
  138. // Skip hidden files
  139. if ('.' == $fixtureFile{0}) {
  140. continue;
  141. }
  142. $source = "$fixturePath/$fixtureFile";
  143. $target = "$sampleDataBuildPath/$fixtureFile";
  144. if (!copy($source, $target)) {
  145. throw new Fisma_Zend_Exception_User("Could not copy '$source' to '$target'");
  146. }
  147. }
  148. $this->combineFixtureFilesWithSampleData($sampleDataBuildPath);
  149. }
  150. /**
  151. * Combine fixture files with sample data or merge them
  152. *
  153. * @param string $sampleDataBuildPath
  154. * @return void
  155. */
  156. protected function combineFixtureFilesWithSampleData($sampleDataBuildPath)
  157. {
  158. // Copy files from sample data into build directory. If a fixture already exists, then we need to merge the
  159. // YAML files together.
  160. $samplePath = Fisma::getPath('sampleData');
  161. $sampleDir = opendir($samplePath);
  162. while ($sampleFile = readdir($sampleDir)) {
  163. // Skip hidden files
  164. if ('.' == $sampleFile{0}) {
  165. continue;
  166. }
  167. $source = "$samplePath/$sampleFile";
  168. $target = "$sampleDataBuildPath/$sampleFile";
  169. // When combining fixture files with sample data, we need to strip the YAML
  170. // header off of the sample data file
  171. $stripYamlHeader = file_exists($target);
  172. // If the target file does already exist, then we need to merge the YAML files.
  173. $sourceHandle = fopen($source, 'r');
  174. $targetHandle = fopen($target, 'a');
  175. while ($buffer = fgets($sourceHandle)) {
  176. if (!$stripYamlHeader) {
  177. if (strpos($buffer, '##') !== FALSE) {
  178. $matches = array();
  179. if (preg_match("/##\s*CURDATE(-|\+)(\d+)\s*##/", $buffer, $matches)) {
  180. $today = Zend_Date::now();
  181. if ('+' == $matches[1]) {
  182. $today->addDay($matches[2]);
  183. } elseif ('-' == $matches[1]) {
  184. $today->subDay($matches[2]);
  185. }
  186. $dateString = "'" . $today->toString('YYYY-MM-dd HH:mm:ss') . "'";
  187. $buffer = preg_replace('/##\s*CURDATE.*##/', $dateString, $buffer);
  188. }
  189. }
  190. fwrite($targetHandle, $buffer);
  191. } else {
  192. // Look for the first YAML tag in the document and remove it. Then set the $write flag to true
  193. // so that we can stop looking for the tag.
  194. if (preg_match('/[^#]\w+:.*\R/', $buffer, $a)) {
  195. $buffer = preg_replace('/[^#]\w+:.*(?>\r\n|\n|\x0b|\f|\r|\x85)/', '', $buffer, 1);
  196. fwrite($targetHandle, $buffer);
  197. $stripYamlHeader = false;
  198. }
  199. }
  200. }
  201. }
  202. }
  203. /**
  204. * Get the task name from arguments. Throw exception if there is no or more than one options
  205. *
  206. * @return string $taskName The doctrine task
  207. * @throws Fisma_Zend_Exception_User
  208. */
  209. private function _getAvailableDoctrineTaskFromArguments()
  210. {
  211. $taskCount = 0;
  212. $taskName = null;
  213. foreach ($this->_doctrineTasks as $key => $task) {
  214. if ($this->getOption($key)) {
  215. $taskName = $task;
  216. $taskCount++;
  217. }
  218. }
  219. if ($taskCount == 0) {
  220. throw new Fisma_Zend_Exception_User("An option is required.");
  221. } else if ($taskCount > 1) {
  222. throw new Fisma_Zend_Exception_User("Cannot use more than one option.");
  223. } else {
  224. return $taskName;
  225. }
  226. }
  227. }