Changeset 19273
- Timestamp:
- 06/15/09 14:47:22 (9 months ago)
- Files:
-
- branches/1.3/WHATS_NEW (modified) (2 diffs)
- branches/1.3/lib/autoload/sfCoreAutoload.class.php (modified) (2 diffs)
- branches/1.3/lib/plugin/sfSymfonyPluginManager.class.php (modified) (3 diffs)
- branches/1.3/lib/plugins/sfDoctrinePlugin/config/installer.php (modified) (1 diff)
- branches/1.3/lib/plugins/sfPropelPlugin/config/installer.php (modified) (1 diff)
- branches/1.3/lib/task/generator/sfGenerateProjectTask.class.php (modified) (3 diffs)
- branches/1.3/lib/task/generator/skeleton/project/config/ProjectConfiguration.class.php (modified) (1 diff)
- branches/1.3/lib/task/plugin/sfPluginBaseTask.class.php (modified) (1 diff)
- branches/1.3/lib/task/sfBaseTask.class.php (modified) (2 diffs)
- branches/1.3/lib/task/sfCommandApplicationTask.class.php (modified) (1 diff)
- branches/1.3/lib/util/sfClassManipulator.class.php (added)
- branches/1.3/test/unit/util/sfClassManipulatorTest.php (added)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
branches/1.3/WHATS_NEW
r19214 r19273 261 261 $ php /path/to/symfony generate:project foo --orm=Propel 262 262 263 If you don't want to use Propel or Doctrine, you can pass `none` to the 264 `--orm` option: 265 266 $ php /path/to/symfony generate:project foo --orm=none 267 263 268 The new `--installer` option allows you to pass a PHP script that can further 264 269 customize the newly created project. The script is executed in the context of 265 270 the task, and so can use any of its methods. The more useful ones are the 266 271 following: `installDir()`, `runTask()`, `ask()`, `askConfirmation()`, 267 `askAndValidate()`, and `reloadTasks()`.272 `askAndValidate()`, `reloadTasks()`, `enablePlugin()`, and `disablePlugin()`. 268 273 269 274 More information can be found in this … … 357 362 `sfCultureInfo->sortArray()` can be used for that. 358 363 364 Plugins 365 ------- 366 367 Before symfony 1.3, all plugins were enabled by default, except for the 368 `sfDoctrinePlugin` and the `sfCompat10Plugin` ones: 369 370 [php] 371 class ProjectConfiguration extends sfProjectConfiguration 372 { 373 public function setup() 374 { 375 // for compatibility / remove and enable only the plugins you want 376 $this->enableAllPluginsExcept(array('sfDoctrinePlugin', 'sfCompat10Plugin')); 377 } 378 } 379 380 For freshly created projects with symfony 1.3, plugins must be explicitly 381 enabled in the `ProjectConfiguration` class to be able to use them: 382 383 [php] 384 class ProjectConfiguration extends sfProjectConfiguration 385 { 386 public function setup() 387 { 388 $this->enablePlugins('sfDoctrinePlugin'); 389 } 390 } 391 392 The `plugin:install` task automatically enables the plugin(s) it installs (and 393 `plugin:uninstall` disable them). If you install a plugin via Subversion, you 394 still need to enable it by hand. 395 396 If you want to use a core-plugin, like `sfProtoculousPlugin` or 397 `sfCompat10Plugin`, you just need to add the corresponding `enablePlugins()` 398 statement in the `ProjectConfiguration` class. 399 400 >**NOTE** 401 >If you upgrade a project from 1.2, the old behavior will still be 402 >active as the upgrade task does not change the `ProjectConfiguration` 403 >file. The behavior change is only for new symfony 1.3 projects. branches/1.3/lib/autoload/sfCoreAutoload.class.php
r18331 r19273 377 377 'sfcachecleartask' => 'task/cache/sfCacheClearTask.class.php', 378 378 'sfconfigureauthortask' => 'task/configure/sfConfigureAuthorTask.class.php', 379 'sfconfiguredatabasetask' => 'task/configure/sfConfigureDatabaseTask.class.php',380 379 'sfgenerateapptask' => 'task/generator/sfGenerateAppTask.class.php', 381 380 'sfgeneratemoduletask' => 'task/generator/sfGenerateModuleTask.class.php', … … 429 428 'sfbrowserbase' => 'util/sfBrowserBase.class.php', 430 429 'sfcallable' => 'util/sfCallable.class.php', 430 'sfclassmanipulator' => 'util/sfClassManipulator.class.php', 431 431 'sfcontext' => 'util/sfContext.class.php', 432 432 'sfdomcssselector' => 'util/sfDomCssSelector.class.php', branches/1.3/lib/plugin/sfSymfonyPluginManager.class.php
r12847 r19273 56 56 57 57 // register callbacks to manage web content 58 $this->dispatcher->connect('plugin.post_install', array($this, 'ListenToPluginPostInstall')); 59 $this->dispatcher->connect('plugin.pre_uninstall', array($this, 'ListenToPluginPostUninstall')); 58 $this->dispatcher->connect('plugin.post_install', array($this, 'listenToPluginPostInstall')); 59 $this->dispatcher->connect('plugin.pre_uninstall', array($this, 'listenToPluginPostUninstall')); 60 $this->dispatcher->connect('plugin.post_uninstall', array($this, 'listenToPluginPostUnintall')); 60 61 } 61 62 … … 104 105 105 106 /** 107 * Enables a plugin in the ProjectConfiguration class. 108 * 109 * @param string $plugin The name of the plugin 110 */ 111 public function enablePlugin($plugin) 112 { 113 if (!$this->environment->getOption('config_dir')) 114 { 115 throw new sfPluginException('You must provide a "config_dir" option.'); 116 } 117 118 $manipulator = sfClassManipulator::fromFile($this->environment->getOption('config_dir').'/ProjectConfiguration.class.php'); 119 $manipulator->wrapMethod('setup', '', sprintf('$this->enablePlugins(\'%s\');', $plugin)); 120 $manipulator->save(); 121 } 122 123 /** 124 * Disables a plugin in the ProjectConfiguration class. 125 * 126 * @param string $plugin The name of the plugin 127 */ 128 protected function disablePlugin($plugin) 129 { 130 if (!$this->environment->getOption('config_dir')) 131 { 132 throw new sfPluginException('You must provide a "config_dir" option.'); 133 } 134 135 $file = $this->environment->getOption('config_dir').'/ProjectConfiguration.class.php'; 136 $source = file_get_contents($file); 137 138 $source = preg_replace(sprintf('# *\$this\->enablePlugins\(array\(([^\)]+), *\'%s\'([^\)]*)\)\)#', $plugin), '$this->enablePlugins(array($1$2))', $source); 139 $source = preg_replace(sprintf('# *\$this\->enablePlugins\(array\(\'%s\', *([^\)]*)\)\)#', $plugin), '$this->enablePlugins(array($1))', $source); 140 $source = preg_replace(sprintf('# *\$this\->enablePlugins\(\'%s\'\); *\n?#', $plugin), '', $source); 141 $source = preg_replace(sprintf('# *\$this\->enablePlugins\(array\(\'%s\'\)\); *\n?#', $plugin), '', $source); 142 $source = preg_replace(sprintf('# *\$this\->enablePlugins\(array\(\)\); *\n?#', $plugin), '', $source); 143 144 file_put_contents($file, $source); 145 } 146 147 /** 106 148 * Listens to the plugin.post_install event. 107 149 * 108 150 * @param sfEvent $event An sfEvent instance 109 151 */ 110 public function ListenToPluginPostInstall($event) 111 { 112 $this->installWebContent($event['plugin'], 113 isset($event['plugin_dir']) ? $event['plugin_dir'] : $this->environment->getOption('plugin_dir')); 152 public function listenToPluginPostInstall($event) 153 { 154 $this->installWebContent($event['plugin'], isset($event['plugin_dir']) ? $event['plugin_dir'] : $this->environment->getOption('plugin_dir')); 155 156 $this->enablePlugin($event['plugin']); 114 157 } 115 158 … … 119 162 * @param sfEvent $event An sfEvent instance 120 163 */ 121 public function ListenToPluginPostUninstall($event)164 public function listenToPluginPostUninstall($event) 122 165 { 123 166 $this->uninstallWebContent($event['plugin']); 167 } 168 169 public function listenToPluginPostUnintall(sfEvent $event) 170 { 171 $this->disablePlugin($event['plugin']); 124 172 } 125 173 branches/1.3/lib/plugins/sfDoctrinePlugin/config/installer.php
r19116 r19273 2 2 3 3 $this->installDir(dirname(__FILE__).'/skeleton'); 4 $this->enablePlugin('sfDoctrinePlugin'); 5 $this->reloadTasks(); branches/1.3/lib/plugins/sfPropelPlugin/config/installer.php
r19116 r19273 2 2 3 3 $this->installDir(dirname(__FILE__).'/skeleton'); 4 $this->enablePlugin('sfPropelPlugin'); 5 $this->reloadTasks(); branches/1.3/lib/task/generator/sfGenerateProjectTask.class.php
r19215 r19273 65 65 [./symfony generate:project blog --orm=Propel|INFO] 66 66 67 If you don't want to use an ORM, pass [none|INFO] to [--orm|INFO] option: 68 69 [./symfony generate:project blog --orm=none|INFO] 70 67 71 You can also pass the [--installer|INFO] option to further customize the 68 72 project: … … 82 86 } 83 87 84 // create basic project structure 85 $this->installDir(dirname(__FILE__).'/skeleton/project'); 86 87 // execute the choosen ORM installer script 88 include dirname(__FILE__).'/../../plugins/sf'.ucfirst(strtolower($options['orm'])).'Plugin/config/installer.php'; 88 if (!in_array($options['orm'], array('Propel', 'Doctrine', 'none'), false)) 89 { 90 throw new InvalidArgumentException(sprintf('Invalid ORM name "%s".', $options['orm'])); 91 } 89 92 90 93 $this->arguments = $arguments; 91 94 $this->options = $options; 92 95 96 // create basic project structure 97 $this->installDir(dirname(__FILE__).'/skeleton/project'); 98 99 // update ProjectConfiguration class (use a relative path when the symfony core is nested within the project) 100 $symfonyCoreAutoload = 0 === strpos(sfConfig::get('sf_symfony_lib_dir'), sfConfig::get('sf_root_dir')) ? 101 sprintf('dirname(__FILE__).\'/..%s/autoload/sfCoreAutoload.class.php\'', str_replace(sfConfig::get('sf_root_dir'), '', sfConfig::get('sf_symfony_lib_dir'))) : 102 var_export(sfConfig::get('sf_symfony_lib_dir').'/autoload/sfCoreAutoload.class.php', true); 103 104 $this->replaceTokens(array(sfConfig::get('sf_config_dir')), array('SYMFONY_CORE_AUTOLOAD' => $symfonyCoreAutoload)); 105 106 $this->tokens = array( 107 'ORM' => $this->options['orm'], 108 'PROJECT_NAME' => $this->arguments['name'], 109 'PROJECT_DIR' => sfConfig::get('sf_root_dir'), 110 ); 111 93 112 $this->replaceTokens(); 113 114 // execute the choosen ORM installer script 115 if ('none' !== $options['orm']) 116 { 117 include dirname(__FILE__).'/../../plugins/sf'.ucfirst(strtolower($options['orm'])).'Plugin/config/installer.php'; 118 } 94 119 95 120 // execute a custom installer … … 108 133 $this->replaceTokens(); 109 134 } 110 111 /**112 * Executes another task in the context of the current one.113 *114 * @param string $name The name of the task to execute115 * @param array $arguments An array of arguments to pass to the task116 * @param array $options An array of options to pass to the task117 *118 * @return Boolean The returned value of the task run() method119 */120 protected function runTask($name, $arguments = array(), $options = array())121 {122 if (is_null($this->commandApplication))123 {124 throw new LogicException('No command application associated with this task yet.');125 }126 127 $task = $this->commandApplication->getTaskToExecute($name);128 $task->setCommandApplication($this->commandApplication);129 130 return $task->run($arguments, $options);131 }132 133 /**134 * Mirrors a directory structure inside the created project.135 *136 * @param string $dir The directory to mirror137 * @param sfFinder $finder A sfFinder instance to use for the mirroring138 */139 protected function installDir($dir, $finder = null)140 {141 if (is_null($finder))142 {143 $finder = sfFinder::type('any')->discard('.sf');144 }145 146 $this->getFilesystem()->mirror($dir, sfConfig::get('sf_root_dir'), $finder);147 }148 149 /**150 * Replaces tokens in files contained in a given directory.151 *152 * If you don't pass a directory, it will replace in the config/ and lib/ directory.153 *154 * @param array $dirs An array of directory where to do the replacement155 * @param array $tokens An array of tokens to use156 */157 protected function replaceTokens($dirs = array(), $tokens = array())158 {159 if (!$dirs)160 {161 $dirs = array(sfConfig::get('sf_config_dir'), sfConfig::get('sf_lib_dir'));162 }163 164 // update ProjectConfiguration class (use a relative path when the symfony core is nested within the project)165 $symfonyCoreAutoload = 0 === strpos(sfConfig::get('sf_symfony_lib_dir'), sfConfig::get('sf_root_dir')) ?166 sprintf('dirname(__FILE__).\'/..%s/autoload/sfCoreAutoload.class.php\'', str_replace(sfConfig::get('sf_root_dir'), '', sfConfig::get('sf_symfony_lib_dir'))) :167 var_export(sfConfig::get('sf_symfony_lib_dir').'/autoload/sfCoreAutoload.class.php', true);168 169 $tokens = array_merge(array(170 'ORM' => $this->options['orm'],171 'OTHER_ORM' => 'Doctrine' == $this->options['orm'] ? 'Propel' : 'Doctrine',172 'PROJECT_NAME' => $this->arguments['name'],173 'PROJECT_DIR' => sfConfig::get('sf_root_dir'),174 'SYMFONY_CORE_AUTOLOAD' => $symfonyCoreAutoload,175 ), $tokens);176 177 $this->getFilesystem()->replaceTokens(sfFinder::type('file')->prune('vendor')->in($dirs), '##', '##', $tokens);178 }179 180 /**181 * Reloads tasks.182 *183 * Useful when you install plugins with tasks and if you want to use them with the runTask() method.184 */185 protected function reloadTasks()186 {187 $this->configuration = $this->createConfiguration(null, null);188 189 $this->commandApplication->clearTasks();190 $this->commandApplication->loadTasks($this->configuration);191 192 $tasks = array();193 foreach (get_declared_classes() as $class)194 {195 $r = new Reflectionclass($class);196 if ($r->isSubclassOf('sfTask') && !$r->isAbstract() && false === strpos($class, 'Doctrine' == $this->options['orm'] ? 'Propel' : 'Doctrine'))197 {198 $tasks[] = new $class($this->dispatcher, $this->formatter);199 }200 }201 202 $this->commandApplication->registerTasks($tasks);203 }204 135 } branches/1.3/lib/task/generator/skeleton/project/config/ProjectConfiguration.class.php
r19116 r19273 8 8 public function setup() 9 9 { 10 // for compatibility / remove and enable only the plugins you want11 $this->enableAllPluginsExcept(array('sf##OTHER_ORM##Plugin', 'sfCompat10Plugin'));12 10 } 13 11 } branches/1.3/lib/task/plugin/sfPluginBaseTask.class.php
r6931 r19273 19 19 abstract class sfPluginBaseTask extends sfBaseTask 20 20 { 21 private22 $pluginManager = null;23 24 public function getPluginManager()25 {26 if (is_null($this->pluginManager))27 {28 $environment = new sfPearEnvironment($this->dispatcher, array(29 'plugin_dir' => sfConfig::get('sf_plugins_dir'),30 'cache_dir' => sfConfig::get('sf_cache_dir').'/.pear',31 'web_dir' => sfConfig::get('sf_web_dir'),32 ));33 34 $this->pluginManager = new sfSymfonyPluginManager($this->dispatcher, $environment);35 }36 37 return $this->pluginManager;38 }39 21 } branches/1.3/lib/task/sfBaseTask.class.php
r16171 r19273 20 20 { 21 21 protected 22 $configuration = null; 22 $configuration = null, 23 $pluginManager = null; 23 24 24 25 /** … … 205 206 sfSimpleAutoload::getInstance(sfConfig::get('sf_cache_dir').'/project_autoload.cache')->reload(); 206 207 } 208 209 /** 210 * Mirrors a directory structure inside the created project. 211 * 212 * @param string $dir The directory to mirror 213 * @param sfFinder $finder A sfFinder instance to use for the mirroring 214 */ 215 protected function installDir($dir, $finder = null) 216 { 217 if (is_null($finder)) 218 { 219 $finder = sfFinder::type('any')->discard('.sf'); 220 } 221 222 $this->getFilesystem()->mirror($dir, sfConfig::get('sf_root_dir'), $finder); 223 } 224 225 /** 226 * Replaces tokens in files contained in a given directory. 227 * 228 * If you don't pass a directory, it will replace in the config/ and lib/ directory. 229 * 230 * You can define global tokens by defining the $this->tokens property. 231 * 232 * @param array $dirs An array of directory where to do the replacement 233 * @param array $tokens An array of tokens to use 234 */ 235 protected function replaceTokens($dirs = array(), $tokens = array()) 236 { 237 if (!$dirs) 238 { 239 $dirs = array(sfConfig::get('sf_config_dir'), sfConfig::get('sf_lib_dir')); 240 } 241 242 $tokens = array_merge(isset($this->tokens) ? $this->tokens : array(), $tokens); 243 244 $this->getFilesystem()->replaceTokens(sfFinder::type('file')->prune('vendor')->in($dirs), '##', '##', $tokens); 245 } 246 247 /** 248 * Reloads tasks. 249 * 250 * Useful when you install plugins with tasks and if you want to use them with the runTask() method. 251 */ 252 protected function reloadTasks() 253 { 254 if (is_null($this->commandApplication)) 255 { 256 return; 257 } 258 259 $this->configuration = $this->createConfiguration(null, null); 260 261 $this->commandApplication->clearTasks(); 262 $this->commandApplication->loadTasks($this->configuration); 263 264 $disabledPluginsRegex = sprintf('#^(%s)#', implode('|', array_diff($this->configuration->getAllPluginPaths(), $this->configuration->getPluginPaths()))); 265 $tasks = array(); 266 foreach (get_declared_classes() as $class) 267 { 268 $r = new Reflectionclass($class); 269 if ($r->isSubclassOf('sfTask') && !$r->isAbstract() && !preg_match($disabledPluginsRegex, $r->getFileName())) 270 { 271 $tasks[] = new $class($this->dispatcher, $this->formatter); 272 } 273 } 274 275 $this->commandApplication->registerTasks($tasks); 276 } 277 278 /** 279 * Enables a plugin in the ProjectConfiguration class. 280 * 281 * @param string $plugin The name of the plugin 282 */ 283 protected function enablePlugin($plugin) 284 { 285 $this->getPluginManager()->enablePlugin($plugin); 286 } 287 288 /** 289 * Disables a plugin in the ProjectConfiguration class. 290 * 291 * @param string $plugin The name of the plugin 292 */ 293 protected function disablePlugin($plugin) 294 { 295 $this->getPluginManager()->disablePlugin($plugin); 296 } 297 298 /** 299 * Returns a plugin manager instance. 300 * 301 * @return sfSymfonyPluginManager A sfSymfonyPluginManager instance 302 */ 303 protected function getPluginManager() 304 { 305 if (is_null($this->pluginManager)) 306 { 307 $environment = new sfPearEnvironment($this->dispatcher, array( 308 'plugin_dir' => sfConfig::get('sf_plugins_dir'), 309 'cache_dir' => sfConfig::get('sf_cache_dir').'/.pear', 310 'web_dir' => sfConfig::get('sf_web_dir'), 311 'config_dir' => sfConfig::get('sf_config_dir'), 312 )); 313 314 $this->pluginManager = new sfSymfonyPluginManager($this->dispatcher, $environment); 315 } 316 317 return $this->pluginManager; 318 } 207 319 } branches/1.3/lib/task/sfCommandApplicationTask.class.php
r19112 r19273 53 53 } 54 54 } 55 56 /** 57 * Executes another task in the context of the current one. 58 * 59 * @param string $name The name of the task to execute 60 * @param array $arguments An array of arguments to pass to the task 61 * @param array $options An array of options to pass to the task 62 * 63 * @return Boolean The returned value of the task run() method 64 */ 65 protected function runTask($name, $arguments = array(), $options = array()) 66 { 67 if (is_null($this->commandApplication)) 68 { 69 throw new LogicException('No command application associated with this task yet.'); 70 } 71 72 $task = $this->commandApplication->getTaskToExecute($name); 73 $task->setCommandApplication($this->commandApplication); 74 75 return $task->run($arguments, $options); 76 } 55 77 }

