Development

#7220 ([sfDoctrineRecordI18nFilter] Doctrine ResultCache not working with i18n behavior)

You must first sign up to be able to contribute.

Ticket #7220 (reopened defect)

Opened 5 years ago

Last modified 5 years ago

[sfDoctrineRecordI18nFilter] Doctrine ResultCache not working with i18n behavior

Reported by: ju1ius Assigned to: Jonathan.Wage
Priority: major Milestone:
Component: sfDoctrinePlugin Version: 1.3.x DEV
Keywords: doctrine cache i18n behavior Cc:
Qualification: Unreviewed

Description

Seems like sfDoctrineRecordI18nFilter can't find the Translation relation when Doctrine ResultCache? is enabled. See http://www.doctrine-project.org/jira/browse/DC-29

Error:

500 | Internal Server Error | Doctrine_Record_UnknownPropertyException
Unknown record property / related component "title" on "Article"

schema.yml:

Article:
  actAs:
    Timestampable:
    Sluggable:
      fields:   [date, title]
    I18n:
      fields:       [title, content]
      actAs:
        Sluggable:
          fields:   [title]
          uniqueBy: [lang, title]
  columns:
    title:          string(255)
    date:           date
    content:        clob

frontendConfiguration.class.php:

 function configureDoctrine(Doctrine_Manager $manager)
{
  if (sfConfig::get('sf_cache') == true)
  {
    $cacheDriver = new Doctrine_Cache_Apc();
    
    $manager->setAttribute(Doctrine::ATTR_QUERY_CACHE, $cacheDriver);
    $manager->setAttribute(
      Doctrine::ATTR_QUERY_CACHE_LIFESPAN,
      sfConfig::get('app_cache_lifetime', 86000)
    );
    $manager->setAttribute(Doctrine::ATTR_RESULT_CACHE, $cacheDriver);
    $manager->setAttribute(
      Doctrine::ATTR_RESULT_CACHE_LIFESPAN,
      sfConfig::get('app_cache_lifetime', 86000)
    );
  }
}

ArticleTable?.class.php

public function fetchAll()
{
  return Doctrine_Query::create()
    ->from('Article a')
    ->leftJoin('a.Translation t')
    ->orderby('a.date DESC')
    ->useQueryCache()->useResultCache()
    ->execute();
}

Change History

10/01/09 11:42:08 changed by ju1ius

  • owner changed from jwage to Jonathan.Wage.

(follow-up: ↓ 3 ) 11/24/09 15:02:21 changed by r3ap3r

I'm getting this exact same problem with my own caching plugin based on memcache. If I cache the Doctrine_Record object it gets serialized. I have set serializeReferences(true) for the object and I've verified that the Translation information is available inside the cached object (using a debugger). However when I do something like

$myobject->getTitle() or $myobject['title'] 

then it doesn't work (throwing the above mentioned exception).

This is a show stopper for me. Any guidance on how to turn a cached object back into a usable object (at least as far as i18n is concerned) would be greatly appreciated.

I should point out that I'm using Symfony 1.2.9-dev which doesn't match the version ju1ius set, but seems to be the exact same problem.

Thanks, -Chris

(in reply to: ↑ 2 ) 11/24/09 15:09:45 changed by r3ap3r

I assume this has something to do with line 688 in Record.php inside the serialize() function that says:

unset($vars['_filter']);

Although removing it just throws me into some crazy infinite loop (it may not be infinite, but my browser throws up at iteration 100).

I assume this ability is getting lost somewhere:

/**
   * Implementation of filterGet() to call get on Translation relationship to allow
   * access to I18n properties from the main object.
   *
   * @param Doctrine_Record $record
   * @param string $name Name of the property
   * @param string $value Value of the property
   * @return void
   */
  public function filterGet(Doctrine_Record $record, $name)
  {
    $culture = sfDoctrineRecord::getDefaultCulture();
    if (isset($record['Translation'][$culture]))
    {
      return $record['Translation'][$culture][$name];
    } else {
      $defaultCulture = sfConfig::get('sf_default_culture');
      return $record['Translation'][$defaultCulture][$name];
    }
  }

-Chris

Replying to r3ap3r:

I'm getting this exact same problem with my own caching plugin based on memcache. If I cache the Doctrine_Record object it gets serialized. I have set serializeReferences(true) for the object and I've verified that the Translation information is available inside the cached object (using a debugger). However when I do something like {{{ $myobject->getTitle() or $myobjecttitle? }}} then it doesn't work (throwing the above mentioned exception). This is a show stopper for me. Any guidance on how to turn a cached object back into a usable object (at least as far as i18n is concerned) would be greatly appreciated. I should point out that I'm using Symfony 1.2.9-dev which doesn't match the version ju1ius set, but seems to be the exact same problem. Thanks, -Chris

11/24/09 16:46:14 changed by Kris.Wallsmith

