Project

General

Profile

Bug(バグ) #4168

Updated by Youichi Kimura over 5 years ago

h3. Overview (概要)

SnsTerm の "複雑な使用例":https://github.com/openpne/OpenPNE3-doc/blob/master/cookbook/3.6/ja/use-sns-term-from-plugin.rst#%E8%A4%87%E9%9B%91%E3%81%AA%E4%BD%BF%E7%94%A8%E4%BE%8B に記載されている下記のようなコードが正しく動作せず、語形変化が適用されていない「friend」のまま出力される。

<pre><code class="php">
<?php echo __('%friend% are removed.', array('%friend%' => $op_term['friend']->pluralize()->fronting())); ?>
</code></pre>

この問題は #1759 における commit:9b2f55d8 の修正以降から発生している。

これにより、opDiaryPlugin の日記作成画面を英語で表示した際に「My Friends」と表示されるべき箇所が「my friend」と表示される状態になっている。

!{width:567px}スクリーンショット_2017-02-27_18.00.07.png!

h3. Causes (原因)

前提として、SnsTerm は以下のような性質を持っている。 バグが発生した原因を記入

# SnsTerm インスタンスに設定した語形変化は @SnsTerm::__toString()@ が呼ばれると初期状態に戻る
#* <pre><code class="php">
$term = Doctrine_Core::getTable('SnsTerm')->get('my_friend');
$term->titleize();

var_dump((string)$term); // "My Friend"
var_dump((string)$term); // "my friend"
</code></pre>
# SnsTerm インスタンスは SnsTermTable クラス内でキャッシュされる
#* <pre><code class="php">
$term = Doctrine_Core::getTable('SnsTerm')->get('my_friend');
$term->titleize();

// $term と同一のインスタンスが返る
$term2 = Doctrine_Core::getTable('SnsTerm')->get('my_friend');
var_dump((string)$term2); // "My Friend"
</code></pre>

それを踏まえて、@opI18N::__()@ メソッドの動作を追うと以下のようになる。

<pre><code class="php">
// 以下のように呼ばれる。期待する出力は「Friends are removed.」
echo __('%friend% are removed.', array('%friend%' => $op_term['friend']->pluralize()->fronting()));

....

// lib/i18n/opI18N.class.php
public function __($string, $args = array(), $catalogue = 'messages')
{
if (empty($this->parsed[$string])) // 初回の呼び出しでは true になる
{
$this->parsed[$string] = array();

$matches = array();
preg_match_all('/%([a-zA-Z_]+)%/', $string, $matches); // 「%friend%」がヒットする

array_shift($matches);

foreach ($matches as $match)
{
foreach ($match as $v)
{
if ($this->terms[$v])
{
$term = $this->terms[$v]; // 性質 2 より、語形変化が適用されたままのインスタンスが返る
if ($this->titleize) // デフォルトで false
{
$term = $term->titleize();
}

$this->parsed[$string]['%'.$v.'%'] = (string)$term; // ここで返るのは「Friends」
}
}
}
}

$parsedString = $this->parsed[$string];
if (is_array($args))
{
foreach ($args as $k => $v)
{
if ($v instanceof SnsTerm)
{
$args[$k] = (string)$v; // 性質 1 より、ここで返るのは「friend」
}
}
$parsedString = array_merge($parsedString, $args); // 「Friends」が「friend」に上書きされる
}

// 「friend are removed.」が出力される (不具合)
return parent::__($string, $parsedString, $catalogue);
}
</code></pre>

h3. Way to fix (修正内容)

#1759 の修正を一旦取り消し、上記のような SnsTerm の不具合が生じないように #1759 の修正を再度行う。 修正内容を記入

Back