WindowsにMODX Evolutionをインストールしてみた

|[../](https://qiita.com/taconana/items/3f5424f9abfc755772c2) |
|---|

WordPressと似たようなCMS(Contents Management System)であるMODX Evolution 1.0.25JをWindows環境にインストールしてみた。

## MODX のインストール
(1) https://modx.jp/download/download_evo.html から evo-1.0.25J.zip をダウンロードし、展開し、一式をPleiadesのワークスペースに配置する。WordPressとの比較のために同じ箇所に配置してみた。
```
C:\pleiades-xxx\xampp\htdocs
 +-- samples			// PHPのプロジェクトなど
 +-- wp					// WordPress
 +-- modx				// 今回インストールしたMODX
```

そして、Eclipseにmodxプロジェクトを作成しておく。PHPプロジェクトをmodxという名前で新規作成し、上記のディレクトリを指定すればよい。


(2) セットアップ前にMySQLにMODX用のデータベースとユーザーを作成しておく必要がある。WordPressと同じような手順だ。
```
データベースホスト（サーバー）名：	localhost
データベースユーザ名: 			modxadmin
データベースパスワード: 			xxx
データベース名 : 					modx
```
以下のように作成しておくこと。
```sql
# mysql -uroot -p mysql
Enter password: ***
> create database modx;
> show databases;
> create user 'modxadmin'@'localhost' identified by 'xxx';       // modxadmin追加
> grant all privileges on modx.* TO 'modxadmin'@'localhost';     // modxadminの権限
> flush privileges;
> select user,host from user;
> exit;

# mysql -umodxadmin -p modx
Enter password: xxx
> show tables;
Empty set (0.00 sec)
```
(3) http://localhost/modx/ にアクセスするとインストーラが動く。「MODXのインストールを開始します」の画面が出たら、ウィザードに従って進める。インストールが終了すると、ログイン画面に遷移するので管理アカウント(admin)で入る。ダッシュボードが開く。
※MySQLにDBやユーザーが作成されていなかったり、正しくgrant設定できていないと、ウィザードに「進む」ボタンが現れない。grant設定を間違えていてもエラーが表示されず「進む」ボタンが現れないだけであり、ちょっと不親切な感じだった。
```
データベースホストへの接続
データベースホスト名:			localhost
データベース接続ログイン名:	modxadmin
データベース接続パスワード:	xxx
→ データベースホストとの接続テストの結果: 接続できます

利用するデータベースとTableプレフィックスの設定
データベース名:				modx
コレーション(照合順序):		utf8_general_ci
Tableプレフィックス:			modx_
→ データベースとTableプレフィックスのチェック: 問題ありません

デフォルトの管理アカウント作成
ログイン名(半角英数字):		admin
メールアドレス:				xxx@xxx.com
パスワード:					xxx
パスワード(確認入力):			xxx
```

## Apache httpの起動
XAMPP Control PanelからApacheを起動する。EclipseのサーバーからPHPビルトインサーバーを起動する競合するので、Eclipseのサーバーは停止しておくこと。Apacheを使わずに、PHPビルトインサーバーで利用しようとすると、いろいろ問題があるようだ。実質的に使えない。XAMPP Control PanelからApacheを起動して80番ポートで利用すること。


## 「Home」でゼロ割のエラーが出た
Modxのダッシュボードは、ツリーがエクスプローラ風であり、親しめる感じ。しかし「Home」をクリックするといきなりエラーが出た。
※再インストールしたら、この現象は起きなくなっていた。
```
MODX encountered the following error while attempting to parse the requested resource:
« PHP Parse Error »
PHP error debug
Error : Division by zero
ErrorType[num] :	WARNING[2]
File :	C:\pleiades-xxx\xampp\htdocs\modx\manager\includes\extenders\ex_maketable.php
Line :	342
```
ゼロ割のようなので、とりあえず回避するように修正した。
```php:manager/includes/extenders/ex_maketable.php:342
	if ($this->pageLimit == 0){
	  return '';
	}
	$totalPages = ceil($totalRecords / $this->pageLimit);
```
## DBへのアクセスをトレースしてみる
どのようなSQLが実行されているか見たかったので、以下のようにerror_log('@@@')を挟み込んでトレースした。デバッグに使える。242行目あたり。
```php:manager/includes/extenders/dbapi/mysqli.inc.php:242
    function query($sql, $watchError = true) {
        ...
        $result = $this->conn->query($sql);
        // TODO --------------------
        error_log('@@@ ' . $sql . ' --> ' . $result->num_rows);
        // TODO --------------------
        if (!$result) {
        ...
        return $result;
    }
```
## 「サイトを表示」でエラーになる
「サイトを表示」を選ぶと、以下のエラーが出る。このエラーの解決には結構時間がかかった。ネット上では同じ問題に遭遇している方もあるようだ。
```
Parse error: syntax error, unexpected '\' (T_NS_SEPARATOR), expecting ')' 
in C:\pleiades-xxx\xampp\htdocs\modx\manager\includes\document.parser.class.inc.php(2401) : eval()'d code on line 1
```
2401行目は、eval('?>' . $content)している行である。var_dumpしてみると文字列置換がうまくいってないようだった。おそらく、BootstrapのテンプレートとしてDBに登録されたHTMLで、改行(`\n`)とシングルクォートのエスケープ(`\'`)およびダブルクォートのエスケープ(`\"`)が置換できていない。str_replaceを3つ挟んだら、とりあえずエラーは消えた。
※ちなみにもう1つのテンプレートMinimal Templateは、問題ないようだ。Bootstrapのテンプレートも「エレメント管理 -> テンプレート編集」から編集しなおしてDBに再保存すれば、3つのstr_replaceは不要になると思われる。
※この現象は、再インストールしても同様に起きた。Bootstrapのテンプレートを修正しておけば、3つのstr_replaceは不要である。
```php:manager/includes/document.parser.class.inc.php:2401
    ob_start();
    eval('?>' . $content);				// 2401行目
    $content = ob_get_clean();
↓
	// TODO ---------------------
    // var_dump($content);
    $content = str_replace("\\n", ' ', $content);
    $content = str_replace("\\'", '\'', $content);
    $content = str_replace('\\"', '"', $content);
    // TODO ---------------------
    ob_start();
    eval('?>' . $content);
    $content = ob_get_clean();
```
このような修正でいいのかは不明。やたらと、str_replaceの多いコードのようだ。パフォーマンス的に大丈夫なのかな。

## 新着情報の作成日(createdon)が出ない

新着情報の一覧に作成日(createdon)が出ないようだ。以下のようなスクリプトになっている。WordPressでのショートコードに相当するものを、MODXではスニペットと呼んでいる。`[[xxx]]`などで挟んで表現する。publishedon、createdon、pagetitleは、modx_site_contentテーブルのカラム名である。検索したニュース（publishedonでソートしたもの）のcreatedonとpagetitleを表示している。Dittoというプラグインを使用し、その中でプレースホルダ`[+url+]`などを使って差し込んでいる。詳細は、[MODXの独自タグ(エレメント)の使い方](https://qiita.com/taconana/items/f602f8b7d5d390e30443) を参照のこと。
※ちなみに createdon は created on 2022/06/30 などのように作成日を表現する。時分(秒)まで含める場合には、created at 2022/06/30 12:23 のように at を使うそうだ。
```html
<dl class="dl-horizontal">
[[Ditto?
&parents=2
&orderBy=publishedon
&tpl='@CODE:
<dt>[+createdon:date=`%Y年%-m月%-d日`+]</dt>
<dd><a href="[+url+]">[+pagetitle+]</a></dd>
'
]]
</dl>
```
DBには、値は入っているようだ。
```
> SELECT id,alias,isfolder,parent FROM `modx`.`modx_site_content` WHERE `parent` = "0";
+----+---------------+----------+--------+
| id | alias         | isfolder | parent |
+----+---------------+----------+--------+
|  1 | index         |        0 |      0 |
|  2 | news          |        1 |      0 |
|  3 | contact       |        1 |      0 |
|  4 | doc-not-found |        0 |      0 |
|  6 | feed.rss      |        0 |      0 |
|  8 | features      |        1 |      0 |
| 12 | geting-help   |        0 |      0 |
+----+---------------+----------+--------+

> SELECT DISTINCT sc.pagetitle,sc.parent,sc.id,sc.createdon FROM `modx`.`modx_site_content` sc
LEFT JOIN `modx`.`modx_document_groups` dg on dg.document = sc.id
WHERE sc.id IN (5,7) AND sc.published=1 AND sc.deleted=0
AND (sc.privateweb=0 ) GROUP BY sc.id;
+-----------------------------------------+--------+----+------------+
| pagetitle                               | parent | id | createdon  |
+-----------------------------------------+--------+----+------------+
| 新サービスのお知らせ　　　                 |      2 |  5 | 1300505696 |
| サイトをオープンしました。                 |      2 |  7 | 1299728096 |
+-----------------------------------------+--------+----+------------+
```
DBには2件のニュースが入っていて、createdonも保持している。ちょっと調べてみたが、検索のSQLにcreatedonのカラムが漏れている。
※ちなみに`$TVs`はテレビではない。Template Variablesの略らしい。
```php:assets/snippets/ditto/snippet.ditto.php:1296
    $dbFields[] = 'createdon'; 			// TODO 暫定で追記してみた。
    $resource = $ditto->getDocuments(
        $documentIDs,
        $dbFields,
        $TVs,
        $orderBy,
        $showPublishedOnly,
        0,
        $hidePrivate,
        $where,
        $queryLimit,
        $keywords,
        $randomize,
        $dateSource
    );
```
これで作成日(createdon)も検索できる。
```sql
SELECT DISTINCT sc.pagetitle,sc.parent,sc.id,sc.createdon FROM `modx`.`modx_site_content` sc
    LEFT JOIN `modx`.`modx_document_groups` dg on dg.document = sc.id
    WHERE sc.id IN (5,7) AND sc.published=1 AND sc.deleted=0 
    AND (sc.privateweb=0 ) GROUP BY sc.id;
```
以下の部分も影響しているように見える。 
```php:assets/snippets/ditto/classes/ditto.class.inc.php:291
function render($resource, $template, $removeChunk,$dateSource,$dateFormat,$ph=array(),$modifier_mode='normal',$x=0) {
    global $ditto_lang;
    if (!is_array($resource)) {
        return $ditto_lang['resource_array_error'];
    }
    $placeholders = array();
    $contentVars = array();
    foreach ($resource as $name => $value) {
      $placeholders[$name] = $value;
      // $contentVars['[*' . $name . '*]'] = $value;// この記述が間違っているのではないか。
      $contentVars[$name] = '[*' . $name . '*]';	// こんな風に書きたいのではないか。
    }            
```
この状態で [+createdon:date+] で作成日が「2011/03/19」のような書式で入るようになった。それでもまだ、[+createdon:date=`%Y年%-m月%-d日`+] だと機能しない。書式変換はさらに別の箇所も修正しないとダメなのかもしれない。
![modx-createdon.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/39200/d2982a36-f241-264f-4b5c-4594b9c42f8f.png)

|[../](https://qiita.com/taconana/items/3f5424f9abfc755772c2) |
|---|