(In [24343]) [1.3, 1.4] added tests for sfDoctrineRecord (refs #7220, #7392)

11/25/09 16:33:51 changed by willou

I think I'm getting the same problem too.

The first time I get the page, all works. After (when there is a cache), It never works.

The error :

SQLSTATE[42S22]: Column not found: 1054 Unknown column 'i.nom' in 'field list'

The stack trace :

    * at ()
      in SF_SYMFONY_LIB_DIR/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Connection.php line 1082 ...
            1079.             $message .= sprintf('. Failing Query: "%s"', $query);
            1080.         }
            1081.
            1082.         $exc  = new $name($message, (int) $e->getCode());
            1083.         if ( ! isset($e->errorInfo) || ! is_array($e->errorInfo)) {
            1084.             $e->errorInfo = array(null, null, null, null);
            1085.         }
    * at Doctrine_Connection->rethrowException(object('PDOException'), object('Doctrine_Connection_Statement'))
      in SF_SYMFONY_LIB_DIR/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Connection/Statement.php line 269 ...
             266.         } catch (Doctrine_Adapter_Exception $e) {
             267.         }
             268.
             269.         $this->_conn->rethrowException($e, $this);
             270.
             271.         return false;
             272.     }
    * at Doctrine_Connection_Statement->execute(array('1'))
      in SF_SYMFONY_LIB_DIR/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Connection.php line 1006 ...
            1003.         try {
            1004.             if ( ! empty($params)) {
            1005.                 $stmt = $this->prepare($query);
            1006.                 $stmt->execute($params);
            1007.
            1008.                 return $stmt;
            1009.             } else {
    * at Doctrine_Connection->execute('SELECT i.id AS i__id, i.reference AS i__reference, i.art_code AS i__art_code, i.nom AS i__nom, i.commentaire AS i__commentaire, i.image AS i__image, i.marque_id AS i__marque_id, i.type AS i__type, i.article_type_id AS i__article_type_id, i.reference_fournisseur AS i__reference_fournisseur, i.historique AS i__historique, i.article_id AS i__article_id, i.reference_client AS i__reference_client, i.created_at AS i__created_at, i.updated_at AS i__updated_at FROM item i WHERE (i.marque_id = ? AND (i.type = 2))', array('1'))
      in SF_SYMFONY_LIB_DIR/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Query/Abstract.php line 976 ...
             973.             return $this->_conn->exec($query, $params);
             974.         }
             975.
             976.         $stmt = $this->_conn->execute($query, $params);
             977.
             978.         $this->_params['exec'] = array();
 979.
    * at Doctrine_Query_Abstract->_execute(array())
      in SF_SYMFONY_LIB_DIR/plugins/sfDoctrinePlugin/lib/vendor/doctrine/Doctrine/Query/Abstract.php line 1026 ...
            1023.                 $result = $this->_constructQueryFromCache($cached);
            1024.             }
            1025.         } else {
            1026.             $stmt = $this->_execute($params);
            1027.
            1028.             if (is_integer($stmt)) {
            1029.                 $result = $stmt;
    * at Doctrine_Query_Abstract->execute(array(), null)
      in SF_SYMFONY_LIB_DIR/plugins/sfDoctrinePlugin/lib/pager/sfDoctrinePager.class.php line 186 ...
             183.    */
             184.   public function getResults($hydrationMode = null)
             185.   {
             186.     return $this->getQuery()->execute(array(), $hydrationMode);
             187.   }
             188. }
 189.
    * at sfDoctrinePager->getResults()
      in n/a line n/a ...
    * at call_user_func_array(array(object('sfDoctrinePager'), 'getResults'), array())
      in SF_SYMFONY_LIB_DIR/escaper/sfOutputEscaperObjectDecorator.class.php line 64 ...
              61.       $escapingMethod = $this->escapingMethod;
              62.     }
              63.
              64.     $value = call_user_func_array(array($this->value, $method), $args);
              65.
              66.     return sfOutputEscaper::escape($escapingMethod, $value);
              67.   }
    * at sfOutputEscaperObjectDecorator->__call('getResults', array())
      in n/a line n/a ...
    * at sfOutputEscaperIteratorDecorator->getResults()
      in SF_ROOT_DIR/apps/administration/modules/marque/templates/_liste_produits.php line 14 ...
              11.     </tr>
              12.   </thead>
              13.   <tbody>
              14.     <?php foreach($pager->getResults() as $produit) : ?>
              15.     <tr>
              16.       <td><input type="checkbox" id="p<?php echo $produit->id ?>" /></td>
              17.       <td class="reference"><?php echo $produit->reference ?></td>
    * at require('/home/david/Zend/workspaces/DefaultWorkspace7/Plateforme Services 2/apps/administration/modules/marque/templates/_liste_produits.php')
      in SF_SYMFONY_LIB_DIR/view/sfPHPView.class.php line 78 ...
              75.     // render
              76.     ob_start();
              77.     ob_implicit_flush(0);
              78.     require($_sfFile);
              79.
              80.     return ob_get_clean();
              81.   }
    * at sfPHPView->renderFile('/home/david/Zend/workspaces/DefaultWorkspace7/Plateforme Services 2/apps/administration/modules/marque/templates/_liste_produits.php')
      in SF_SYMFONY_LIB_DIR/view/sfPartialView.class.php line 110 ...

