1

ORM フレームワークの調査を行った後、初めて props を使用することにしました。キャッシング メカニズムの多対多の関係に取り組み始めるまで、すべてが完璧に機能していました。複数のキャッシュ タグが挿入されたキャッシュ エントリを取得するのに苦労した後 (トランザクションを使用し、すべてのオブジェクトを手動で永続化せずに ...)、特定のキャッシュ タグでキャッシュ エントリをクエリするという問題に直面しました。filterByTag の使用 (useTagQuery などの使用を引き起こす) は、常に例外で終了します。

Cannot fetch ColumnMap for undefined column: cache_id

原因となるコード:

/**
 * Drops all cache entries which are associated to the given tag
 * 
 * @param $tag string The tag to drop
 * @return void
 */
public function dropTag($tag) {
    $cTag = CacheTagQuery::create()->findOneByTag($tag);
    if($cTag instanceof CacheTag) {
        $cEntries = CacheQuery::create()->filterByTag($cTag)->find();
        foreach($cEntries as $cEntry) {
            if($cEntry instanceof Cache) {
                $cEntry->delete();
            }
        }
    }
}

schema.xml の関連部分:

<table name="tag">
    <column name="id" type="INTEGER" required="true" primaryKey="true" autoIncrement="true" />
    <column name="tag" type="VARCHAR" size="255" />
    <column name="type" type="INTEGER" inheritance="single">
        <inheritance key="1" class="Tag"/>
        <inheritance key="2" class="CacheTag" extends="Tag"/>
    </column>
    <behavior name="cachedrop" />
</table>
<table name="cache">
    <column name="id" type="INTEGER" required="true" primaryKey="true" autoIncrement="true" />
    <column name="crdate" type="TIMESTAMP" />
    <behavior name="timestampable">
        <parameter name="create_column" value="crdate" />
        <parameter name="disable_updated_at" value="true" />
    </behavior>
    <column name="lifetime" type="INTEGER" defaultValue="-1"  />
    <column name="name" type="VARCHAR" />
    <column name="content" type="CLOB" size="4294967296" required="true" />
</table>
<table name="cache_tag_mm" isCrossRef="true">
    <column name="cache_id" type="INTEGER" primaryKey="true" />
    <column name="tag_id" type="INTEGER" primaryKey="true" />
    <foreign-key foreignTable="cache">
        <reference local="cache_id" foreign="id"/>
    </foreign-key>
    <foreign-key foreignTable="tag">
        <reference local="tag_id" foreign="id"/>
    </foreign-key>
</table>

挿入するには、キャッシュ エントリを永続化する前に、各タグを手動で永続化する必要があります。

try {
        // create our new cache entry
    $cEntry = new Cache();
    $cEntry->setContent($content);
    $cEntry->setLifetime($lifetime);
    $cEntry->setName($cachetag);
    if(count($processedTags) > 0) {
        foreach($processedTags as $pTag) {
            $cTag = CacheTagQuery::create()->filterByTag($pTag)->findOneOrCreate();
            if($cTag->isNew()) {
                $cTag->save();
            }
            $cEntry->addTag($cTag);
        }
    }
        // finally persist the entry
    $cEntry->save();
} catch(Exception $e) {
    Logger::debugLog($e->getMessage());
}

開発環境:

PHP 5.3.15 with Suhosin-Patch (cli) (built: Aug 24 2012 17:45:44) Copyright (c) 1997-2012 The PHP Group Zend Engine v2.3.0, Copyright (c) 1998-2012 Zend Technologies with Zendデバッガー v5.2、Copyright (c) 1999-2009、Zend Technologies 著

アパッチ/2.2.22 (Unix)

