内蔵phxのidモディファイア使用時、記述先の違い(テンプレートかリソース)で挙動が異なる  【解決済み】

質問全般・改善要望
返信する
noka
メンバー
メンバー
記事: 94
登録日時: 2013年6月19日(水) 10:02

内蔵phxのidモディファイア使用時、記述先の違い(テンプレートかリソース)で挙動が異なる

投稿記事 by noka »

こんばんは。

内蔵Phxを使用すると、例えば、
[*pub_date:id=`10`:date=`%Y-%m-%d`*]
のように、別のリソースから値を参照するidモディファイアなどが利用でき、非常に便利です。このidモディファイア、実際の運用においてはid指定にスニペットを入れ子にするなど、何かしら処理を入れて使用することも多いと思います。

以下、これに関連したちょっとした不具合ですが、情報共有も兼ねて、ご報告させていただきます。


◎症状
--
idモディファイア内に入れ子するケースとして、

A:指定した数値から何か計算させてターゲットidを算出する場合
[*pagetitle:id=`[[hoge? &id=`5`]]`*]

B:$_GET値や配列名等からターゲットidを特定させたい場合
[*pagetitle:id=`[[hoge? &id=`docid`]]`*]

C:何かしらリソース変数からターゲットidを計算する場合
[*pagetitle:id=`[[hoge? &id=`[*parent*]`]]`*]

とか、いろいろあると思います。スニペットは自作だったりUltimateParentなど、戻り値が整数ならば何でも大丈夫のはずですね。
で、上記A〜C、いずれの場合もリソースとして書き込む場合にはきちんと動作するのですが、テンプレートに書き込むと、Cパターンしか通りません。
(1.0.14Jおよび1.0.14J-r3で確認)。


◎原因/ワークアラウンド
--
いろいろ試してみると、
[*pagetitle:id=`[[hoge? &id='5']]`*]
[*pagetitle:id=`[[hoge? &id='docid']]`*]
のように、入れ子パラメーターの囲み文字(デリミタ)をシングルクオートに変更してあげると、テンプレートでも機能するようになりました。ので、そのあたりの解釈処理にちょっとした不具合があるのかもしれません(スニペットの入れ子など他の場合には何重に入れ子してもきちんと動作しますので、たぶん内蔵Phxに限った話です)。

バッククオートが作法のように身に付いておりましたが、入れ子にする際には、「`」「"」「'」を使い分けるようにした方が、可読性も上がり良いのかもしれません(もしかして、当たり前なのですかね? 皆さんはどうされているのでしょうか)。


◎idが見つからない場合の問題
--
これに関連して、
[*pagetitle:id=`99999`*]
のように、「存在しないid」が指定された場合、404Document Not Found へリダイレクトしてしまいます。この場合の期待される動作は、空白orエラーテキストを返す感じでしょう。

1.0.14Jベースで確認しますと、この部分の処理は、
manager/includes/extenders/phx.parser.class.inc.php 566行目あたり。

コード: 全て選択

			$this->documentObject[$target] = $modx->getDocumentObject($method,$target,'phx');
としてidを引き渡しているのですが、呼ばれている
manager/includes/document.parser.class.inc.php のgetDocumentObject関数では、第3引数の'phx'が利用されていないため、idが見つからない場合には(管理画面なのか権限外かどうかのチェックのみで)一律にエラーページにリダイレクトする流れのようです。

ページを構成するパーツの場合にはリダイレクトしない方が望ましいので、例えば、manager/includes/document.parser.class.inc.php 1829行目あたり。

コード: 全て選択

			if ($this->isBackend()) return false;

コード: 全て選択

			if ($this->isBackend() || $mode!='direct') return false;
のようにしてあげると(もしくは$mode=='phx'でしょうか)、一応期待する挙動になりますけれど…参考ということで。

毎度、大したことでもないのに、説明が長くなってしまい恐縮です。
以上です。
アバター
yama
管理人
記事: 3236
登録日時: 2009年7月29日(水) 02:50

Re: 内蔵phxのidモディファイア使用時、記述先の違い(テンプレートかリソース)で挙動が異なる

投稿記事 by yama »

調査ありがとうございます、後ほど修正します。
アバター
yama
管理人
記事: 3236
登録日時: 2009年7月29日(水) 02:50

Re: 内蔵phxのidモディファイア使用時、記述先の違い(テンプレートかリソース)で挙動が異なる

投稿記事 by yama »

コード: 全て選択

if ($this->isBackend() || $mode!='direct') return false;
上記は if ($this->isBackend() || $mode==='direct') ではないでしょうか?
noka
メンバー
メンバー
記事: 94
登録日時: 2013年6月19日(水) 10:02

Re: 内蔵phxのidモディファイア使用時、記述先の違い(テンプレートかリソース)で挙動が異なる

投稿記事 by noka »

yama 様

あまり深くコードを追っていなかったのですが、

第三引数は、direct:直接呼ばれる(デフォルト)、phx:phx経由で呼ばれる、(などなど)

と理解しましたので、phx経由の場合(つまりdirectではないケース)が該当すると思いました。
1.0.14Jで軽く試したところ、期待通りの挙動ぽかったので、自信なさげに投稿させていただいた次第です。

呼び出し元のmanager/includes/extenders内
phx.parser.class.inc.php
を再度確認しますと、235行目あたりで、

コード: 全て選択

			#####  Resource fields
			case 'id':
				if($opt) $value = $this->getDocumentObject($opt,$phxkey,'direct');
				break;
と、'direct' を付けて呼んでいました。さらに、呼ばれている602行目あたりを確認しますと、

コード: 全て選択

	function getDocumentObject($target='',$field='pagetitle')
	{
		global $modx;
		
		$target = trim($target);
		if(empty($target)) $target = $modx->config['site_start'];
		if(preg_match('@^[1-9][0-9]*$@',$target)) $method='id';
		else $method = 'alias';

		if(!isset($this->documentObject[$target])) 
		{
			$this->documentObject[$target] = $modx->getDocumentObject($method,$target,'phx');
       (略)
となっていて、第三引数は利用されず、$modeに'phx'を指定して$modx->getDocumentObjectを呼んでいます。

なので、現状は若干整合性に欠けていて、$modeの仕様次第かと思われます(実質的には利用されていなかったようですけれども)。

お手数おかけしますが宜しくお願いいたします。
アバター
yama
管理人
記事: 3236
登録日時: 2009年7月29日(水) 02:50

Re: 内蔵phxのidモディファイア使用時、記述先の違い(テンプレートかリソース)で挙動が異なる  【解決済み】

投稿記事 by yama »

http://forum.modx.jp/viewtopic.php?p=7965#p7965
情報ありがとうございます。上記パッケージを試していただいてよいでしょうか?

https://github.com/modxcms-jp/evolution ... 5fa2327e64
今回はこのように対応しました
返信する