Subversion-Projekte lars-tiefland.php_share

Revision

Details | Letzte Änderung | Log anzeigen | RSS feed

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