Development

#2855 (Admin generated code creates fatal errors with CameCase table/columns)

You must first sign up to be able to contribute.

Ticket #2855 (new defect)

Opened 7 months ago

Admin generated code creates fatal errors with CameCase table/columns

Reported by: loopedcode Assigned to: fabien
Priority: major Milestone:
Component: other Version: 1.0.10
Keywords: Cc:
Qualification: Unreviewed

Description

Here are the steps to reproduce this defect. This has been tested on:
- Symfony 1.0.10
- mySQL 4.1.18 (this should not matter, the error will get generated regardless of database server version).

1. Create the mySQL database tables with following SQL:

CREATE TABLE `Info_Country` (
  `CountryID` smallint(6) NOT NULL auto_increment,
  `Name` varchar(50) NOT NULL default '',
  PRIMARY KEY  (`CountryID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;

INSERT INTO `Info_Country` (`CountryID`, `Name`) VALUES 
(1, 'USA'),
(2, 'Canada');

CREATE TABLE `Info_People` (
  `PeopleID` smallint(6) NOT NULL auto_increment,
  `CountryID` smallint(6) NOT NULL default '0',
  `Name` varchar(100) NOT NULL default '',
  PRIMARY KEY  (`PeopleID`),
  KEY `CountryID` (`CountryID`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 AUTO_INCREMENT=3 ;

INSERT INTO `Info_People` (`PeopleID`, `CountryID`, `Name`) VALUES 
(1, 1, 'Test User'),
(2, 2, 'User 1');

ALTER TABLE `Info_People`
  ADD CONSTRAINT `info_people_ibfk_1` FOREIGN KEY (`CountryID`) REFERENCES `info_country` (`CountryID`) ON UPDATE CASCADE;

2. Setup the propel.ini and database.yml for mySQL connection string.

3. Erase the default schema.yml in the config directory and then generate schema.xml from the database with the command: symfony propel-build-schema xml

4. Make sure you have set phpName attribute in schema.xml for all the tables and columns as shown here. Alternatively, you can just copy the schema.xml from below and save into your config directory.

Here is the generated schema.xml:

<?xml version="1.0" encoding="utf-8"?>
<!--Autogenerated by CreoleToXMLSchema!-->
<database name="propel">
  <table name="Info_Country" idMethod="native" phpName="Info_Country">
    <vendor type="mysql">
      <parameter name="Name" value="Info_Country"/>
      <parameter name="Engine" value="InnoDB"/>
      <parameter name="Version" value="9"/>
      <parameter name="Row_format" value="Dynamic"/>
      <parameter name="Rows" value="2"/>
      <parameter name="Avg_row_length" value="8192"/>
      <parameter name="Data_length" value="16384"/>
      <parameter name="Max_data_length" value=""/>
      <parameter name="Index_length" value="0"/>
      <parameter name="Data_free" value="0"/>
      <parameter name="Auto_increment" value="3"/>
      <parameter name="Create_time" value="2008-01-23 21:30:14"/>
      <parameter name="Update_time" value=""/>
      <parameter name="Check_time" value=""/>
      <parameter name="Collation" value="latin1_swedish_ci"/>
      <parameter name="Checksum" value=""/>
      <parameter name="Create_options" value=""/>
      <parameter name="Comment" value="InnoDB free: 7168 kB"/>
    </vendor>
    <column name="CountryID" type="SMALLINT" required="true" autoIncrement="true" primaryKey="true" phpName="CountryID">
      <vendor type="mysql">
        <parameter name="Field" value="CountryID"/>
        <parameter name="Type" value="smallint(6)"/>
        <parameter name="Null" value=""/>
        <parameter name="Key" value="PRI"/>
        <parameter name="Default" value=""/>
        <parameter name="Extra" value="auto_increment"/>
      </vendor>
    </column>
    <column name="Name" type="VARCHAR" size="50" required="true" default="" phpName="Name">
      <vendor type="mysql">
        <parameter name="Field" value="Name"/>
        <parameter name="Type" value="varchar(50)"/>
        <parameter name="Null" value=""/>
        <parameter name="Key" value=""/>
        <parameter name="Default" value=""/>
        <parameter name="Extra" value=""/>
      </vendor>
    </column>
  </table>
  <table name="Info_People" idMethod="native" phpName="Info_People">
    <vendor type="mysql">
      <parameter name="Name" value="Info_People"/>
      <parameter name="Engine" value="InnoDB"/>
      <parameter name="Version" value="9"/>
      <parameter name="Row_format" value="Dynamic"/>
      <parameter name="Rows" value="0"/>
      <parameter name="Avg_row_length" value="0"/>
      <parameter name="Data_length" value="16384"/>
      <parameter name="Max_data_length" value=""/>
      <parameter name="Index_length" value="16384"/>
      <parameter name="Data_free" value="0"/>
      <parameter name="Auto_increment" value="1"/>
      <parameter name="Create_time" value="2008-01-23 21:31:15"/>
      <parameter name="Update_time" value=""/>
      <parameter name="Check_time" value=""/>
      <parameter name="Collation" value="latin1_swedish_ci"/>
      <parameter name="Checksum" value=""/>
      <parameter name="Create_options" value=""/>
      <parameter name="Comment" value="InnoDB free: 7168 kB; (`CountryID`) REFER `bcdb_test/info_country`(`CountryID`) ON UPDATE CASCADE"/>
    </vendor>
    <column name="PeopleID" type="SMALLINT" required="true" autoIncrement="true" primaryKey="true" phpName="PeopleID">
      <vendor type="mysql">
        <parameter name="Field" value="PeopleID"/>
        <parameter name="Type" value="smallint(6)"/>
        <parameter name="Null" value=""/>
        <parameter name="Key" value="PRI"/>
        <parameter name="Default" value=""/>
        <parameter name="Extra" value="auto_increment"/>
      </vendor>
    </column>
    <column name="CountryID" type="SMALLINT" required="true" default="0" phpName="CountryID">
      <vendor type="mysql">
        <parameter name="Field" value="CountryID"/>
        <parameter name="Type" value="smallint(6)"/>
        <parameter name="Null" value=""/>
        <parameter name="Key" value="MUL"/>
        <parameter name="Default" value="0"/>
        <parameter name="Extra" value=""/>
      </vendor>
    </column>
    <column name="Name" type="VARCHAR" size="100" required="true" default="" phpName="Name">
      <vendor type="mysql">
        <parameter name="Field" value="Name"/>
        <parameter name="Type" value="varchar(100)"/>
        <parameter name="Null" value=""/>
        <parameter name="Key" value=""/>
        <parameter name="Default" value=""/>
        <parameter name="Extra" value=""/>
      </vendor>
    </column>
    <foreign-key foreignTable="Info_Country" onDelete="RESTRICT" onUpdate="CASCADE">
      <reference local="CountryID" foreign="CountryID"/>
    </foreign-key>
    <index name="CountryID">
      <index-column name="CountryID"/>
      <vendor type="mysql">
        <parameter name="Table" value="Info_People"/>
        <parameter name="Non_unique" value="1"/>
        <parameter name="Key_name" value="CountryID"/>
        <parameter name="Seq_in_index" value="1"/>
        <parameter name="Column_name" value="CountryID"/>
        <parameter name="Collation" value="A"/>
        <parameter name="Cardinality" value="0"/>
        <parameter name="Sub_part" value=""/>
        <parameter name="Packed" value=""/>
        <parameter name="Null" value=""/>
        <parameter name="Index_type" value="BTREE"/>
        <parameter name="Comment" value=""/>
      </vendor>
    </index>
  </table>
</database>

5. Create model with the command: symfony propel-build-model

6. Create an app called "admin": symfony init-app admin

7. Generate admin module called "people" for "Info_People" table under "admin" app:
symfony propel-init-admin admin people Info_People

8. Edit the generator.yml for "people" module to add one filter for "CountryID":

generator:
  class:              sfPropelAdminGenerator
  param:
    model_class:      Info_People
    theme:            default
    
    list:
     filters: 
      - CountryID

9. Write the toString() method for Info_Country:

public function __toString() 
{
  return $this->getName();
}

Now browse to the page /sandbox/web/admin_dev.php/people Everything should look fine; and the Country filter should be there.

Now Select a Country from the dropdown list and click on filter. This will reseult in PHP fatal error:

Fatal error: Undefined class constant 'COUNTRY_ID' in     /sandbox/cache/admin/dev/modules/autoPeople/actions/actions.class.php on line 185

actions.class.php line 185 crashes because of this:

$c->add(Info_PeoplePeer::COUNTRY_ID, $this->filters['country_id']);

The column names are getting underscore from /lib/symfony/generator/sfAdminGenerator.class.php around line 738:

 /**
   * Gets the name of the column.
   *
   * @return string The column name
   */
  public function getName()
  {
    return sfInflector::underscore($this->phpName);
  }

sfInflector::underscore converts CamelCase into underscore, and it is defined in /lib/symfony/util/sfInflector.class.php The function "uderscore" is defined as follows in sfInflector:

  /**
   * Returns an underscore-syntaxed version or the CamelCased string.
   *
   * @param string String to underscore.
   *
   * @return string Underscored string.
   */
  public static function underscore($camel_cased_word)
  {
    $tmp = $camel_cased_word;
    $tmp = str_replace('::', '/', $tmp);
    $tmp = sfToolkit::pregtr($tmp, array('/([A-Z]+)([A-Z][a-z])/' => '\\1_\\2',
                                         '/([a-z\d])([A-Z])/'     => '\\1_\\2'));

    return strtolower($tmp);
  }

Some suggestion for solution:
1. Specify naming requirements in documentation that all table/column names must be in lowercase underscore style.
or
2. Update logic so that admin generator does not blindly convert all CamelCase into underscore.