propel ホームページの多対多の例 (http://propelorm.org/documentation/04-relationships.html#manytomany_relationships) でさえ、この問題を引き起こします。

アップデート

TagTableMap.php

class TagTableMap extends TableMap
{

    /**
     * The (dot-path) name of this class
     */
    const CLASS_NAME = 'orm.map.TagTableMap';

    /**
     * Initialize the table attributes, columns and validators
     * Relations are not initialized by this method since they are lazy loaded
     *
     * @return void
     * @throws PropelException
     */
    public function initialize()
    {
        // attributes
        $this->setName('tag');
        $this->setPhpName('Tag');
        $this->setClassname('Tag');
        $this->setPackage('orm');
        $this->setUseIdGenerator(true);
        $this->setSingleTableInheritance(true);
        // columns
        $this->addPrimaryKey('ID', 'Id', 'INTEGER', true, null, null);
        $this->addColumn('TAG', 'Tag', 'VARCHAR', false, 255, null);
        $this->addColumn('TYPE', 'Type', 'INTEGER', false, null, null);
        // validators
    } // initialize()

    /**
     * Build the RelationMap objects for this table relationships
     */
    public function buildRelations()
    {
        $this->addRelation('CacheTagMm', 'CacheTagMm', RelationMap::ONE_TO_MANY, array('id' => 'tag_id', ), null, null, 'CacheTagMms');
        $this->addRelation('Cache', 'Cache', RelationMap::MANY_TO_MANY, array(), null, null, 'Caches');
    } // buildRelations()

    /**
     *
     * Gets the list of behaviors registered for this table
     *
     * @return array Associative array (name => parameters) of behaviors
     */
    public function getBehaviors()
    {
        return array(
            'cachedrop' => array(),
        );
    } // getBehaviors()

} // TagTableMap

CacheTableMap.php

class CacheTableMap extends TableMap
{

    /**
     * The (dot-path) name of this class
     */
    const CLASS_NAME = 'orm.map.CacheTableMap';

    /**
     * Initialize the table attributes, columns and validators
     * Relations are not initialized by this method since they are lazy loaded
     *
     * @return void
     * @throws PropelException
     */
    public function initialize()
    {
        // attributes
        $this->setName('cache');
        $this->setPhpName('Cache');
        $this->setClassname('Cache');
        $this->setPackage('orm');
        $this->setUseIdGenerator(true);
        // columns
        $this->addPrimaryKey('ID', 'Id', 'INTEGER', true, null, null);
        $this->addColumn('CRDATE', 'Crdate', 'TIMESTAMP', false, null, null);
        $this->addColumn('LIFETIME', 'Lifetime', 'INTEGER', false, null, -1);
        $this->addColumn('NAME', 'Name', 'VARCHAR', false, 255, null);
        $this->addColumn('CONTENT', 'Content', 'CLOB', true, 4294967296, null);
        // validators
    } // initialize()

    /**
     * Build the RelationMap objects for this table relationships
     */
    public function buildRelations()
    {
        $this->addRelation('CacheTagMm', 'CacheTagMm', RelationMap::ONE_TO_MANY, array('id' => 'cache_id', ), null, null, 'CacheTagMms');
        $this->addRelation('Tag', 'Tag', RelationMap::MANY_TO_MANY, array(), null, null, 'Tags');
    } // buildRelations()

    /**
     *
     * Gets the list of behaviors registered for this table
     *
     * @return array Associative array (name => parameters) of behaviors
     */
    public function getBehaviors()
    {
        return array(
            'timestampable' => array('create_column' => 'crdate', 'update_column' => 'updated_at', 'disable_updated_at' => 'true', ),
        );
    } // getBehaviors()

} // CacheTableMap

CacheTagMmTableMap.php

class CacheTagMmTableMap extends TableMap
{

/**
 * The (dot-path) name of this class
 */
const CLASS_NAME = 'orm.map.CacheTagMmTableMap';

/**
 * Initialize the table attributes, columns and validators
 * Relations are not initialized by this method since they are lazy loaded
 *
 * @return void
 * @throws PropelException
 */
public function initialize()
{
    // attributes
    $this->setName('cache_tag_mm');
    $this->setPhpName('CacheTagMm');
    $this->setClassname('CacheTagMm');
    $this->setPackage('orm');
    $this->setUseIdGenerator(true);
    $this->setIsCrossRef(true);
    // columns
    $this->addPrimaryKey('ID', 'Id', 'INTEGER', true, null, null);
    $this->addForeignKey('CACHE_ID', 'CacheId', 'INTEGER', 'cache', 'ID', false, null, null);
    $this->addForeignKey('TAG_ID', 'TagId', 'INTEGER', 'tag', 'ID', false, null, null);
    // validators
} // initialize()

/**
 * Build the RelationMap objects for this table relationships
 */
public function buildRelations()
{
    $this->addRelation('Cache', 'Cache', RelationMap::MANY_TO_ONE, array('cache_id' => 'id', ), null, null);
    $this->addRelation('Tag', 'Tag', RelationMap::MANY_TO_ONE, array('tag_id' => 'id', ), null, null);
} // buildRelations()

} // CacheTagMmTableMap

例外バックトレース:

13 TableMap::getColumn("cache_id")  
12 TableMap::addRelation("CacheTagMm", "CacheTagMm", 2, array, NULL, NULL, "CacheTagMms")  
11 CacheTableMap::buildRelations()  
10 TableMap::getRelations()  
9 TableMap::getRelation("CacheTagMm")  
8 BaseCacheQuery::joinCacheTagMm(NULL, "LEFT JOIN")  
7 BaseCacheQuery::useCacheTagMmQuery()

アップデート

TableMaps をさらに掘り下げると、ビルドされた各 (Tag、Cache、CacheTagMm) buildRelations() 関数に間違ったコードが含まれていることがわかりました。4 番目の引数として渡された列マッピング配列で strtoupper() を実行して、これらの部分を編集しました。CacheTableMap の例:

public function buildRelations()
{
    $this->addRelation('Cache', 'Cache', RelationMap::MANY_TO_ONE, array('CACHE_ID' => 'ID', ), null, null);
    $this->addRelation('Tag', 'Tag', RelationMap::MANY_TO_ONE, array('TAG_ID' => 'ID', ), null, null);
} // buildRelations()

これで問題は解決しました!ただし、propel がそのようなファイルをビルドする理由がわかりません。schema.xml にエラーはありますか? デフォルトの命名方法に問題がありますか? 唯一の問題は、スキーマを編集してプロジェクトを再構築するたびに、これらのファイルを更新する必要があることです。Phing のバージョンを 2.4.5 にダウングレードしましたが (ドキュメントでは最小バージョンと記載されています)、何も変わりませんでした。ヒントはありますか?

4

1 に答える 1

1

生成されたファイルをpropelで変更しないことを強くお勧めします。そうしないと、スキーマで何かを変更するときに本当に頭痛の種になります。テーブル名の変更はpropelが自動的に行うものですが、生成されたテキストの何かを最初に変更しない限り、列マップによってエラーがスローされることはなく、propelをビルドしたときにエラーがスローされるはずです。定義している関係に問題があった場合。

新しいPropelディレクトリを生成してみて、新しく生成されたファイルを持っているものの上にドロップして、関係でエラーが発生するかどうかを確認することをお勧めします。次のような非常に単純なクエリを実行するだけです

    $collection = CacheQuery()::create()
          ->limit(1)
          ->findOne();

    $relationshipTest = $collection->getTag();

それでもエラーが発生するかどうかを確認します。生成されたファイル内の名前を変更し始めると、悪い方法になります。

propelのデフォルトの命名規則をオーバーライドする場合は、スキーマでphpname属性を使用できます。これにより、propelのデフォルトが任意の名前でオーバーライドされます(アンダースコアを保持する場合)。

于 2013-01-08T17:16:49.853 に答える