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
 * Model generator.
13
 *
14
 * @package    symfony
15
 * @subpackage generator
16
 * @author     Fabien Potencier <fabien.potencier@symfony-project.com>
17
 * @version    SVN: $Id: sfModelGenerator.class.php 25459 2009-12-16 13:08:43Z fabien $
18
 */
19
abstract class sfModelGenerator extends sfGenerator
20
{
21
  protected
22
    $configuration = null,
23
    $primaryKey    = array(),
24
    $modelClass    = '',
25
    $params        = array(),
26
    $config        = array(),
27
    $formObject    = null;
28
 
29
  /**
30
   * Generates classes and templates in cache.
31
   *
32
   * @param array $params The parameters
33
   *
34
   * @return string The data to put in configuration cache
35
   */
36
  public function generate($params = array())
37
  {
38
    $this->validateParameters($params);
39
 
40
    $this->modelClass = $this->params['model_class'];
41
 
42
    // generated module name
43
    $this->setModuleName($this->params['moduleName']);
44
    $this->setGeneratedModuleName('auto'.ucfirst($this->params['moduleName']));
45
 
46
    // theme exists?
47
    $theme = isset($this->params['theme']) ? $this->params['theme'] : 'default';
48
    $this->setTheme($theme);
49
    $themeDir = $this->generatorManager->getConfiguration()->getGeneratorTemplate($this->getGeneratorClass(), $theme, '');
50
    if (!is_dir($themeDir))
51
    {
52
      throw new sfConfigurationException(sprintf('The theme "%s" does not exist.', $theme));
53
    }
54
 
55
    // configure the model
56
    $this->configure();
57
 
58
    $this->configuration = $this->loadConfiguration();
59
 
60
    // generate files
61
    $this->generatePhpFiles($this->generatedModuleName, sfFinder::type('file')->relative()->in($themeDir));
62
 
63
    // move helper file
64
    if (file_exists($file = $this->generatorManager->getBasePath().'/'.$this->getGeneratedModuleName().'/lib/helper.php'))
65
    {
66
      @rename($file, $this->generatorManager->getBasePath().'/'.$this->getGeneratedModuleName().'/lib/Base'.ucfirst($this->moduleName).'GeneratorHelper.class.php');
67
    }
68
 
69
    return "require_once(sfConfig::get('sf_module_cache_dir').'/".$this->generatedModuleName."/actions/actions.class.php');";
70
  }
71
 
72
  /**
73
   * Gets the actions base class for the generated module.
74
   *
75
   * @return string The actions base class
76
   */
77
  public function getActionsBaseClass()
78
  {
79
    return isset($this->params['actions_base_class']) ? $this->params['actions_base_class'] : 'sfActions';
80
  }
81
 
82
  /**
83
   * Gets the class name for current model.
84
   *
85
   * @return string
86
   */
87
  public function getModelClass()
88
  {
89
    return $this->modelClass;
90
  }
91
 
92
  /**
93
   * Gets the primary key name.
94
   *
95
   * @param Boolean $firstOne Whether to return the first PK or not
96
   *
97
   * @return array An array of primary keys
98
   */
99
  public function getPrimaryKeys($firstOne = false)
100
  {
101
    return $firstOne ? $this->primaryKey[0] : $this->primaryKey;
102
  }
103
 
104
  /**
105
   * Gets the singular name for current model.
106
   *
107
   * @return string
108
   */
109
  public function getSingularName()
110
  {
111
    return isset($this->params['singular']) ? $this->params['singular'] : sfInflector::underscore($this->getModelClass());
112
  }
113
 
114
  /**
115
   * Gets the plural name for current model.
116
   *
117
   * @return string
118
   */
119
  public function getPluralName()
120
  {
121
    return isset($this->params['plural']) ? $this->params['plural'] : $this->getSingularName().'_list';
122
  }
123
 
124
  /**
125
   * Gets the i18n catalogue to use for user strings.
126
   *
127
   * @return string The i18n catalogue
128
   */
129
  public function getI18nCatalogue()
130
  {
131
    return isset($this->params['i18n_catalogue']) ? $this->params['i18n_catalogue'] : 'messages';
132
  }
133
 
134
  /**
135
   * Returns PHP code for primary keys parameters.
136
   *
137
   * @param integer $indent The indentation value
138
   * @param string  $callee The function to call
139
   *
140
   * @return string The PHP code
141
   */
142
  public function getRetrieveByPkParamsForAction($indent)
143
  {
144
    $params = array();
145
    foreach ($this->getPrimaryKeys() as $pk)
146
    {
147
      $params[] = sprintf("\$request->getParameter('%s')", sfInflector::underscore($pk));
148
    }
149
 
150
    return implode(",\n".str_repeat(' ', max(0, $indent - strlen($this->getSingularName().$this->modelClass))), $params);
151
  }
152
 
153
  /**
154
   * Returns PHP code to add to a URL for primary keys.
155
   *
156
   * @param string $prefix The prefix value
157
   *
158
   * @return string PHP code
159
   */
160
  public function getPrimaryKeyUrlParams($prefix = '', $full = false)
161
  {
162
    $params = array();
163
    foreach ($this->getPrimaryKeys() as $pk)
164
    {
165
      $fieldName = sfInflector::underscore($pk);
166
 
167
      if ($full)
168
      {
169
        $params[] = sprintf("%s='.%s->%s()", $fieldName, $prefix, $this->getColumnGetter($fieldName, false));
170
      }
171
      else
172
      {
173
        $params[] = sprintf("%s='.%s", $fieldName, $this->getColumnGetter($fieldName, true, $prefix));
174
      }
175
    }
176
 
177
    return implode(".'&", $params);
178
  }
179
 
180
  /**
181
   * Configures this generator.
182
   */
183
  abstract protected function configure();
184
 
185
  abstract public function getType($column);
186
 
187
  abstract public function getAllFieldNames();
188
 
189
  /**
190
   * Returns the getter either non-developped: 'getFoo' or developped: '$class->getFoo()'.
191
   *
192
   * This method is ORM dependant.
193
   *
194
   * @param string  $column    The column name
195
   * @param boolean $developed true if you want developped method names, false otherwise
196
   * @param string  $prefix    The prefix value
197
   *
198
   * @return string PHP code
199
   */
200
  abstract public function getColumnGetter($column, $developed = false , $prefix = '');
201
 
202
  abstract public function getManyToManyTables();
203
 
204
  /**
205
   * Returns HTML code for an action link.
206
   *
207
   * @param string  $actionName The action name
208
   * @param array   $params     The parameters
209
   * @param boolean $pk_link    Whether to add a primary key link or not
210
   *
211
   * @return string HTML code
212
   */
213
  public function getLinkToAction($actionName, $params, $pk_link = false)
214
  {
215
    $action = isset($params['action']) ? $params['action'] : 'List'.sfInflector::camelize($actionName);
216
 
217
    $url_params = $pk_link ? '?'.$this->getPrimaryKeyUrlParams() : '\'';
218
 
219
    return '[?php echo link_to(__(\''.$params['label'].'\', array(), \''.$this->getI18nCatalogue().'\'), \''.$this->getModuleName().'/'.$action.$url_params.', '.$this->asPhp($params['params']).') ?]';
220
  }
221
 
222
  /**
223
   * Wraps content with a credential condition.
224
   *
225
   * @param string $content The content
226
   * @param array  $params  The parameters
227
   *
228
   * @return string HTML code
229
   */
230
  public function addCredentialCondition($content, $params = array())
231
  {
232
    if (isset($params['credentials']))
233
    {
234
      $credentials = $this->asPhp($params['credentials']);
235
 
236
      return <<<EOF
237
[?php if (\$sf_user->hasCredential($credentials)): ?]
238
$content
239
[?php endif; ?]
240
 
241
EOF;
242
    }
243
    else
244
    {
245
      return $content;
246
    }
247
  }
248
 
249
  /**
250
   * Returns HTML code for a field.
251
   *
252
   * @param sfModelGeneratorConfigurationField $field The field
253
   *
254
   * @return string HTML code
255
   */
256
  public function renderField($field)
257
  {
258
    $html = $this->getColumnGetter($field->getName(), true);
259
 
260
    if ($renderer = $field->getRenderer())
261
    {
262
      $html = sprintf("$html ? call_user_func_array(%s, array_merge(array(%s), %s)) : '&nbsp;'", $this->asPhp($renderer), $html, $this->asPhp($field->getRendererArguments()));
263
    }
264
    else if ($field->isComponent())
265
    {
266
      return sprintf("get_component('%s', '%s', array('type' => 'list', '%s' => \$%s))", $this->getModuleName(), $field->getName(), $this->getSingularName(), $this->getSingularName());
267
    }
268
    else if ($field->isPartial())
269
    {
270
      return sprintf("get_partial('%s/%s', array('type' => 'list', '%s' => \$%s))", $this->getModuleName(), $field->getName(), $this->getSingularName(), $this->getSingularName());
271
    }
272
    else if ('Date' == $field->getType())
273
    {
274
      $html = sprintf("false !== strtotime($html) ? format_date(%s, \"%s\") : '&nbsp;'", $html, $field->getConfig('date_format', 'f'));
275
    }
276
    else if ('Boolean' == $field->getType())
277
    {
278
      $html = sprintf("get_partial('%s/list_field_boolean', array('value' => %s))", $this->getModuleName(), $html);
279
    }
280
 
281
    if ($field->isLink())
282
    {
283
      $html = sprintf("link_to(%s, '%s', \$%s)", $html, $this->getUrlForAction('edit'), $this->getSingularName());
284
    }
285
 
286
    return $html;
287
  }
288
 
289
  /**
290
   * Wraps a content for I18N.
291
   *
292
   * @param string $key The configuration key name
293
   *
294
   * @return string HTML code
295
   */
296
  public function getI18NString($key)
297
  {
298
    $value = $this->configuration->getValue($key, '', true);
299
 
300
    $parts = explode('.', $key);
301
    $context = $parts[0];
302
 
303
    // find %%xx%% strings
304
    preg_match_all('/%%([^%]+)%%/', $value, $matches, PREG_PATTERN_ORDER);
305
    $fields = array();
306
    foreach ($matches[1] as $name)
307
    {
308
      $fields[] = $name;
309
    }
310
 
311
    $vars = array();
312
    foreach ($this->configuration->getContextConfiguration($context, $fields) as $field)
313
    {
314
      $vars[] = '\'%%'.$field->getName().'%%\' => '.$this->renderField($field);
315
    }
316
 
317
    return sprintf("__('%s', array(%s), '%s')", $value, implode(', ', $vars), $this->getI18nCatalogue());
318
  }
319
 
320
  /**
321
   * Gets the form object
322
   *
323
   * @return sfForm
324
   */
325
  public function getFormObject()
326
  {
327
    if (null === $this->formObject)
328
    {
329
      $class = null === $this->configuration ? $this->getModelClass().'Form' : $this->configuration->getFormClass();
330
 
331
      $this->formObject = new $class();
332
    }
333
 
334
    return $this->formObject;
335
  }
336
 
337
  /**
338
   * Gets the HTML to add to the form tag if the form is multipart.
339
   *
340
   * @return string
341
   */
342
  public function getFormMultipartHtml()
343
  {
344
    if (isset($this->params['non_verbose_templates']) && $this->params['non_verbose_templates'])
345
    {
346
      return '[?php $form->isMultipart() and print \' enctype="multipart/form-data"\' ?]';
347
    }
348
    else
349
    {
350
      return $this->getFormObject()->isMultipart() ? ' enctype="multipart/form-data"' : '';
351
    }
352
  }
353
 
354
  /**
355
   * Validates the basic structure of the parameters.
356
   *
357
   * @param array $params An array of parameters
358
   */
359
  protected function validateParameters($params)
360
  {
361
    foreach (array('model_class', 'moduleName') as $key)
362
    {
363
      if (!isset($params[$key]))
364
      {
365
        throw new sfParseException(sprintf('sfModelGenerator must have a "%s" parameter.', $key));
366
      }
367
    }
368
 
369
    if (!class_exists($params['model_class']))
370
    {
371
      throw new sfInitializationException(sprintf('Unable to generate a module for non-existent model "%s".', $params['model_class']));
372
    }
373
 
374
    $this->config = isset($params['config']) ? $params['config'] : array();
375
 
376
    unset($params['config']);
377
    $this->params = $params;
378
  }
379
 
380
  /**
381
   * Loads the configuration for this generated module.
382
   */
383
  protected function loadConfiguration()
384
  {
385
    try
386
    {
387
      $this->generatorManager->getConfiguration()->getGeneratorTemplate($this->getGeneratorClass(), $this->getTheme(), '../parts/configuration.php');
388
    }
389
    catch (sfException $e)
390
    {
391
      return null;
392
    }
393
 
394
    $config = $this->getGeneratorManager()->getConfiguration();
395
    if (!$config instanceof sfApplicationConfiguration)
396
    {
397
      throw new LogicException('The sfModelGenerator can only operates with an application configuration.');
398
    }
399
 
400
    $basePath = $this->getGeneratedModuleName().'/lib/Base'.ucfirst($this->getModuleName()).'GeneratorConfiguration.class.php';
401
    $this->getGeneratorManager()->save($basePath, $this->evalTemplate('../parts/configuration.php'));
402
 
403
    require_once $this->getGeneratorManager()->getBasePath().'/'.$basePath;
404
 
405
    $class = 'Base'.ucfirst($this->getModuleName()).'GeneratorConfiguration';
406
    foreach ($config->getLibDirs($this->getModuleName()) as $dir)
407
    {
408
      if (!is_file($configuration = $dir.'/'.$this->getModuleName().'GeneratorConfiguration.class.php'))
409
      {
410
        continue;
411
      }
412
 
413
      require_once $configuration;
414
      $class = $this->getModuleName().'GeneratorConfiguration';
415
      break;
416
    }
417
 
418
    // validate configuration
419
    foreach ($this->config as $context => $value)
420
    {
421
      if (!$value)
422
      {
423
        continue;
424
      }
425
 
426
      throw new InvalidArgumentException(sprintf('Your generator configuration contains some errors for the "%s" context. The following configuration cannot be parsed: %s.', $context, $this->asPhp($value)));
427
    }
428
 
429
    return new $class();
430
  }
431
 
432
  /**
433
   * Returns the URL for a given action.
434
   *
435
   * @return string The URL related to a given action
436
   */
437
  public function getUrlForAction($action)
438
  {
439
    if (isset($this->params['route_prefix']))
440
    {
441
      return 'list' == $action ? $this->params['route_prefix'] : $this->params['route_prefix'].'_'.$action;
442
    }
443
    else
444
    {
445
      return $this->getModuleName().'/'.$action;
446
    }
447
  }
448
 
449
  public function asPhp($variable)
450
  {
451
    return str_replace(array("\n", 'array ('), array('', 'array('), var_export($variable, true));
452
  }
453
 
454
  public function escapeString($string)
455
  {
456
    return str_replace("'", "\\'", $string);
457
  }
458
}