這似乎適合One-To-Many Bidirectional association。這是從該網頁翻譯成您的具體情況的方案:
/** @Entity */
class NavigationElement
{
// ...
/**
* @OneToMany(targetEntity="NavigationElementTranslation", mappedBy="navigationElement")
*/
private $translations;
// ...
public function __construct() {
$this->translations = new \Doctrine\Common\Collections\ArrayCollection();
}
}
/** @Entity */
class NavigationElementTranslation
{
// ...
/**
* @ManyToOne(targetEntity="NavigationElement", inversedBy="translations")
* @JoinColumn(name="navigation_element_id", referencedColumnName="id")
*/
private $navigationElement;
// ...
}
你可以添加一個getLabel($languageId)
方法,通過翻譯進行搜索,以獲取正確的標籤NavigationElement實體:
public function getLabel($languageId) {
foreach($this->translations as $trans) {
if($trans->languageId == $languageId)
return $trans->label;
}
throw new InvalidArgumentException();
}
,你可以使用下面的DQL,以確保您只想要翻譯裝入$translations
屬性:
$query = $em->createQuery(
"SELECT ne, net
FROM Entity\NavigationElement ne
JOIN ne.translations net WITH net.languageId = :langId"
);
$query->setParameter('langId', $languageId);
$navigationElements = $query->execute();
釷情況聽起來像是你想積極緩存的地方。確保你也看到Doctrine 2's caching機制。
此外,如果您發現用於翻譯的連接表開始變得難以管理,那麼國際化可以在PHP中用gettext合理處理。
對於這個非常好的解釋,我無法感謝你。我想我有一個問題,理解創建一個實體(翻譯)的需要,這個實體(本身)在我的域中沒有意義 - 但是當然,考慮到你提供的例子,我不直接訪問它,但透明,但元素本身。 – calumbrodie 2011-04-22 01:09:00
rojoca的回答相當不錯,但他的最後一句話也是一個很大的暗示。你的直覺是正確的:國際化(I18N)非常棘手,而且從你的領域抽象出這些東西通常會更好。gettext可以非常有用,還有其他機制。例如,ZF的Zend_Locale和Zend_Translate可以在框架之外使用。如果這是一個很大的項目,而且你需要做大量的翻譯工作(並且有時間),我會向後退一步,開始對i18n進行一些研究。 – timdev 2011-04-22 05:13:58
@timdev感謝您的評論。該項目的範圍只是(現在)模擬我們的系統運行的方式*現在*。謝天謝地,它不是很複雜,所以我的解決方案也不需要(我沒有試圖添加那些尚未存在的功能)而且你是對的 - 我對i18n的理解是非常有限的,儘管在這個特定情況下我只需要處理(一些)域對象名稱的簡單翻譯。我會看看你提到的軟件包以及symfony的本地化和國際化功能。 – calumbrodie 2011-04-22 09:18:46