My version :

$ ./symfony --version
symfony version 1.3.0-DEV (/*****/_symfonys/1.3/lib)

(from svn and up to date).

I'm using multiple connection, databases.yml :

all:
  db2:
    class: sfDoctrineDatabase
    param:
      dsn: 'mysql:host=localhost;dbname=db2'
      username: username2
      password: ***
  db1:
    class: sfDoctrineDatabase
    param:
      dsn: 'mysql:host=localhost;dbname=db1'
      username: username1
      password: ***

The model :

connection: pfs2
actAs: [Timestampable]
options:
  type: INNODB
  collate: utf8_unicode_ci
  charset: utf8

Item:
  actAs:
    Timestampable:
    I18n:
      fields: [nom]
  columns:
    reference: string(255)
    art_code: string(50)
    nom: string(255)
    commentaire: clob
    image: string(255)
    marque_id: integer
  relations:
    ItemNomenclatures:
      type: many
      class: ItemNomenclature
      local: id
      foreign: item_id
      onDelete: cascade
    Nomenclatures:
      class: Nomenclature
      local: item_id
      foreign: nomenclature_id
      refClass: ItemNomenclature
    Marque:
      local: marque_id
      foreign: id
    Reseaux:
      class: Reseau
      local: item_id
      foreign: reseau_id
      refClass: ItemReseau
    ItemReseaux:
      type: many
      class: ItemReseau
      local: id
      foreign: item_id

Article:
  inheritance:
    extends: Item
    type: column_aggregation
    keyField: type
    keyValue: 1
  columns:
    article_type_id: integer
    reference_fournisseur: string(255)
    historique: clob
    article_id: integer
  relations:
    ArticleType:
      local: article_type_id
      foreign: id
    ArticleRemplacant:
      class: Article
      local: article_id
      foreign: id

Produit:
  inheritance:
    extends: Item
    type: column_aggregation
    keyField: type
    keyValue: 2
  columns:
    reference_client: string(255)

[...]

As you can see, 'nom' is a translated field.

I'll hope all theses elements will help you to fix this or to help me to find another way.

11/30/09 22:46:43 changed by Jonathan.Wage

  • status changed from new to closed.
  • resolution set to worksforme.

This is working for me in symfony 1.3/1.4 and Doctrine 1.2. I added some test coverage for it as well.

12/15/09 15:27:16 changed by wgohier

  • status changed from closed to reopened.
  • resolution deleted.

I always have this problem with Symfony 1.3.x (as willou) Unknown record property / related component "name" on "Game"

I can only have fulltime access to i18n data through Translation?[$sf_user->getCulture()]name? ... but doesn't work with ->getName()

First access, it works than i refresh and it doesn't work anymore, until i do a clear-cache and refresh.

I can avoid this effect by activating file cache (in cache.yml) but i can't cache everything in my application.

The problem appeared when i stated to use ->useQueryCache()->useResultCache() on my Doctrine_Queries (for optimization).

I use custom query like this (in a function of my class : GameTable? extends Doctrine_Table)

$this->createQuery('g') ->select('g.*, t.*, u.*') ->addSelect('AVG(gr.rate) as average_rate') ->innerJoin('g.Translation t') ->leftJoin('g.GameRating? gr');

I don't know if it's a Doctrine or Symfony problem. Could you help me please ?

12/15/09 15:37:57 changed by wgohier

Please delete my previous post

I always have this problem with Symfony 1.3.x (as willou)

Unknown record property / related component "name" on "Game"

I can only have fulltime access to i18n data through $game['Translation'][$sf_user->getCulture()]['name'] ... but doesn't work with $game->getName()

First access, it works than i refresh and it doesn't work anymore, until i do a clear-cache and refresh.

I can avoid this effect by activating file cache (in cache.yml) but i can't cache everything in my application.

The problem appeared when i stated to use $q->useQueryCache()->useResultCache() on my Doctrine_Queries (for optimization).

I use custom query like this (in a function of my class - GameTable? extends Doctrine_Table)

$this->createQuery('g')  		
->select('g.*, t.*, u.*')
->addSelect('AVG(gr.rate) as average_rate')   	 	
->innerJoin('g.Translation t')
->leftJoin('g.GameRating gr');  

I don't know if it's a Doctrine or Symfony problem. Could you help me please ?

03/30/10 19:37:17 changed by Jonathan.Wage

It is a Doctrine problem and a sort of known issue. We have not been able to successful patch the problem yet.