Development

Changeset 19273

You must first sign up to be able to contribute.

Changeset 19273

Show
Ignore:
Timestamp:
06/15/09 14:47:22 (9 months ago)
Author:
fabien
Message:

[1.3] enhanced the generate:project task and plugin installation

  • You can now ask symfony to generate a project without any ORM (--orm=none)
  • You can enable/disable a plugin from an installer (enablePlugin(), disablePlugin())
  • Plugins are now disabled by default for new projects
    • the plugin:install task enable the installed plugins
    • the plugin:unintall task disable the uninstalled plugins
Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/1.3/WHATS_NEW

    r19214 r19273  
    261261    $ php /path/to/symfony generate:project foo --orm=Propel 
    262262 
     263If 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 
    263268The new `--installer` option allows you to pass a PHP script that can further 
    264269customize the newly created project. The script is executed in the context of 
    265270the task, and so can use any of its methods. The more useful ones are the 
    266271following: `installDir()`, `runTask()`, `ask()`, `askConfirmation()`, 
    267 `askAndValidate()`, and `reloadTasks()`. 
     272`askAndValidate()`, `reloadTasks()`, `enablePlugin()`, and `disablePlugin()`. 
    268273 
    269274More information can be found in this 
     
    357362`sfCultureInfo->sortArray()` can be used for that. 
    358363 
     364Plugins 
     365------- 
     366 
     367Before 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 
     380For freshly created projects with symfony 1.3, plugins must be explicitly 
     381enabled 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 
     392The `plugin:install` task automatically enables the plugin(s) it installs (and 
     393`plugin:uninstall` disable them). If you install a plugin via Subversion, you 
     394still need to enable it by hand. 
     395 
     396If you want to use a core-plugin, like `sfProtoculousPlugin` or 
     397`sfCompat10Plugin`, you just need to add the corresponding `enablePlugins()` 
     398statement 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  
    377377    'sfcachecleartask' => 'task/cache/sfCacheClearTask.class.php', 
    378378    'sfconfigureauthortask' => 'task/configure/sfConfigureAuthorTask.class.php', 
    379     'sfconfiguredatabasetask' => 'task/configure/sfConfigureDatabaseTask.class.php', 
    380379    'sfgenerateapptask' => 'task/generator/sfGenerateAppTask.class.php', 
    381380    'sfgeneratemoduletask' => 'task/generator/sfGenerateModuleTask.class.php', 
     
    429428    'sfbrowserbase' => 'util/sfBrowserBase.class.php', 
    430429    'sfcallable' => 'util/sfCallable.class.php', 
     430    'sfclassmanipulator' => 'util/sfClassManipulator.class.php', 
    431431    'sfcontext' => 'util/sfContext.class.php', 
    432432    'sfdomcssselector' => 'util/sfDomCssSelector.class.php', 
  • branches/1.3/lib/plugin/sfSymfonyPluginManager.class.php

    r12847 r19273  
    5656 
    5757    // 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')); 
    6061  } 
    6162 
     
    104105 
    105106  /** 
     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  /** 
    106148   * Listens to the plugin.post_install event. 
    107149   * 
    108150   * @param sfEvent $event An sfEvent instance 
    109151   */ 
    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']); 
    114157  } 
    115158 
     
    119162   * @param sfEvent $event An sfEvent instance 
    120163   */ 
    121   public function ListenToPluginPostUninstall($event) 
     164  public function listenToPluginPostUninstall($event) 
    122165  { 
    123166    $this->uninstallWebContent($event['plugin']); 
     167  } 
     168 
     169  public function listenToPluginPostUnintall(sfEvent $event) 
     170  { 
     171    $this->disablePlugin($event['plugin']); 
    124172  } 
    125173 
  • branches/1.3/lib/plugins/sfDoctrinePlugin/config/installer.php

    r19116 r19273  
    22 
    33$this->installDir(dirname(__FILE__).'/skeleton'); 
     4$this->enablePlugin('sfDoctrinePlugin'); 
     5$this->reloadTasks(); 
  • branches/1.3/lib/plugins/sfPropelPlugin/config/installer.php

    r19116 r19273  
    22 
    33$this->installDir(dirname(__FILE__).'/skeleton'); 
     4$this->enablePlugin('sfPropelPlugin'); 
     5$this->reloadTasks(); 
  • branches/1.3/lib/task/generator/sfGenerateProjectTask.class.php

    r19215 r19273  
    6565  [./symfony generate:project blog --orm=Propel|INFO] 
    6666 
     67If 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 
    6771You can also pass the [--installer|INFO] option to further customize the 
    6872project: 
     
    8286    } 
    8387 
    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    } 
    8992 
    9093    $this->arguments = $arguments; 
    9194    $this->options = $options; 
    9295 
     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 
    93112    $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    } 
    94119 
    95120    // execute a custom installer 
     
    108133    $this->replaceTokens(); 
    109134  } 
    110  
    111   /** 
    112    * Executes another task in the context of the current one. 
    113    * 
    114    * @param  string  $name      The name of the task to execute 
    115    * @param  array   $arguments An array of arguments to pass to the task 
    116    * @param  array   $options   An array of options to pass to the task 
    117    * 
    118    * @return Boolean The returned value of the task run() method 
    119    */ 
    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 mirror 
    137    * @param sfFinder $finder A sfFinder instance to use for the mirroring 
    138    */ 
    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 replacement 
    155    * @param array $tokens An array of tokens to use 
    156    */ 
    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   } 
    204135} 
  • branches/1.3/lib/task/generator/skeleton/project/config/ProjectConfiguration.class.php

    r19116 r19273  
    88  public function setup() 
    99  { 
    10     // for compatibility / remove and enable only the plugins you want 
    11     $this->enableAllPluginsExcept(array('sf##OTHER_ORM##Plugin', 'sfCompat10Plugin')); 
    1210  } 
    1311} 
  • branches/1.3/lib/task/plugin/sfPluginBaseTask.class.php

    r6931 r19273  
    1919abstract class sfPluginBaseTask extends sfBaseTask 
    2020{ 
    21   private 
    22    $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   } 
    3921} 
  • branches/1.3/lib/task/sfBaseTask.class.php

    r16171 r19273  
    2020{ 
    2121  protected 
    22     $configuration = null; 
     22    $configuration = null, 
     23    $pluginManager = null; 
    2324 
    2425  /** 
     
    205206    sfSimpleAutoload::getInstance(sfConfig::get('sf_cache_dir').'/project_autoload.cache')->reload(); 
    206207  } 
     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  } 
    207319} 
  • branches/1.3/lib/task/sfCommandApplicationTask.class.php

    r19112 r19273  
    5353    } 
    5454  } 
     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  } 
    5577} 

The Sensio Labs Network

Since 1998, Sensio Labs has been promoting the Open-Source software movement by providing quality web application development, training, consulting.
Sensio Labs also supports several large Open-Source projects.