Development

Changeset 7394

You must first sign up to be able to contribute.

Changeset 7394

Show
Ignore:
Timestamp:
02/07/08 21:42:52 (10 months ago)
Author:
francois
Message:

Ported sfPropelAlternativeSchemaPlugin features to 1.1 branch:

  • Allow a schema to override another one
  • Allow behavior declaration directly in the schema
  • Provide an alternative schema syntax, more object-oriented
Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/1.1/lib/plugins/sfPropelPlugin/lib/propel/builder/SfObjectBuilder.php

    r6970 r7394  
    347347    $script .= $tmp; 
    348348  } 
     349   
     350  protected function addClassClose(&$script) 
     351  { 
     352    parent::addClassClose($script); 
     353     
     354    $behaviors = $this->getTable()->getAttribute('behaviors'); 
     355    if($behaviors) 
     356    { 
     357      $behavior_file_name = 'Base'.$this->getTable()->getPhpName().'Behaviors'; 
     358      $behavior_file_path = $this->getFilePath($this->getStubObjectBuilder()->getPackage().'.om.'.$behavior_file_name); 
     359      $script .= sprintf("\n\ninclude_once '%s';\n", $behavior_file_path); 
     360    } 
     361  } 
    349362} 
  • branches/1.1/lib/plugins/sfPropelPlugin/lib/propel/builder/SfPeerBuilder.php

    r6970 r7394  
    382382    $script .= $tmp; 
    383383  } 
     384   
     385  protected function addClassClose(&$script) 
     386  { 
     387    parent::addClassClose($script); 
     388 
     389    $behavior_file_name = 'Base'.$this->getTable()->getPhpName().'Behaviors'; 
     390    $behavior_file_path = $this->getFilePath($this->getStubObjectBuilder()->getPackage().'.om.'.$behavior_file_name); 
     391    $absolute_behavior_file_path = sfConfig::get('sf_root_dir').'/'.$behavior_file_path; 
     392     
     393    if(file_exists($absolute_behavior_file_path)) 
     394    { 
     395      unlink($absolute_behavior_file_path); 
     396    } 
     397     
     398    $behaviors = $this->getTable()->getAttribute('behaviors'); 
     399    if($behaviors) 
     400    { 
     401      file_put_contents($absolute_behavior_file_path, sprintf("<?php\nsfPropelBehavior::add('%s', %s);\n", $this->getTable()->getPhpName(), var_export(unserialize($behaviors), true))); 
     402      $script .= sprintf("\n\ninclude_once '%s';\n", $behavior_file_path); 
     403    } 
     404  } 
    384405} 
  • branches/1.1/lib/plugins/sfPropelPlugin/lib/propel/sfPropelDatabaseSchema.class.php

    r6970 r7394  
    33/* 
    44 * This file is part of the symfony package. 
    5  * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com> 
     5 * (c) Fabien Potencier <fabien.potencier@symfony-project.com> 
     6 * (c) Francois Zaninotto <francois.zaninotto@symfony-project.com> 
    67 * 
    78 * For the full copyright and license information, please view the LICENSE 
     
    2728  } 
    2829 
     30  public function loadArray($schema_array) 
     31  { 
     32    $database = array(); 
     33    $connection_name = ''; 
     34 
     35    if (isset($schema_array['classes'])) 
     36    { 
     37      // New schema syntax 
     38      $schema_array = $this->convertNewToOldYaml($schema_array); 
     39    } 
     40 
     41    if (count($schema_array) > 1) 
     42    { 
     43      throw new sfException('A schema.yml must only contain 1 database entry.'); 
     44    } 
     45 
     46    $tmp = array_keys($schema_array); 
     47    $connection_name = array_shift($tmp); 
     48 
     49    if ($connection_name) 
     50    { 
     51      $database = $schema_array[$connection_name]; 
     52    } 
     53 
     54    $this->connection_name = $connection_name; 
     55    $this->database = $database; 
     56     
     57    $this->fixYAMLDatabase(); 
     58    $this->fixYAMLI18n(); 
     59    $this->fixYAMLColumns(); 
     60  } 
     61   
    2962  public function loadYAML($file) 
    3063  { 
    31     $schema = sfYaml::load($file); 
    32  
    33     if (count($schema) > 1) 
    34     { 
    35       throw new sfException('A schema.yml must only contain 1 database entry.'); 
    36     } 
     64    $schema_array = sfYaml::load($file); 
     65     
     66    if (!isset($schema_array['classes'])) 
     67    { 
     68      // Old schema syntax: we convert it  
     69      $schema_array = $this->convertOldToNewYaml($schema_array); 
     70    } 
     71     
     72    $this->loadArray($schema_array); 
     73  } 
     74   
     75  public function convertOldToNewYaml($schema) 
     76  { 
     77    $new_schema = array(); 
    3778 
    3879    $tmp = array_keys($schema); 
    39     $this->connection_name = array_shift($tmp); 
    40     if ($this->connection_name) 
    41     { 
    42       $this->database = $schema[$this->connection_name]; 
    43  
    44       $this->fixYAMLDatabase(); 
    45       $this->fixYAMLI18n(); 
    46       $this->fixYAMLColumns(); 
    47     } 
     80    $connection_name = array_shift($tmp); 
     81    $new_schema['connection'] = $connection_name; 
     82     
     83    $classes = array(); 
     84    foreach($schema[$connection_name] as $table => $table_params) 
     85    { 
     86      if ($table == '_attributes') 
     87      { 
     88        // Database attributes 
     89        $new_schema = array_merge($new_schema, $table_params); 
     90      } 
     91      else 
     92      { 
     93        // Table 
     94        $phpName = sfInflector::camelize($table); 
     95        if (isset($table_params['_attributes'])) 
     96        { 
     97          $table_attributes = $table_params['_attributes']; 
     98          unset($table_params['_attributes']); 
     99          if (isset($table_attributes['phpName'])) 
     100          { 
     101            $phpName = $table_attributes['phpName']; 
     102            unset($table_attributes['phpName']); 
     103          } 
     104        } 
     105        else 
     106        { 
     107          $table_attributes = array(); 
     108        } 
     109        $classes[$phpName] = $table_attributes; 
     110        $classes[$phpName]['tableName'] = $table; 
     111        $classes[$phpName]['columns'] = array(); 
     112        foreach($table_params as $column => $column_params) 
     113        { 
     114          switch($column) 
     115          { 
     116            case '_behaviors': 
     117              $classes[$phpName]['behaviors'] = $column_params; 
     118              break; 
     119            case '_foreignKeys': 
     120              $classes[$phpName]['foreignKeys'] = $column_params; 
     121              break; 
     122            case '_indexes': 
     123              $classes[$phpName]['indexes'] = $column_params; 
     124              break; 
     125            case '_uniques': 
     126              $classes[$phpName]['uniques'] = $column_params; 
     127              break; 
     128            default: 
     129              $classes[$phpName]['columns'][$column] = $column_params; 
     130          } 
     131        } 
     132      } 
     133    } 
     134     
     135    $new_schema['classes'] = $classes; 
     136     
     137    return $new_schema; 
     138  } 
     139   
     140  public function convertNewToOldYaml($schema) 
     141  { 
     142     
     143    if (isset($schema['connection'])) 
     144    { 
     145      $connection_name = $schema['connection']; 
     146      unset($schema['connection']); 
     147    } 
     148    else 
     149    { 
     150      $connection_name = 'propel'; 
     151    } 
     152     
     153    $database = array(); 
     154     
     155    // Tables 
     156    if (isset($schema['classes'])) 
     157    { 
     158      $tables = array(); 
     159      foreach ($schema['classes'] as $className => $classParams) 
     160      { 
     161        $tableParams = array();  
     162         
     163        // Columns 
     164        if (isset($classParams['columns'])) 
     165        { 
     166          $tableParams = array_merge($classParams['columns'], $tableParams); 
     167          unset($classParams['columns']); 
     168        } 
     169 
     170        // Indexes and foreign keys 
     171        if (isset($classParams['indexes'])) 
     172        { 
     173          $tableParams['_indexes'] = $classParams['indexes']; 
     174          unset($classParams['indexes']); 
     175        } 
     176        if (isset($classParams['uniques'])) 
     177        { 
     178          $tableParams['_uniques'] = $classParams['uniques']; 
     179          unset($classParams['uniques']); 
     180        } 
     181        if (isset($classParams['foreignKeys'])) 
     182        { 
     183          $tableParams['_foreignKeys'] = $classParams['foreignKeys']; 
     184          unset($classParams['foreignKeys']); 
     185        } 
     186         
     187        // Behaviors 
     188        if (isset($classParams['behaviors'])) 
     189        { 
     190          $tableParams['_behaviors'] = $classParams['behaviors']; 
     191          unset($classParams['behaviors']); 
     192        } 
     193         
     194        // Table attributes 
     195        $tableAttributes = array(); 
     196        if (isset($classParams['tableName'])) 
     197        { 
     198          $tableName = $classParams['tableName']; 
     199          unset($classParams['tableName']); 
     200        } 
     201        else 
     202        { 
     203          $tableName = sfInflector::underscore($className); 
     204        } 
     205         
     206        if (sfInflector::camelize($tableName) != $className) 
     207        { 
     208          $tableAttributes['phpName'] = $className; 
     209        } 
     210         
     211        if ($tableAttributes || $classParams) 
     212        { 
     213          $tableParams['_attributes'] = array_merge($tableAttributes, $classParams); 
     214        } 
     215         
     216        $tables[$tableName] = $tableParams; 
     217      } 
     218      $database = array_merge($database, $tables); 
     219      unset($schema['classes']); 
     220    } 
     221     
     222    // Database attributes 
     223    if ($schema) 
     224    { 
     225      $database['_attributes'] = $schema; 
     226    } 
     227     
     228    return array($connection_name => $database); 
    48229  } 
    49230 
     
    57238    foreach ($this->getChildren($this->database) as $tb_name => $table) 
    58239    { 
    59       $xml .= "\n  <table name=\"$tb_name\"".$this->getAttributesFor($table).">\n"; 
     240      $xml .= "\n  <table name=\"$tb_name\"".$this->getAttributesFor($table); 
     241      if (isset($table['_behaviors'])) 
     242      { 
     243        $xml .= sprintf(" behaviors=\"%s\"", htmlspecialchars(serialize($table['_behaviors']))); 
     244      } 
     245      $xml .= ">\n"; 
    60246 
    61247      // columns 
     
    226412              'required'      => true, 
    227413              'primaryKey'    => true, 
    228               'autoincrement' => true 
     414              'autoIncrement' => true 
    229415            ); 
    230416            $has_primary_key = true; 
     
    240426              $this->database[$table][$column] = array( 
    241427                'type'             => 'integer', 
    242                 'required'         => true, 
    243428                'foreignTable'     => $foreign_table, 
    244                 'foreignReference' => 'id', 
     429                'foreignReference' => 'id' 
    245430              ); 
    246431            } 
    247432            else 
    248433            { 
    249               throw new sfException(sprintf('Unable to resolve foreign table for column "%s"', $column)); 
     434              throw new sfException(sprintf('Unable to resolve foreign table for column "%s".', $column)); 
    250435            } 
    251436          } 
     437           
    252438        } 
    253439        else 
     
    280466          'required'      => true, 
    281467          'primaryKey'    => true, 
    282           'autoincrement' => true 
     468          'autoIncrement' => true 
    283469        ); 
    284470      } 
     
    313499    foreach ($this->getTables() as $tb_name => $table) 
    314500    { 
    315       if ((isset($table['_attributes']['phpName']) && $table['_attributes']['phpName'] == sfInflector::camelize($table_name)) || ($tb_name == $table_name)) 
     501      if ( 
     502           ($tb_name == $table_name) 
     503           || (isset($table['_attributes']['phpName']) &&  
     504             ( 
     505               $table['_attributes']['phpName'] == sfInflector::camelize($table_name)  
     506               || $table['_attributes']['phpName'] == $table_name 
     507             ) 
     508           || (sfInflector::underscore($table_name) == $tb_name))  
     509         ) 
    316510      { 
    317511        $table_match = $tb_name; 
     512        break; 
    318513      } 
    319514    } 
     
    329524      foreach ($column as $key => $value) 
    330525      { 
    331         if (!in_array($key, array('foreignTable', 'foreignReference', 'onDelete', 'onUpdate', 'index', 'unique'))) 
     526        if (!in_array($key, array('foreignClass', 'foreignTable', 'foreignReference', 'onDelete', 'onUpdate', 'index', 'unique', 'sequence'))) 
    332527        { 
    333528          $attributes_string .= " $key=\"".htmlspecialchars($this->getCorrectValueFor($key, $value))."\""; 
     
    338533    else 
    339534    { 
    340       throw new sfException(sprintf('Incorrect settings for column %s', $col_name)); 
     535      throw new sfException(sprintf('Incorrect settings for column "%s".', $col_name)); 
    341536    } 
    342537 
    343538    // conventions for foreign key attributes 
    344     if (is_array($column) && isset($column['foreignTable'])) 
    345     { 
    346       $attributes_string .= "    <foreign-key foreignTable=\"$column[foreignTable]\""; 
     539    if (is_array($column) && (isset($column['foreignTable']) || isset($column['foreignClass']))) 
     540    { 
     541      if (isset($column['foreignTable'])) 
     542      { 
     543        $attributes_string .= "    <foreign-key foreignTable=\"$column[foreignTable]\""; 
     544      } 
     545      else 
     546      { 
     547        $foreignTable = $this->findTable($column['foreignClass']); 
     548        if (!$foreignTable) 
     549        { 
     550          // Let's assume that the class given is from another schema 
     551          // We have no access to the other schema's phpNames 
     552          // So our last guess is to try to underscore the class name 
     553          $foreignTable = sfInflector::underscore($column['foreignClass']); 
     554        } 
     555        $attributes_string .= "    <foreign-key foreignTable=\"".$foreignTable."\""; 
     556      } 
     557       
    347558      if (isset($column['onDelete'])) 
    348559      { 
     
    659870      foreach ($columns as $column => $attributes) 
    660871      { 
    661         if ($column == 'id' && !array_diff($attributes, array('type' => 'integer', 'required' => 'true', 'primaryKey' => 'true', 'autoincrement' => 'true'))) 
     872        if ($column == 'id' && !array_diff($attributes, array('type' => 'integer', 'required' => 'true', 'primaryKey' => 'true', 'autoIncrement' => 'true'))) 
    662873        { 
    663874          // simplify primary keys 
     
    704915    foreach ($hash as $attribute => $value) 
    705916    { 
    706       $attributes[$attribute] = strval($value)
     917      $attributes[$attribute] = (string) $value
    707918    } 
    708919 
  • branches/1.1/lib/plugins/sfPropelPlugin/lib/task/sfPropelBaseTask.class.php

    r7333 r7394  
    9898 
    9999    $dbSchema = new sfPropelDatabaseSchema(); 
     100     
    100101    foreach ($schemas as $schema) 
    101102    { 
    102       $dbSchema->loadYAML($schema); 
     103      $schemaArray = sfYaml::load($schema); 
     104       
     105      if (!isset($schema_array['classes'])) 
     106      { 
     107        // Old schema syntax: we convert it  
     108        $schemaArray = $dbSchema->convertOldToNewYaml($schemaArray); 
     109      } 
     110 
     111      $customSchemaFilename = str_replace(array(sfConfig::get('sf_root_dir').DIRECTORY_SEPARATOR, 'plugins'.DIRECTORY_SEPARATOR, 'config'.DIRECTORY_SEPARATOR, DIRECTORY_SEPARATOR, 'schema.yml'), array('', '', '', '_', 'schema.custom.yml'), $schema); 
     112      $customSchemas = sfFinder::type('file')->name($customSchemaFilename)->in($dirs); 
     113       
     114      foreach ($customSchemas as $customSchema) 
     115      { 
     116        $this->dispatcher->notify(new sfEvent($this, 'command.log', array($this->formatter->formatSection('schema', sprintf('found custom schema %s', $customSchema))))); 
     117         
     118        $customSchemaArray = sfYaml::load($customSchema); 
     119        if (!isset($customSchemaArray['classes'])) 
     120        { 
     121          // Old schema syntax: we convert it  
     122          $customSchemaArray = $dbSchema->convertOldToNewYaml($customSchemaArray); 
     123        } 
     124        $schemaArray = sfToolkit::arrayDeepMerge($schemaArray, $customSchemaArray); 
     125      } 
     126 
     127      $dbSchema->loadArray($schemaArray); 
    103128 
    104129      $this->dispatcher->notify(new sfEvent($this, 'command.log', array($this->formatter->formatSection('schema', sprintf('converting "%s" to XML', $schema))))); 
  • branches/1.1/lib/plugins/sfPropelPlugin/test/unit/fixtures/schema.yml

    r3136 r7394  
    11propel: 
    2   some_table: 
    3     _attributes:    { phpName: SomeTable } 
    4     somechar:       { type: VARCHAR, size: 255, default: "This & That" } 
     2  _attributes:      { noXsd: false, defaultIdMethod: none, package: lib.model } 
     3  ab_group: 
     4    _attributes:    { phpName: Group, package: foo.bar.lib.model } 
     5    id: 
     6    name:           varchar(50) 
     7     
     8  cd_user: 
     9    _attributes:    { phpName: User, isI18N: true, i18nTable: cd_user_i18n } 
     10    first_name:     { type: varchar, size: 255, default: "Anonymous" } 
     11    last_name:      varchar(50) 
     12    age:            { type: integer, required: true, index: true } 
     13    ab_group_id: 
     14    created_at: 
     15   
     16  cd_user_i18n: 
     17    description:    longvarchar 
     18     
     19  ef_article: 
     20    title:          { type: longvarchar, required: true, index: unique } 
     21    stripped_title: { type: longvarchar, required: true, primaryKey: true, sequence: my_custom_sequence_name } 
     22    user_id: 
     23    my_group:       { type: integer, foreignTable: ab_group, foreignReference: id, onDelete: setnull } 
     24    my_other_group: { type: integer, foreignTable: ab_group, foreignReference: id, onDelete: setnull } 
     25    created_at:     timestamp 
     26    updated_at: 
     27 
     28  ij_article: 
     29    _attributes:    { phpName: Article } 
     30    title:          varchar(50) 
     31    user_id:        { type: integer } 
     32    _foreignKeys: 
     33      - 
     34        foreignTable: cd_user 
     35        onDelete:     cascade 
     36        references: 
     37          - { local: user_id, foreign: id } 
     38    created_at: 
     39    _indexes: 
     40      my_index:       [title, user_id] 
     41    _uniques: 
     42      my_other_index: [created_at] 
     43    _behaviors: 
     44      paranoid: { column: deleted_at } 
     45      act_as_nested_set: 
     46   
     47  ab_group_i18n: 
     48    motto:            longvarchar 
  • branches/1.1/lib/plugins/sfPropelPlugin/test/unit/sfPropelDatabaseSchemaTest.php

    r5105 r7394  
    33/* 
    44 * This file is part of the symfony package. 
    5  * (c) 2004-2006 Fabien Potencier <fabien.potencier@symfony-project.com> 
     5 * (c) Fabien Potencier <fabien.potencier@symfony-project.com> 
     6 * (c) Francois Zaninotto <francois.zaninotto@symfony-project.com> 
    67 *  
    78 * For the full copyright and license information, please view the LICENSE 
     
    1112require_once(dirname(__FILE__).'/../../../../../test/bootstrap/unit.php'); 
    1213 
    13 $t = new lime_test(1, new lime_output_color()); 
     14class my_lime_test extends lime_test 
     15
     16  public function is_array_explicit($test, $target, $prefix = '') 
     17  { 
     18    foreach ($test as $key => $value) 
     19    {  
     20      if (is_array($value))  
     21      { 
     22        $this->is_array_explicit($value, $target[$key], $prefix.' '.$key); 
     23      } 
     24      else 
     25      { 
     26        $this->is($value, $target[$key], sprintf('%s %s is %s', $prefix, $key, $value)); 
     27      } 
     28    } 
     29  } 
     30   
     31  public function is_line_by_line($exp1, $exp2) 
     32  { 
     33    $array_exp1 = explode("\n", $exp1); 
     34    $array_exp2 = explode("\n", $exp2); 
     35    $nb_lines = count($array_exp1); 
     36    for ($i=0; $i < $nb_lines; $i++)  
     37    {  
     38      if(!$array_exp1[$i]) continue; // Skip blank lines to avoid testing nothing 
     39      $this->is(trim($array_exp1[$i]), trim($array_exp2[$i]), sprintf('Line %d matches %s', $i, $array_exp1[$i])); 
     40    } 
     41  } 
     42
    1443 
     44require_once(dirname(__FILE__).'/../../../../../test/bootstrap/unit.php'); 
     45require_once(dirname(__FILE__).'/../../lib/propel/sfPropelDatabaseSchema.class.php'); 
     46require_once(dirname(__FILE__).'/../../../../util/sfInflector.class.php'); 
     47require_once(dirname(__FILE__).'/../../../../util/sfToolkit.class.php'); 
     48require_once(dirname(__FILE__).'/../../../../util/sfYaml.class.php'); 
     49 
     50$t = new my_lime_test(261, new lime_output_color()); 
     51 
     52$t->diag('Classical YAML to XML conversion'); 
    1553$p = new sfPropelDatabaseSchema(); 
    1654$p->loadYAML(dirname(__FILE__).'/fixtures/schema.yml'); 
    17 $t->like($p->asXML(), '/This &amp; That/'); 
     55$target = file_get_contents(dirname(__FILE__).'/fixtures/schema.xml'); 
     56$t->is_line_by_line($p->asXML(), $target); 
     57 
     58$t->diag('New YAML to XML conversion'); 
     59$p = new sfPropelDatabaseSchema(); 
     60$p->loadYAML(dirname(__FILE__).'/fixtures/new_schema.yml'); 
     61$target = file_get_contents(dirname(__FILE__).'/fixtures/schema.xml'); 
     62$t->is_line_by_line($p->asXML(), $target); 
     63 
     64$t->diag('New YAML to Old YAML conversion'); 
     65$old_yml_target = sfYaml::load(dirname(__FILE__).'/fixtures/schema.yml'); 
     66$p = new sfPropelDatabaseSchema(); 
     67$new_yml_transformed = $p->convertNewToOldYaml(sfYaml::load(dirname(__FILE__).'/fixtures/new_schema.yml')); 
     68$t->is_array_explicit($new_yml_transformed, $old_yml_target); 
     69 
     70$t->diag('Old YAML to New YAML conversion'); 
     71$new_yml_target = sfYaml::load(dirname(__FILE__).'/fixtures/new_schema.yml'); 
     72$p = new sfPropelDatabaseSchema(); 
     73$old_yml_transformed = $p->convertOldToNewYaml(sfYaml::load(dirname(__FILE__).'/fixtures/schema.yml')); 
     74$t->is_array_explicit($old_yml_transformed, $new_yml_target); 
     75 
     76 
     77$t->todo('XML and classical YAML internal representation'); 
     78$p1 = new sfPropelDatabaseSchema(); 
     79$p1->loadXML(dirname(__FILE__).'/fixtures/schema.xml'); 
     80$p2 = new sfPropelDatabaseSchema(); 
     81$p2->loadYAML(dirname(__FILE__).'/fixtures/schema.yml'); 
     82//$t->is_array_explicit($p1->asArray(), $p2->asArray()); 
     83 
     84$t->todo('XML and classical YAML compared as XML'); 
     85//$t->is_line_by_line($p1->asXML(), $p2->asXML()); 
     86 
     87$t->todo('XML and classical YAML compared as YAML'); 
     88//$t->is_line_by_line($p1->asYAML(), $p2->asYAML());