Development

/branches/1.4/lib/plugins/sfPropelPlugin/lib/generator/sfPropelFormGenerator.class.php

You must first sign up to be able to contribute.

root/branches/1.4/lib/plugins/sfPropelPlugin/lib/generator/sfPropelFormGenerator.class.php

Revision 33137, 14.9 kB (checked in by fabien, 3 years ago)

[1.4] fixed multiple database support in Propel plugin (for the generator and sfPropelData, closes #8345)

  • Property svn:mime-type set to text/x-php
  • 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  *
7  * For the full copyright and license information, please view the LICENSE
8  * file that was distributed with this source code.
9  */
10
11 /**
12  * Propel form generator.
13  *
14  * This class generates a Propel forms.
15  *
16  * @package    symfony
17  * @subpackage generator
18  * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
19  * @version    SVN: $Id$
20  */
21 class sfPropelFormGenerator extends sfGenerator
22 {
23   protected
24     $dbMap = null;
25
26   /**
27    * Initializes the current sfGenerator instance.
28    *
29    * @param sfGeneratorManager $generatorManager A sfGeneratorManager instance
30    */
31   public function initialize(sfGeneratorManager $generatorManager)
32   {
33     parent::initialize($generatorManager);
34
35     $this->setGeneratorClass('sfPropelForm');
36   }
37
38   /**
39    * Generates classes and templates in cache.
40    *
41    * @param array $params The parameters
42    *
43    * @return string The data to put in configuration cache
44    */
45   public function generate($params = array())
46   {
47     $this->params = $params;
48
49     if (!isset($this->params['connection']))
50     {
51       throw new sfParseException('You must specify a "connection" parameter.');
52     }
53
54     if (!isset($this->params['model_dir_name']))
55     {
56       $this->params['model_dir_name'] = 'model';
57     }
58
59     if (!isset($this->params['form_dir_name']))
60     {
61       $this->params['form_dir_name'] = 'form';
62     }
63
64     $this->loadBuilders();
65
66     // create the project base class for all forms
67     $file = sfConfig::get('sf_lib_dir').'/form/BaseFormPropel.class.php';
68     if (!file_exists($file))
69     {
70       if (!is_dir($directory = dirname($file)))
71       {
72         mkdir($directory, 0777, true);
73       }
74
75       file_put_contents($file, $this->evalTemplate('sfPropelFormBaseTemplate.php'));
76     }
77
78     // create a form class for every Propel class
79     foreach ($this->dbMap->getTables() as $tableName => $table)
80     {
81       $behaviors = $table->getBehaviors();
82       if (isset($behaviors['symfony']['form']) && 'false' === $behaviors['symfony']['form'])
83       {
84         continue;
85       }
86
87       $this->table = $table;
88
89       // find the package to store forms in the same directory as the model classes
90       $packages = explode('.', constant(constant($table->getClassname().'::PEER').'::CLASS_DEFAULT'));
91       array_pop($packages);
92       if (false === $pos = array_search($this->params['model_dir_name'], $packages))
93       {
94         throw new InvalidArgumentException(sprintf('Unable to find the model dir name (%s) in the package %s.', $this->params['model_dir_name'], constant(constant($table->getClassname().'::PEER').'::CLASS_DEFAULT')));
95       }
96       $packages[$pos] = $this->params['form_dir_name'];
97       $baseDir = sfConfig::get('sf_root_dir').'/'.implode(DIRECTORY_SEPARATOR, $packages);
98
99       if (!is_dir($baseDir.'/base'))
100       {
101         mkdir($baseDir.'/base', 0777, true);
102       }
103
104       file_put_contents($baseDir.'/base/Base'.$table->getClassname().'Form.class.php', $this->evalTemplate('sfPropelFormGeneratedTemplate.php'));
105       if (!file_exists($classFile = $baseDir.'/'.$table->getClassname().'Form.class.php'))
106       {
107         file_put_contents($classFile, $this->evalTemplate('sfPropelFormTemplate.php'));
108       }
109     }
110   }
111
112   /**
113    * Returns an array of tables that represents a many to many relationship.
114    *
115    * A table is considered to be a m2m table if it has 2 foreign keys that are also primary keys.
116    *
117    * @return array An array of tables.
118    */
119   public function getManyToManyTables()
120   {
121     $tables = array();
122
123     // go through all tables to find m2m relationships
124     foreach ($this->dbMap->getTables() as $tableName => $table)
125     {
126       foreach ($table->getColumns() as $column)
127       {
128         if ($column->isForeignKey() && $column->isPrimaryKey() && $this->table->getClassname() == $this->getForeignTable($column)->getClassname())
129         {
130           // we have a m2m relationship
131           // find the other primary key
132           foreach ($table->getColumns() as $relatedColumn)
133           {
134             if ($relatedColumn->isForeignKey() && $relatedColumn->isPrimaryKey() && $this->table->getClassname() != $this->getForeignTable($relatedColumn)->getClassname())
135             {
136               // we have the related table
137               $tables[] = array(
138                 'middleTable'   => $table,
139                 'relatedTable'  => $this->getForeignTable($relatedColumn),
140                 'column'        => $column,
141                 'relatedColumn' => $relatedColumn,
142               );
143
144               break 2;
145             }
146           }
147         }
148       }
149     }
150
151     return $tables;
152   }
153
154   /**
155    * Returns PHP names for all foreign keys of the current table.
156    *
157    * This method does not returns foreign keys that are also primary keys.
158    *
159    * @return array An array composed of:
160    *                 * The foreign table PHP name
161    *                 * The foreign key PHP name
162    *                 * A Boolean to indicate whether the column is required or not
163    *                 * A Boolean to indicate whether the column is a many to many relationship or not
164    */
165   public function getForeignKeyNames()
166   {
167     $names = array();
168     foreach ($this->table->getColumns() as $column)
169     {
170       if (!$column->isPrimaryKey() && $column->isForeignKey())
171       {
172         $names[] = array($this->getForeignTable($column)->getClassname(), $column->getPhpName(), $column->isNotNull(), false);
173       }
174     }
175
176     foreach ($this->getManyToManyTables() as $tables)
177     {
178       $names[] = array($tables['relatedTable']->getClassname(), $tables['middleTable']->getClassname(), false, true);
179     }
180
181     return $names;
182   }
183
184   /**
185    * Returns the first primary key column of the current table.
186    *
187    * @return ColumnMap A ColumnMap object
188    */
189   public function getPrimaryKey()
190   {
191     foreach ($this->table->getColumns() as $column)
192     {
193       if ($column->isPrimaryKey())
194       {
195         return $column;
196       }
197     }
198   }
199
200   /**
201    * Returns the foreign table associated with a column.
202    *
203    * @param  ColumnMap $column A ColumnMap object
204    *
205    * @return TableMap  A TableMap object
206    */
207   public function getForeignTable(ColumnMap $column)
208   {
209     return $this->dbMap->getTable($column->getRelatedTableName());
210   }
211
212   /**
213    * Returns a sfWidgetForm class name for a given column.
214    *
215    * @param  ColumnMap  $column A ColumnMap object
216    *
217    * @return string    The name of a subclass of sfWidgetForm
218    */
219   public function getWidgetClassForColumn(ColumnMap $column)
220   {
221     switch ($column->getType())
222     {
223       case PropelColumnTypes::BOOLEAN:
224         $name = 'InputCheckbox';
225         break;
226       case PropelColumnTypes::CLOB:
227       case PropelColumnTypes::LONGVARCHAR:
228         $name = 'Textarea';
229         break;
230       case PropelColumnTypes::DATE:
231         $name = 'Date';
232         break;
233       case PropelColumnTypes::TIME:
234         $name = 'Time';
235         break;
236       case PropelColumnTypes::TIMESTAMP:
237         $name = 'DateTime';
238         break;
239       default:
240         $name = 'InputText';
241     }
242
243     if ($column->isPrimaryKey())
244     {
245       $name = 'InputHidden';
246     }
247     else if ($column->isForeignKey())
248     {
249       $name = 'PropelChoice';
250     }
251
252     return sprintf('sfWidgetForm%s', $name);
253   }
254
255   /**
256    * Returns a PHP string representing options to pass to a widget for a given column.
257    *
258    * @param  ColumnMap $column  A ColumnMap object
259    *
260    * @return string    The options to pass to the widget as a PHP string
261    */
262   public function getWidgetOptionsForColumn(ColumnMap $column)
263   {
264     $options = array();
265
266     if (!$column->isPrimaryKey() && $column->isForeignKey())
267     {
268       $options[] = sprintf('\'model\' => \'%s\', \'add_empty\' => %s', $this->getForeignTable($column)->getClassname(), $column->isNotNull() ? 'false' : 'true');
269
270       $refColumn = $this->getForeignTable($column)->getColumn($column->getRelatedColumnName());
271       if (!$refColumn->isPrimaryKey())
272       {
273         $options[] = sprintf('\'key_method\' => \'get%s\'', $refColumn->getPhpName());
274       }
275     }
276
277     return count($options) ? sprintf('array(%s)', implode(', ', $options)) : '';
278   }
279
280   /**
281    * Returns a sfValidator class name for a given column.
282    *
283    * @param  ColumnMap $column  A ColumnMap object
284    *
285    * @return string    The name of a subclass of sfValidator
286    */
287   public function getValidatorClassForColumn(ColumnMap $column)
288   {
289     switch ($column->getType())
290     {
291       case PropelColumnTypes::BOOLEAN:
292         $name = 'Boolean';
293         break;
294       case PropelColumnTypes::CLOB:
295       case PropelColumnTypes::CHAR:
296       case PropelColumnTypes::VARCHAR:
297       case PropelColumnTypes::LONGVARCHAR:
298         $name = 'String';
299         break;
300       case PropelColumnTypes::DOUBLE:
301       case PropelColumnTypes::FLOAT:
302       case PropelColumnTypes::NUMERIC:
303       case PropelColumnTypes::DECIMAL:
304       case PropelColumnTypes::REAL:
305         $name = 'Number';
306         break;
307       case PropelColumnTypes::INTEGER:
308       case PropelColumnTypes::SMALLINT:
309       case PropelColumnTypes::TINYINT:
310       case PropelColumnTypes::BIGINT:
311         $name = 'Integer';
312         break;
313       case PropelColumnTypes::DATE:
314         $name = 'Date';
315         break;
316       case PropelColumnTypes::TIME:
317         $name = 'Time';
318         break;
319       case PropelColumnTypes::TIMESTAMP:
320         $name = 'DateTime';
321         break;
322       default:
323         $name = 'Pass';
324     }
325
326     if ($column->isForeignKey())
327     {
328       $name = 'PropelChoice';
329     }
330     else if ($column->isPrimaryKey())
331     {
332       $name = 'Choice';
333     }
334
335     return sprintf('sfValidator%s', $name);
336   }
337
338   /**
339    * Returns a PHP string representing options to pass to a validator for a given column.
340    *
341    * @param  ColumnMap $column  A ColumnMap object
342    *
343    * @return string    The options to pass to the validator as a PHP string
344    */
345   public function getValidatorOptionsForColumn(ColumnMap $column)
346   {
347     $options = array();
348
349     if ($column->isForeignKey())
350     {
351       $options[] = sprintf('\'model\' => \'%s\', \'column\' => \'%s\'', $this->getForeignTable($column)->getClassname(), $this->translateColumnName($column, true));
352     }
353     else if ($column->isPrimaryKey())
354     {
355       $options[] = sprintf('\'choices\' => array($this->getObject()->get%s()), \'empty_value\' => $this->getObject()->get%1$s()', $this->translateColumnName($column, false, BasePeer::TYPE_PHPNAME));
356     }
357     else
358     {
359       switch ($column->getType())
360       {
361         case PropelColumnTypes::CLOB:
362         case PropelColumnTypes::CHAR:
363         case PropelColumnTypes::VARCHAR:
364         case PropelColumnTypes::LONGVARCHAR:
365           if ($column->getSize())
366           {
367             $options[] = sprintf('\'max_length\' => %s', $column->getSize());
368           }
369           break;
370
371        case PropelColumnTypes::TINYINT:
372          $options[] = sprintf('\'min\' => %s, \'max\' => %s', -128, 127);
373          break;
374
375        case PropelColumnTypes::SMALLINT:
376          $options[] = sprintf('\'min\' => %s, \'max\' => %s', -32768, 32767);
377          break;
378
379        case PropelColumnTypes::INTEGER:
380          $options[] = sprintf('\'min\' => %s, \'max\' => %s', -2147483648, 2147483647);
381          break;
382
383        case PropelColumnTypes::BIGINT:
384          $options[] = sprintf('\'min\' => %s, \'max\' => %s', -9223372036854775808, 9223372036854775807);
385          break;
386       }
387     }
388
389     if (!$column->isNotNull() || $column->isPrimaryKey())
390     {
391       $options[] = '\'required\' => false';
392     }
393
394     return count($options) ? sprintf('array(%s)', implode(', ', $options)) : '';
395   }
396
397   /**
398    * Returns the maximum length for a column name.
399    *
400    * @return integer The length of the longer column name
401    */
402   public function getColumnNameMaxLength()
403   {
404     $max = 0;
405     foreach ($this->table->getColumns() as $column)
406     {
407       if (($m = strlen($column->getName())) > $max)
408       {
409         $max = $m;
410       }
411     }
412
413     foreach ($this->getManyToManyTables() as $tables)
414     {
415       if (($m = strlen($this->underscore($tables['middleTable']->getClassname()).'_list')) > $max)
416       {
417         $max = $m;
418       }
419     }
420
421     return $max;
422   }
423
424   /**
425    * Returns an array of primary key column names.
426    *
427    * @return array An array of primary key column names
428    */
429   public function getPrimaryKeyColumNames()
430   {
431     $pks = array();
432     foreach ($this->table->getColumns() as $column)
433     {
434       if ($column->isPrimaryKey())
435       {
436         $pks[] = $this->translateColumnName($column);
437       }
438     }
439
440     return $pks;
441   }
442
443   /**
444    * Returns a PHP string representation for the array of all primary key column names.
445    *
446    * @return string A PHP string representation for the array of all primary key column names
447    *
448    * @see getPrimaryKeyColumNames()
449    */
450   public function getPrimaryKeyColumNamesAsString()
451   {
452     return sprintf('array(\'%s\')', implode('\', \'', $this->getPrimaryKeyColumNames()));
453   }
454
455   /**
456    * Returns true if the current table is internationalized.
457    *
458    * @return Boolean true if the current table is internationalized, false otherwise
459    */
460   public function isI18n()
461   {
462     return method_exists(constant($this->table->getClassname().'::PEER'), 'getI18nModel');
463   }
464
465   /**
466    * Returns the i18n model name for the current table.
467    *
468    * @return string The model class name
469    */
470   public function getI18nModel()
471   {
472     return call_user_func(array(constant($this->table->getClassname().'::PEER'), 'getI18nModel'));
473   }
474
475   public function underscore($name)
476   {
477     return strtolower(preg_replace(array('/([A-Z]+)([A-Z][a-z])/', '/([a-z\d])([A-Z])/'), '\\1_\\2', $name));
478   }
479
480   public function getUniqueColumnNames()
481   {
482     $uniqueColumns = array();
483
484     foreach (call_user_func(array(constant($this->table->getClassname().'::PEER'), 'getUniqueColumnNames')) as $unique)
485     {
486       $uniqueColumn = array();
487       foreach ($unique as $column)
488       {
489         $uniqueColumn[] = $this->translateColumnName($this->table->getColumn($column));
490       }
491
492       $uniqueColumns[] = $uniqueColumn;
493     }
494
495     return $uniqueColumns;
496   }
497
498   public function translateColumnName($column, $related = false, $to = BasePeer::TYPE_FIELDNAME)
499   {
500     $peer = $related ? constant($column->getTable()->getDatabaseMap()->getTable($column->getRelatedTableName())->getPhpName().'::PEER') : constant($column->getTable()->getPhpName().'::PEER');
501     $field = $related ? $column->getRelatedName() : $column->getFullyQualifiedName();
502
503     return call_user_func(array($peer, 'translateFieldName'), $field, BasePeer::TYPE_COLNAME, $to);
504   }
505
506   /**
507    * Loads all Propel builders.
508    */
509   protected function loadBuilders()
510   {
511     $this->dbMap = Propel::getDatabaseMap($this->params['connection']);
512     $classes = sfFinder::type('file')->name('*TableMap.php')->in($this->generatorManager->getConfiguration()->getModelDirs());
513     foreach ($classes as $class)
514     {
515       $omClass = basename($class, 'TableMap.php');
516       if (class_exists($omClass) && is_subclass_of($omClass, 'BaseObject') && constant($omClass.'Peer::DATABASE_NAME') == $this->params['connection'])
517       {
518         $tableMapClass = basename($class, '.php');
519         $this->dbMap->addTableFromMapClass($tableMapClass);
520       }
521     }
522   }
523 }
524
Note: See TracBrowser for help on using the browser.