進歩のエンジン
ギャラリーはアルバムとアイテムで構成されています。 アルバムとアイテムの両方には、次のメインフィールドがあります。
- id
- タイトル
- 説明
- ファイル
タイトルと説明は、StoreView、つまりデータベース内のstore_idに依存する必要があることがわかります。 最初は別のstore_idフィールドを追加するオプションが最初にありましたが、最初に行ったように、このソリューションは単純にばかげていることがわかりました! 理由を説明します。
- 異なるStoreViewsのアルバムには異なるIDがありました(アイテムと同様)
- ユーザーは、各StoreViewに同じ画像をロードする必要があります(ファイルフィールド)
- その後、すべての言語に他の共通フィールドを追加する必要がある場合、画像と同様の問題が発生する可能性があります
悪くはないようですが、エンドユーザー向けではありません。
フリークアイデア
私は最近Symfony1.4 + Doctrine1.2をよく使うので、長い間解決策を探す必要はありませんでした。 Doctrine I18nの動作に似た機能をMagentoに実装することにしました。
なんで?
しかし、それは便利でシンプルだからです! さらに、これを実装する標準機能が見つかりませんでした。 EAVを介してすべてを実行するというアイデアがありましたが(entity_type、属性、およびそこに必要な他のすべてを作成します)、私にとっては-複雑でわかりにくいです。
このソリューションの魅力は、同じで外部APIに残っているコレクションとモデルですが、複数のStoreViewのデータを保存および共有することを考慮する必要がないことです。
安くて陽気な
実装自体は、Sourceモデル(コレクションとモデル自体)の抽象化の別のレイヤーを作成することです。 そして、複数のStoreViewのデータの保存と操作を実装する必要がある場合、それらから単純に継承します。
クラス自体は次のとおりです。
-アプリ/コード/ローカル/ Sj /ギャラリー/モデル/ Mysql4 / Translation.php
abstract class Sj_Gallery_Model_Mysql4_Translation extends Mage_Core_Model_Mysql4_Abstract
{
const TABLE_SUFIX = '_translation' ;
protected
$_translatableFields = array();
/**
* Standard resource model initialization
*
* @param string $mainTable
* @param string $idFieldName
* @return Mage_Core_Model_Mysql4_Abstract
*/
protected function _init($mainTable, $idFieldName)
{
if (empty($ this ->_translatableFields)) {
throw new Exception( 'You must specify translatable fields' );
}
$ this ->_setMainTable($mainTable, $idFieldName);
}
/**
* Retrieve select object for load object data
*
* @param string $field
* @param mixed $value
* @return Zend_Db_Select
*/
protected function _getLoadSelect($field, $value, $ object )
{
$tableName = $ this ->getMainTable();
$select = parent::_getLoadSelect($field, $value, $ object );
$select->joinLeft(
array( 'trnslt' => $ this ->getTranslationTableName()),
'trnslt.id = ' . $tableName . '.' . $field . '
AND trnslt.store_id = ' . ( int )$ object ->getStoreId(),
$ this ->getTranslatableColumns()
);
return $select;
}
/**
* Set multilang field names
*
* @param array $fields
* @return Sj_Gallery_Model_Mysql4_Translation
*/
public function setTranslatableFields($fields)
{
if (!is_array($fields)) {
return false ;
}
$ this ->_translatableFields = $fields;
return $ this ;
}
/**
* Get multilang field names
*
* @return array
*/
public function getTranslatableFields()
{
return $ this ->_translatableFields;
}
/**
* Get multilang columns
*
* @return array
*/
public function getTranslatableColumns()
{
$columns = $ this ->getTranslatableFields();
$columns[ 'translation_id' ] = 'trnslt.id' ;
$columns[ 'store_id' ] = 'trnslt.store_id' ;
return $columns;
}
/**
* Get translation table name
*
* @return string
*/
public function getTranslationTableName()
{
return $ this ->getMainTable() . self::TABLE_SUFIX;
}
/**
* Save object object data
*
* @param Mage_Core_Model_Abstract $object
* @return Mage_Core_Model_Mysql4_Abstract
*/
public function save(Mage_Core_Model_Abstract $ object )
{
$adapter = $ this ->_getWriteAdapter();
$adapter->beginTransaction();
try {
$data = $ object ->getData();
$translations = array();
foreach ($ this ->_translatableFields as $field) {
if (isset($data[$field])) {
$translations[$field] = $data[$field];
unset($data[$field]);
}
}
$onDuplicate = array_keys($translations);
$translations[ 'id' ] = $ object ->getId();
$translations[ 'store_id' ] = $ object ->getStoreId();
$adapter->insertOnDuplicate(
$ this ->getTranslationTableName(),
$translations,
array_combine($onDuplicate, $onDuplicate)
);
parent::save($ object );
$adapter->commit();
return $ this ;
} catch (Exception $e) {
$adapter->rollBack();
throw $e;
}
}
}
*このソースコードは、 ソースコードハイライターで強調表示されました。
-アプリ/コード/ローカル/ Sj /ギャラリー/モデル/ Mysql4 /翻訳/ Collection.php
abstract class Sj_Gallery_Model_Mysql4_Translation_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
{
protected function _initSelect()
{
$tableName = $ this ->getResource()->getMainTable();
$ this ->getSelect()
->from(array( 'main_table' => $tableName))
->joinLeft(array( 'trnslt' => $ this ->getResource()->getTranslationTableName()),
'trnslt.id = main_table.' . $ this ->getResource()->getIdFieldName(),
$ this ->getResource()->getTranslatableColumns()
);
return $ this ;
}
public function addStoreToFilter(Mage_Core_Model_Store $store)
{
$ this ->addFieldToFilter( 'trnslt.store_id' , $store->getId());
return $ this ;
}
}
*このソースコードは、 ソースコードハイライターで強調表示されました。
練習する
すべてが非常に単純です。 以前は、ソースモデルを作成するとき、Sj_Gallery_Model_Mysql4_TranslationからMage_Core_Model_Mysql4_Abstractを継承する必要がありました。
また、モジュールのインストールファイルに翻訳用のテーブルを作成する必要があります。 1つのテーブルは、「_ translation」の別のサフィックスです(この値はクラス定数であり、変更できます)。
唯一かつ非常に重要な点は、loadメソッドを呼び出す前に、モデルにstore_idを常に設定する必要があるということです!
コレクションの使用例:
$collection = Mage::getModel( 'gallery/group' )->getCollection()
->addStoreToFilter(Mage::app()->getStore())
->addFieldToFilter( 'status' , 1)
->getItems();
* This source code was highlighted with Source Code Highlighter .
モデルの使用例:
$store = Mage::app()->getStore($request->getParam( 'store' ));
$group = Mage::getModel( 'gallery/group' )
->setStoreId($store->getId())
->load($id);
* This source code was highlighted with Source Code Highlighter .
インストールモジュールファイルギャラリーのソースコード:
$installer = $ this ;
$installer->startSetup();
$installer->run( "
CREATE TABLE {$this->getTable('gallery/gallery')} (
`gallery_id` int(11) unsigned NOT NULL AUTO_INCREMENT,
`filename` varchar(255) NOT NULL DEFAULT '',
`status` smallint(6) NOT NULL DEFAULT '0',
`created_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`gallery_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
" );
$installer->run( "
CREATE TABLE IF NOT EXISTS `{$this->getTable('gallery/group')}` (
`collection_id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`file` varchar(255) NOT NULL DEFAULT '',
`status` tinyint(4) NOT NULL,
`created_time` datetime DEFAULT NULL,
`update_time` datetime DEFAULT NULL,
PRIMARY KEY (`collection_id`),
KEY `gallery_group_idx` ( `collection_id` )
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
" );
$installer->run( "
CREATE TABLE `{$this->getTable('gallery/items_translation')}` (
`id` int(10) unsigned NOT NULL,
`title` varchar(255) NOT NULL DEFAULT '',
`description` varchar(20000) NOT NULL DEFAULT '',
`store_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`, `store_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
ALTER TABLE `{$this->getTable('gallery/items_translation')}`
ADD FOREIGN KEY (`id`) REFERENCES `{$this->getTable('gallery/gallery')}` (`gallery_id`)
ON DELETE CASCADE;
CREATE TABLE `{$this->getTable('gallery/group_translation')}` (
`id` int(10) unsigned NOT NULL,
`title` varchar(255) NOT NULL DEFAULT '',
`description` varchar(20000) NOT NULL DEFAULT '',
`store_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`, `store_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 ;
ALTER TABLE `{$this->getTable('gallery/group_translation')}`
ADD FOREIGN KEY (`id`) REFERENCES `{$this->getTable('gallery/group')}` (`collection_id`)
ON DELETE CASCADE;
" );
$installer->endSetup();
* This source code was highlighted with Source Code Highlighter .
ソースはここからダウンロードできます 。
PS:本格的な国際化機能を実装するという目標を設定しませんでした。 私は問題を解決したばかりで、移植性があり理解しやすいので解決策が気に入りました。 これは、マルチストアビューで透過的に動作するのに十分ですが、さらに改善することができます。 たとえば、すべてをモジュールの形で整理し、セットアップモデルを作成します。セットアップモデル自体が追加のテーブルを作成し、ストアに依存するフィールドの名前を構成に追加します。
この記事では、 ソースコードハイライターを使用してコードを強調表示しました。