Development

/branches/1.4/lib/plugins/sfDoctrinePlugin/lib/task/sfDoctrineBaseTask.class.php

You must first sign up to be able to contribute.

root/branches/1.4/lib/plugins/sfDoctrinePlugin/lib/task/sfDoctrineBaseTask.class.php

Revision 28976, 8.2 kB (checked in by Kris.Wallsmith, 5 years ago)

[1.3, 1.4] added expansion of short listeners syntax when merging schemas (closes #7701, refs #8449)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
Line 
1 <?php
2
3 /*
4  * This file is part of the symfony package.
5  * (c) Fabien Potencier <fabien.potencier@symfony-project.com>
6  * (c) Jonathan H. Wage <jonwage@gmail.com>
7  *
8  * For the full copyright and license information, please view the LICENSE
9  * file that was distributed with this source code.
10  */
11
12 /**
13  * Base class for all symfony Doctrine tasks.
14  *
15  * @package    symfony
16  * @subpackage doctrine
17  * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
18  * @author     Jonathan H. Wage <jonwage@gmail.com>
19  * @version    SVN: $Id$
20  */
21 abstract class sfDoctrineBaseTask extends sfBaseTask
22 {
23   /**
24    * Returns an array of configuration variables for the Doctrine CLI.
25    *
26    * @return array $config
27    *
28    * @see sfDoctrinePluginConfiguration::getCliConfig()
29    */
30   public function getCliConfig()
31   {
32     return $this->configuration->getPluginConfiguration('sfDoctrinePlugin')->getCliConfig();
33   }
34
35   /**
36    * Calls a Doctrine CLI command.
37    *
38    * @param string $task Name of the Doctrine task to call
39    * @param array  $args Arguments for the task
40    *
41    * @see sfDoctrineCli
42    */
43   public function callDoctrineCli($task, $args = array())
44   {
45     $config = $this->getCliConfig();
46
47     $arguments = array('./symfony', $task);
48
49     foreach ($args as $key => $arg)
50     {
51       if (isset($config[$key]))
52       {
53         $config[$key] = $arg;
54       }
55       else
56       {
57         $arguments[] = $arg;
58       }
59     }
60
61     $cli = new sfDoctrineCli($config);
62     $cli->setSymfonyDispatcher($this->dispatcher);
63     $cli->setSymfonyFormatter($this->formatter);
64     $cli->run($arguments);
65   }
66
67   /**
68    * Returns Doctrine databases from the supplied database manager.
69    *
70    * @param sfDatabaseManager $databaseManager
71    * @param array|null        $names An array of names or NULL for all databases
72    *
73    * @return array An associative array of {@link sfDoctrineDatabase} objects and their names
74    *
75    * @throws InvalidArgumentException If a requested database is not a Doctrine database
76    */
77   protected function getDoctrineDatabases(sfDatabaseManager $databaseManager, array $names = null)
78   {
79     $databases = array();
80
81     if (null === $names)
82     {
83       foreach ($databaseManager->getNames() as $name)
84       {
85         $database = $databaseManager->getDatabase($name);
86
87         if ($database instanceof sfDoctrineDatabase)
88         {
89           $databases[$name] = $database;
90         }
91       }
92     }
93     else
94     {
95       foreach ($names as $name)
96       {
97         $database = $databaseManager->getDatabase($name);
98
99         if (!$database instanceof sfDoctrineDatabase)
100         {
101           throw new InvalidArgumentException(sprintf('The database "%s" is not a Doctrine database.', $name));
102         }
103
104         $databases[$name] = $database;
105       }
106     }
107
108     return $databases;
109   }
110
111   /**
112    * Merges all project and plugin schema files into one.
113    *
114    * Schema files are merged similar to how other configuration files are in
115    * symfony, utilizing a configuration cascade. Files later in the cascade
116    * can change values from earlier in the cascade.
117    *
118    * The order in which schema files are processed is like so:
119    *
120    *  1. Plugin schema files
121    *    * Plugins are processed in the order which they were enabled in ProjectConfiguration
122    *    * Each plugin's schema files are processed in alphabetical order
123    *  2. Project schema files
124    *    * Project schema files are processed in alphabetical order
125    *
126    * A schema file is any file saved in a plugin or project's config/doctrine/
127    * directory that matches the "*.yml" glob.
128    *
129    * @return string Absolute path to the consolidated schema file
130    */
131   protected function prepareSchemaFile($yamlSchemaPath)
132   {
133     $models = array();
134     $finder = sfFinder::type('file')->name('*.yml')->sort_by_name()->follow_link();
135
136     // plugin models
137     foreach ($this->configuration->getPlugins() as $name)
138     {
139       $plugin = $this->configuration->getPluginConfiguration($name);
140       foreach ($finder->in($plugin->getRootDir().'/config/doctrine') as $schema)
141       {
142         $pluginModels = (array) sfYaml::load($schema);
143         $globals = $this->filterSchemaGlobals($pluginModels);
144
145         foreach ($pluginModels as $model => $definition)
146         {
147           // canonicalize this definition
148           $definition = $this->canonicalizeModelDefinition($model, $definition);
149
150           // merge in the globals
151           $definition = array_merge($globals, $definition);
152
153           // merge this model into the schema
154           $models[$model] = isset($models[$model]) ? sfToolkit::arrayDeepMerge($models[$model], $definition) : $definition;
155
156           // the first plugin to define this model gets the package
157           if (!isset($models[$model]['package']))
158           {
159             $models[$model]['package'] = $plugin->getName().'.lib.model.doctrine';
160           }
161
162           if (!isset($models[$model]['package_custom_path']) && 0 === strpos($models[$model]['package'], $plugin->getName()))
163           {
164             $models[$model]['package_custom_path'] = $plugin->getRootDir().'/lib/model/doctrine';
165           }
166         }
167       }
168     }
169
170     // project models
171     foreach ($finder->in($yamlSchemaPath) as $schema)
172     {
173       $projectModels = (array) sfYaml::load($schema);
174       $globals = $this->filterSchemaGlobals($projectModels);
175
176       foreach ($projectModels as $model => $definition)
177       {
178         // canonicalize this definition
179         $definition = $this->canonicalizeModelDefinition($model, $definition);
180
181         // merge in the globals
182         $definition = array_merge($globals, $definition);
183
184         // merge this model into the schema
185         $models[$model] = isset($models[$model]) ? sfToolkit::arrayDeepMerge($models[$model], $definition) : $definition;
186       }
187     }
188
189     // create one consolidated schema file
190     $file = realpath(sys_get_temp_dir()).'/doctrine_schema_'.rand(11111, 99999).'.yml';
191     $this->logSection('file+', $file);
192     file_put_contents($file, sfYaml::dump($models, 4));
193
194     return $file;
195   }
196
197   /**
198    * Removes and returns globals from the supplied array of models.
199    *
200    * @param array $models An array of model definitions
201    *
202    * @return array An array of globals
203    *
204    * @see Doctrine_Import_Schema::getGlobalDefinitionKeys()
205    */
206   protected function filterSchemaGlobals(& $models)
207   {
208     $globals = array();
209     $globalKeys = Doctrine_Import_Schema::getGlobalDefinitionKeys();
210
211     foreach ($models as $key => $value)
212     {
213       if (in_array($key, $globalKeys))
214       {
215         $globals[$key] = $value;
216         unset($models[$key]);
217       }
218     }
219
220     return $globals;
221   }
222
223   /**
224    * Canonicalizes a model definition in preparation for merging.
225    *
226    * @param string $model      The model name
227    * @param array  $definition The model definition
228    *
229    * @return array The canonicalized model definition
230    */
231   protected function canonicalizeModelDefinition($model, $definition)
232   {
233     // expand short "type" syntax
234     if (isset($definition['columns']))
235     {
236       foreach ($definition['columns'] as $key => $value)
237       {
238         if (!is_array($value))
239         {
240           $definition['columns'][$key] = array('type' => $value);
241           $value = $definition['columns'][$key];
242         }
243
244         // expand short type(length, scale) syntax
245         if (isset($value['type']) && preg_match('/ *(\w+) *\( *(\d+)(?: *, *(\d+))? *\)/', $value['type'], $match))
246         {
247           $definition['columns'][$key]['type'] = $match[1];
248           $definition['columns'][$key]['length'] = $match[2];
249
250           if (isset($match[3]))
251           {
252             $definition['columns'][$key]['scale'] = $match[3];
253           }
254         }
255       }
256     }
257
258     // expand short "actAs" syntax
259     if (isset($definition['actAs']))
260     {
261       foreach ($definition['actAs'] as $key => $value)
262       {
263         if (is_numeric($key))
264         {
265           $definition['actAs'][$value] = array();
266           unset($definition['actAs'][$key]);
267         }
268       }
269     }
270
271     // expand short "listeners" syntax
272     if (isset($definition['listeners']))
273     {
274       foreach ($definition['listeners'] as $key => $value)
275       {
276         if (is_numeric($key))
277         {
278           $definition['listeners'][$value] = array();
279           unset($definition['listeners'][$key]);
280         }
281       }
282     }
283
284     return $definition;
285   }
286 }
287
Note: See TracBrowser for help on using the browser.