Exact Model Property Names in Doctrine

    This article is devoted to the exact (case-sensitive) mapping of column names of the database table to the model properties. This problem is relevant for the first branch of ORM, because in the second branch, it seems to have already been resolved. But since the stable release at the moment is version 1.2.1 and version 2 is in the ALPHA4 stage, I think that this problem is relevant for many ORM users.

    If camelCase column names / aliases are not used in your project, then this solution will be irrelevant for you.


    While working with Doctrine, I had a problem. Many database columns had the name camelCase. And when receiving records, they turned into lowercase. At first I sinned on Mysql.
    Column, index, and stored routine names are not case sensitive on any platform, nor are column aliases . Trigger names are case sensitive, which differs from standard SQL.
    see Identifier-case-sensitivity

    From this it became clear that column aliases are still case-sensitive , and the essence of the problem is that Doctrine itself incorrectly (case insensitive) substitutes aliases for columns, making it strtolower (). Googling, came across this page . The bug is closed for the second branch. And for the first, strtolower () is automatically produced for the column names. It remains to find where ...


    Pieces of code were found quite quickly. This is Doctrine_Table -> setColumn (). There we see:
    $ name = strtolower ($ parts [0]);
    $ name = strtolower ($ name);

    It is they who are responsible for casting the column names to lower case. Now our task, without changing the ORM classes, is to make the column name case not change.
    First, create your own MyDoctrine_Table class, in which we override the setColumn () function and replace these sections of code.
    class MyDoctrine_Table extends Doctrine_Table

      public function setColumn($name, $type, $length = null, $options = array(), $prepend = false)
        if (is_string($options)) {
          $options = explode('|', $options);

        foreach ($options as $k => $option) {
          if (is_numeric($k)) {
            if ( ! empty($option)) {
              $options[$option] = true;

        // extract column name & field name
        if (stripos($name, ' as '))
          if (strpos($name, ' as ')) {
            $parts = explode(' as ', $name);
          } else {
            $parts = explode(' AS ', $name);

          if (count($parts) > 1) {
            $fieldName = $parts[1];
          } else {
            $fieldName = $parts[0];

          //$name = strtolower($parts[0]);
          $name = $parts[0];
        } else {
          $fieldName = $name;
          //$name = strtolower($name);

        $name = trim($name);
        $fieldName = trim($fieldName);

        if ($prepend) {
          $this->_columnNames = array_merge(array($fieldName => $name), $this->_columnNames);
          $this->_fieldNames = array_merge(array($name => $fieldName), $this->_fieldNames);
        } else {
          $this->_columnNames[$fieldName] = $name;
          $this->_fieldNames[$name] = $fieldName;

        if ($length == null) {
          switch ($type) {
            case 'integer':
              $length = 8;
            case 'decimal':
              $length = 18;
            case 'string':
            case 'clob':
            case 'float':
            case 'integer':
            case 'array':
            case 'object':
            case 'blob':
            case 'gzip':
              //$length = 2147483647;
              //All the DataDict driver classes have work-arounds to deal
              //with unset lengths.
              $length = null;
            case 'boolean':
              $length = 1;
            case 'date':
              // YYYY-MM-DD ISO 8601
              $length = 10;
            case 'time':
              // HH:NN:SS+00:00 ISO 8601
              $length = 14;
            case 'timestamp':
              // YYYY-MM-DDTHH:MM:SS+00:00 ISO 8601
              $length = 25;

        $options['type'] = $type;
        $options['length'] = $length;

        if ($prepend) {
          $this->_columns = array_merge(array($name => $options), $this->_columns);
        } else {
          $this->_columns[$name] = $options;

        if (isset($options['primary']) && $options['primary']) {
          if (isset($this->_identifier)) {
            $this->_identifier = (array) $this->_identifier;
          if ( ! in_array($fieldName, $this->_identifier)) {
            $this->_identifier[] = $fieldName;
        if (isset($options['default'])) {
          $this->hasDefaultValues = true;


    * This source code was highlighted with Source Code Highlighter.

    Then we include it in bootstrap.php, and register it as a Doctrine table class.

    // Убирает автоматический lowercase для столбцов таблицы
    require_once(dirname(__FILE__) . '/lib/doctrine_extra/MyDoctrine/Table.php');
    $conn->setAttribute(Doctrine::ATTR_TABLE_CLASS, 'MyDoctrine_Table');

    * This source code was highlighted with Source Code Highlighter.

    That’s it, now the name of the model properties completely coincides with the names of the table columns.

    Please do not judge strictly, if you have other options for solving this problem, I will be glad to hear them in the comments.

    Also popular now: