<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Groove Labo &#187; CMS</title>
	<atom:link href="http://labo.opengroove.com/blog/category/tools/cms/feed/" rel="self" type="application/rss+xml" />
	<link>http://labo.opengroove.com/blog</link>
	<description>株式会社オープングルーヴの開発者のブログ</description>
	<lastBuildDate>Wed, 30 Jun 2010 03:59:55 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>ja</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>MODxでsnippetを作る</title>
		<link>http://labo.opengroove.com/blog/2008/05/19/modx%e3%81%a7snippet%e3%82%92%e4%bd%9c%e3%82%8b/</link>
		<comments>http://labo.opengroove.com/blog/2008/05/19/modx%e3%81%a7snippet%e3%82%92%e4%bd%9c%e3%82%8b/#comments</comments>
		<pubDate>Mon, 19 May 2008 02:35:05 +0000</pubDate>
		<dc:creator>sugimoto</dc:creator>
				<category><![CDATA[CMS]]></category>
		<category><![CDATA[MODx]]></category>

		<guid isPermaLink="false">http://labo.opengroove.com/blog/index.php/2008/05/19/modx%e3%81%a7snippet%e3%82%92%e4%bd%9c%e3%82%8b/</guid>
		<description><![CDATA[
MODxのsnippetを使うと、コンテンツを管理、表示するための便利な機能を作ることができます。



snippetはMODx本体と同じように、PHPで書きます。zeera document searchのページで使う、「次のページへ」のリンクを作るsnippetを作りました。


modx オブジェクトの関数


modx オブジェクトはMODxがページを表示するときに必ず作成されるオブジェクトです。
DocumentParserクラスから作られます。DocumentParserクラスはドキュメントを表示する機能を提供するクラスですが、それ以外にも



データベースから任意のドキュメントを取ってくる
ドキュメントのパラメータの取得
プレースホルダーの作成



などのAPIを提供しています。たとえば、次のようなAPIがあります。



getParentIds($id, $height, $parent) : 親ドキュメントのIDをrecursiveに取得
getChildIds($id, $height, $children) : 子ドキュメントのIDをrecursiveに取得
getDocument($id, $fields, $published, $deleted) : ドキュメントを取得してarrayで返します。
getDocuments($id, $fields, $published, $deleted) : $id に一括取得するドキュメントのIDをarrayで指定します。
getActiveChildren($id, $sort, $dir, $fields) : 子ドキュメントを一括取得します。
makeURL($id, $alias, $args, $scheme) : フレンドリーURLを返します。
getPlaceholder($name) : プレースホルダーに設定された値を取得。
setPlaceholder($name, $value) : プレースホルダーを作ります。


snippetの作成


管理画面で、[リソース]->[リソース管理]->[スニペット]->[新規作成]で、snippetを作成します。



今回は[次へ]リンクを作成するためのDocumentPager snippetを作りました。



親IDが同じドキュメントのうち、指定したソート順で次(前)のドキュメントをプレースホルダーにします。



[[DocumentPager? &#038;sortBy='id' &#038;sortDir='ASC' &#038;returnId='xx']]
[+dpPrev+] [+dpNext+]



パラメータ



sortBy: 次、前のドキュメントを探す順番
sortDir: 次、前のドキュメントを探す順番
returnId: 最初と最後のドキュメントで[戻る]リンクの先ドキュメントID



作られるPlaceholder



[+dpPrevId+]: 前のドキュメントのID
[+dpPrevPagetitle+]: 前のドキュメントのページタイトル
[+dpPrevAlias+]: 前のドキュメントのAlias
[+dpPrevLink+]: 前のドキュメントへのリンク
[+dpNextId+]: 次のドキュメントのID
[+dpNextPagetitle+]: 次のドキュメントのページタイトル
[+dpNextAlias+]: 次のドキュメントのAlias
[+dpNextLink+]: 次のドキュメントのリンク


snippet


< [...]]]></description>
			<content:encoded><![CDATA[<p>
<a href="http://modxcms.com/" title="modxcms">MODx</a>のsnippetを使うと、コンテンツを管理、表示するための便利な機能を作ることができます。
</p>

<p>
snippetはMODx本体と同じように、PHPで書きます。<a href="http://search.opengroove.com/" title="zeera document search">zeera document search</a>のページで使う、「次のページへ」のリンクを作るsnippetを作りました。
</p>

<h3>modx オブジェクトの関数</h3>

<p>
modx オブジェクトはMODxがページを表示するときに必ず作成されるオブジェクトです。
DocumentParserクラスから作られます。DocumentParserクラスはドキュメントを表示する機能を提供するクラスですが、それ以外にも
</p>

<ul class="normal">
<li>データベースから任意のドキュメントを取ってくる</li>
<li>ドキュメントのパラメータの取得</li>
<li>プレースホルダーの作成</li>
</ul>

<p>
などのAPIを提供しています。たとえば、次のようなAPIがあります。
</p>

<ul class="normal">
<li>getParentIds($id, $height, $parent) : 親ドキュメントのIDをrecursiveに取得</li>
<li>getChildIds($id, $height, $children) : 子ドキュメントのIDをrecursiveに取得</li>
<li>getDocument($id, $fields, $published, $deleted) : ドキュメントを取得してarrayで返します。</li>
<li>getDocuments($id, $fields, $published, $deleted) : $id に一括取得するドキュメントのIDをarrayで指定します。</li>
<li>getActiveChildren($id, $sort, $dir, $fields) : 子ドキュメントを一括取得します。</li>
<li>makeURL($id, $alias, $args, $scheme) : フレンドリーURLを返します。</li>
<li>getPlaceholder($name) : プレースホルダーに設定された値を取得。</li>
<li>setPlaceholder($name, $value) : プレースホルダーを作ります。</li>
</ul>

<h3>snippetの作成</h3>

<p>
管理画面で、[リソース]->[リソース管理]->[スニペット]->[新規作成]で、snippetを作成します。
</p>

<p>
今回は[次へ]リンクを作成するためのDocumentPager snippetを作りました。
</p>

<p>
親IDが同じドキュメントのうち、指定したソート順で次(前)のドキュメントをプレースホルダーにします。
</p>

<pre>
[[DocumentPager? &#038;sortBy='id' &#038;sortDir='ASC' &#038;returnId='xx']]
[+dpPrev+] [+dpNext+]
</pre>

<p>
パラメータ
</p>

<ul class="normal">
<li>sortBy: 次、前のドキュメントを探す順番</li>
<li>sortDir: 次、前のドキュメントを探す順番</li>
<li>returnId: 最初と最後のドキュメントで[戻る]リンクの先ドキュメントID</li>
</ul>

<p>
作られるPlaceholder
</p>

<ul class="normal">
<li>[+dpPrevId+]: 前のドキュメントのID</li>
<li>[+dpPrevPagetitle+]: 前のドキュメントのページタイトル</li>
<li>[+dpPrevAlias+]: 前のドキュメントのAlias</li>
<li>[+dpPrevLink+]: 前のドキュメントへのリンク</li>
<li>[+dpNextId+]: 次のドキュメントのID</li>
<li>[+dpNextPagetitle+]: 次のドキュメントのページタイトル</li>
<li>[+dpNextAlias+]: 次のドキュメントのAlias</li>
<li>[+dpNextLink+]: 次のドキュメントのリンク</li>
</ul>

<h4>snippet</h4>

<pre>
< ?php
class DocumentPager {
    var $id, $sort, $dir, $return;
    function DocumentPager($sort = "id", $dir = "ASC", $returnId = null) {
        global $modx;
        $this-&gt;id = $modx-&gt;documentIdentifier;
        $this-&gt;sort = "id";
        $this-&gt;dir = "ASC";
        $this-&gt;returnId = $return;
        $this-&gt;getDocuments();
        $this-&gt;return = $modx-&gt;getDocument($returnId);
        $this-&gt;setPlaceholders();
    }
    function getDocuments() {
        global $modx;
        $parent = $modx-&gt;getParent();
        $docs = $modx-&gt;getActiveChildren($parent['id'], $this-&gt;sort, $this-&gt;dir);
        $found = false;
        for ($i = 0; $i &lt; count($docs); $i++) {
            if ($this-&gt;id == $docs[$i]['id']) {
                $this-&gt;next = $docs[$i + 1];
                break;
            }
            $this-&gt;prev = $docs[$i];
        }
    }
    function setPlaceholders() {
        global $modx;
        if ($this-&gt;prev != null) {
            $modx-&gt;setPlaceholder('dpPrevId', $this-&gt;prev['id']);
            $modx-&gt;setPlaceholder('dpPrevPagetitle', $this-&gt;prev['pagetitle']);
            $modx-&gt;setPlaceholder('dpPrevAlias', $this-&gt;prev['alias']);
            $prevLink = "&lt;a href='". $modx-&gt;makeUrl($this-&gt;prev['id']) ."'&gt;&#171; ". $this-&gt;prev['pagetitle'] ."&lt;/a&gt;";
            $modx-&gt;setPlaceholder('dpPrev', $prevLink);
        } elseif ($this-&gt;return) {
            $prevLink = "&lt;a href='". $modx-&gt;makeUrl($this-&gt;return['id']) ."'&gt;&#171; ". $this-&gt;return['pagetitle'] ."に戻る&lt;/a&gt;";
            $modx-&gt;setPlaceholder('dpPrev', $prevLink);
        }
        if ($this-&gt;next != null) {
            $modx-&gt;setPlaceholder('dpNextId', $this-&gt;next['id']);
            $modx-&gt;setPlaceholder('dpNextPagetitle', $this-&gt;next['pagetitle']);
            $modx-&gt;setPlaceholder('dpNextAlias', $this-&gt;next['alias']);
            $nextLink = "&lt;a href='". $modx-&gt;makeUrl($this-&gt;next['id']) ."'&gt;". $this-&gt;next['pagetitle'] ." &#187;&lt;/a&gt;";
            $modx-&gt;setPlaceholder('dpNext', $nextLink);
        } elseif ($this-&gt;return) {
            $nextLink = "&lt;a href='". $modx-&gt;makeUrl($this-&gt;return['id']) ."'&gt;". $this-&gt;return['pagetitle'] ."に戻る &#187;&lt;/a&gt;";
            $modx-&gt;setPlaceholder('dpNext', $nextLink);
        }
    }
}
new DocumentPager($sortBy, $sortDir, $returnId);
?>
</pre>

<h3>参考</h3>

<ul>
    <li><a href="http://wiki.modxcms.com/index.php/Creating_Snippets">Creating Snippets &#8211; MODx Wiki</a></li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://labo.opengroove.com/blog/2008/05/19/modx%e3%81%a7snippet%e3%82%92%e4%bd%9c%e3%82%8b/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>MODxのサイトをテスト環境から本番環境へコピーする</title>
		<link>http://labo.opengroove.com/blog/2008/04/21/modx%e3%81%a7staging%e7%92%b0%e5%a2%83%e3%81%8b%e3%82%89production%e7%92%b0%e5%a2%83%e3%81%b8/</link>
		<comments>http://labo.opengroove.com/blog/2008/04/21/modx%e3%81%a7staging%e7%92%b0%e5%a2%83%e3%81%8b%e3%82%89production%e7%92%b0%e5%a2%83%e3%81%b8/#comments</comments>
		<pubDate>Mon, 21 Apr 2008 01:56:02 +0000</pubDate>
		<dc:creator>sugimoto</dc:creator>
				<category><![CDATA[CMS]]></category>
		<category><![CDATA[MODx]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[rsync]]></category>

		<guid isPermaLink="false">http://labo.opengroove.com/blog/index.php/2008/04/21/modx%e3%81%a7staging%e7%92%b0%e5%a2%83%e3%81%8b%e3%82%89production%e7%92%b0%e5%a2%83%e3%81%b8/</guid>
		<description><![CDATA[
OpenGrooveの検索アプライアンスサーバ「zeera document search」の製品サイトはMODx CMSを利用して構築しています。

サイトの更新は


    別に用意したテスト環境で更新

    更新に問題がないか社内でチェック
    本番環境に更新分を反映


という手順でやっているのですが、#3の反映作業は手作業にすると、手間がかかり、反映漏れが出るもとになります。

そこで、ssh, rsync, mysqldumpを使って、#3の手順を自動化し、更新分を確実に反映することにしました。

1. 反映の方法

自動化の方法の概要を簡単に説明すると以下の通りです。

- rsyncでディレクトリの同期

MODx CMSは、


   top --- manager
        +- assets

というディレクトリ構造をしていて、assetsにテンプレート,CSS,imageなどが保存されています。
逆にmanagerにはMODxのコアスクリプトと設定ファイルがあります。
そのため、assetsをrsyncで同期することにします。

- データベースの更新

MODx CMSはMySQLでデータを保存しています。
環境依存なデータはsite_settingsテーブルに集約されているため、このテーブル以外をコピーします。

- サーバ間の接続はSSHを使用する

自動化するためにパスフレーズなしの鍵をつくり、自動接続して本番環境にデータを転送します。

2. サーバの設定

自動化のためにテストサーバから本番サーバにSSHで接続するための環境を作ります。

- 鍵の作成

テストサーバで鍵を作成します。


&#62; ssh-keygen -t rsa


パスフレーズを聞かれますが、入力せずにリターンキーを押し、パスフレーズなしで作成します。
出来上がった公開鍵は本番サーバに転送し、/home/[user]/.ssh/authorized_keysに入れておきます。

3. データベースの更新の設定

mysqldumpでテスト環境のデータベースをdumpして、本番環境にdumpデータを反映します。

まず、テスト環境のデータをコピーし、本番環境に反映するためのSQL文のファイルを生成するシェルスクリプトを用意します。

[dump_modx_data.sh]


#!/bin/bash
work_dir=/home/user/xxxxx
filename=dumpfile.dump
file_path=$work_dir$filename

echo "" &#62; $file_path

# データを削除するSQL文をファイルに書き込み
echo "TRUNCATE TABLE active_users;" &#62;&#62; $file_path
...site_settings 以外のテーブルについて同じ

# データを [...]]]></description>
			<content:encoded><![CDATA[<p>
OpenGrooveの検索アプライアンスサーバ「<a href="http://search.opengroove.com/" title="ジーラ・検索サーバー">zeera document search</a>」の製品サイトは<a href="http://modxcms.com/" title="MODx CMS">MODx CMS</a>を利用して構築しています。</p>

<p>サイトの更新は</p>

<ol>
    <li>別に用意したテスト環境で更新</li>

    <li>更新に問題がないか社内でチェック</li>
    <li>本番環境に更新分を反映</li>
</ol>

<p>という手順でやっているのですが、#3の反映作業は手作業にすると、手間がかかり、反映漏れが出るもとになります。</p>

<p>そこで、ssh, rsync, mysqldumpを使って、#3の手順を自動化し、更新分を確実に反映することにしました。</p>

<h3>1. 反映の方法</h3>

<p>自動化の方法の概要を簡単に説明すると以下の通りです。</p>

<h4>- rsyncでディレクトリの同期</h4>

<p>MODx CMSは、</p>

<pre>
   top --- manager
        +- assets</pre>

<p>というディレクトリ構造をしていて、assetsにテンプレート,CSS,imageなどが保存されています。
逆にmanagerにはMODxのコアスクリプトと設定ファイルがあります。
そのため、assetsをrsyncで同期することにします。</p>

<h4>- データベースの更新</h4>

<p>MODx CMSはMySQLでデータを保存しています。
環境依存なデータはsite_settingsテーブルに集約されているため、このテーブル以外をコピーします。</p>

<h4>- サーバ間の接続はSSHを使用する</h4>

<p>自動化するためにパスフレーズなしの鍵をつくり、自動接続して本番環境にデータを転送します。</p>

<h3>2. サーバの設定</h3>

<p>自動化のためにテストサーバから本番サーバにSSHで接続するための環境を作ります。</p>

<h4>- 鍵の作成</h4>

<p>テストサーバで鍵を作成します。</p>

<pre>
&gt; ssh-keygen -t rsa
</pre>

<p>パスフレーズを聞かれますが、入力せずにリターンキーを押し、パスフレーズなしで作成します。
出来上がった公開鍵は本番サーバに転送し、/home/[user]/.ssh/authorized_keysに入れておきます。</p>

<h3>3. データベースの更新の設定</h3>

<p>mysqldumpでテスト環境のデータベースをdumpして、本番環境にdumpデータを反映します。</p>

<p>まず、テスト環境のデータをコピーし、本番環境に反映するためのSQL文のファイルを生成するシェルスクリプトを用意します。</p>

<p>[dump_modx_data.sh]</p>

<pre>
#!/bin/bash
work_dir=/home/user/xxxxx
filename=dumpfile.dump
file_path=$work_dir$filename

echo "" &gt; $file_path

# データを削除するSQL文をファイルに書き込み
echo "TRUNCATE TABLE active_users;" &gt;&gt; $file_path
...site_settings 以外のテーブルについて同じ

# データを INSERT するSQL文をファイルに書き込み
mysqldump -u [user] -p[password] [database] --no-create-info \
        --tables [テーブルを列挙] &gt;&gt; $file_path</pre>

<p>これで、データベース反映用のSQLスクリプトがダンプされます。</p>

<h3>4. データベース反映用のSQLスクリプトを本番サーバで実行する</h3>

<p>次に、先ほどのシェルスクリプトで作成したデータベース反映用のSQLスクリプトを本番サーバで実行します。</p>

<p>[insert_dumpfile.sh]</p>

<pre>
#!/bin/bash
work_dir=/home/user/workdirectory
filename=dumpfile.dump
file_path=$work_dir$filename
#本番サーバで実行するシェルスクリプト
command=remote_commands.sh

#SQLスクリプトを本番サーバにコピー
scp $file_path remoteuser@remoteserver:/temporary/dir/.
#sshでログインしてSQLスクリプトを実行
ssh -l remoteuser remoteserver &lt; $work_dir$command
#作業後に削除
rm -f $file_path</pre>

<p>[remote_commands.sh] &lt; 本番サーバー上で実行されるシェルスクリプト</p>

<pre>
#!/bin/bash
filename=/temporary/dir/dumpfile.dump
mysql -u [user] -p[password] [database] &lt; $filename
rm -f $filename
</pre>

<h3>5. rsync でディレクトリをコピーする</h3>

<p>スタイルシートや、画像ファイルはデータベースには保存されていないので、rsyncでディレクトリの同期をして本番サーバに反映します。assets ディレクトリ全体を同期の対象にします。</p>

<p>[rsync_assets.sh]</p>

<pre>
#!/bin/bash
#rsyncコマンドでassetsディレクトリの同期
#削除されたファイルも反映する
#remoteディレクトリは親ディレクトリを指定する
rsync -a --delete --exclude "cache/docid_*.pageCache.php" /path/to/local remoteserver:/parent/path/to/remote    

</pre>

<h3>6. 反映の実行</h3>

<p>これまでに作成したシェルスクリプトを</p>

<ol>
    <li>dump_modx_data.sh</li>

    <li>insert_dumpfile.sh</li>
    <li>rsync_assets.sh</li>

</ol>

<p>の順に実行すると自動的にテストサーバーのデータが本番サーバーに反映されます。</p>

<p>3つのファイルを一つにまとめて、cronに登録しておけば、毎晩、自動的にテストサーバーのデータが本番サーバーに反映されます。</p>

<ul>
    <li><a href="http://samba.anu.edu.au/rsync/" title="rsync">rsync</a></li>

</ul>
]]></content:encoded>
			<wfw:commentRss>http://labo.opengroove.com/blog/2008/04/21/modx%e3%81%a7staging%e7%92%b0%e5%a2%83%e3%81%8b%e3%82%89production%e7%92%b0%e5%a2%83%e3%81%b8/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
	</channel>
</rss>
