読者です 読者をやめる 読者になる 読者になる

Ethnaを業務で使うために(2) ディレクトリ構造の変更

Ethnaを業務で使うために(1) 雛形の準備 - maru.cc@はてな」の続きです。


前回は、大枠の設置をしたので、今回は少し進めて、ディレクトリ構造の整理を行います。
大きく分けて次の3つの作業を行います。

  • AppManagerの作成されるディレクトリの場所を変更
  • AppObjectの作成されるディレクトリの場所を変更
  • テスト関連のファイルが作成されるディレクトリの変更


※シェルコマンドは、特に明記していなければ、プロジェクトのルート(ethna.shの置いてあるディレクトリ)で発行したものとします。

$ cd /path/to/common/
$ ls
app  bin  etc  ethna.sh  htdocs  htdocs.ssl  lib  locale  log  schema  skel  template  test  tmp

AppManager、AppObjectの作成されるディレクトリの場所を変更

これから、アプリを作成する上で、AppManagerは必須になってくるクラスファイルです。
AppManagerには、DB操作を含めたビジネスロジックを記述することになります。
AppObjectは、使いにくいと評判(?)で、使わない場合には、この作業は必要ありませが、AppManagerとほぼ同じ作業なのでまとめて書きます。


AppManagerや、AppObjectのファイルは、デフォルトでは、app以下に作成されるようになっています。
例)

$ sh ethna.sh add-app-manager test
file generated [/path/to/common/lib/Ethna/skel/skel.app_manager.php -> /path/to/common/app/Mm_TestManager.php]
app-manager script(s) successfully created [/path/to/common/app/Mm_TestManager.php]

これだと、AppManagerが増えてきたときに、Common_Controller.phpなどに混ざり、作業がしにくくなってしまいます。
ですので、app/manager/ ディレクトリを新規に作成し、そちらに AppManagerを全て置くようにしてみます。
AppObjcetについては、app/manager/object に置くようにします。
※このファイルは確認なので消しておいてください。

Generator_AppManagerの拡張

今後、作成されるファイルを全て、手動で動かしてもいいのですが、それだと移動漏れや、いちいち作業が発生するのは、めんどくさいので、Generatorを拡張します。


pluginディレクトリ内に、Generatorディレクトリを作成します。

$ mkdir app/plugin/Generator


app/plugin/Generator内に以下のファイルを作成します。
Common_Plugin_Generator_AppManager.php

<?php
// vim: foldmethod=marker
/**
 *  Common_Plugin_Generator_AppManager.php
 *
 *  @author     
 *  @license    http://www.opensource.org/licenses/bsd-license.php The BSD License
 *  @package    Ethna
 *  @version    $Id:  $
 */

// {{{ Common_Plugin_Generator_AppManager
/**
 *  スケルトン生成クラス
 *
 *  @author     
 *  @access     public
 *  @package    Ethna
 */
class Common_Plugin_Generator_AppManager extends Ethna_Plugin_Generator
{
    /**
     *  アプリケーションマネージャのスケルトンを生成する
     *
     *  @access public
     *  @param  string  $manager_name    アプリケーションマネージ名
     *  @return bool    true:成功 false:失敗
     */
    function generate($manager_name, $skelton = null)
    {
        $manager_id = preg_replace('/_(.)/e', "strtoupper('\$1')", ucfirst($manager_name));

        $app_dir = $this->ctl->getDirectory('manager');
        $app_path = ucfirst($this->ctl->getAppId()) . '_' . $manager_id .'Manager.php';

        $macro = array();
        $macro['project_id'] = $this->ctl->getAppId();
        $macro['app_path'] = $app_path;
        $macro['app_manager'] = ucfirst($this->ctl->getAppId()) . '_' . $manager_id;

        $user_macro = $this->_getUserMacro();
        $macro = array_merge($macro, $user_macro);

        $path = "$app_dir/$app_path";
        Ethna_Util::mkdir(dirname($path), 0755);
        if (file_exists($path)) {
            printf("file [%s] already exists -> skip\n", $path);
        } else if ($this->_generateFile("skel.app_manager.php", $path, $macro) == false) {
            printf("[warning] file creation failed [%s]\n", $path);
        } else {
            printf("app-manager script(s) successfully created [%s]\n", $path);
        }
    }
}
// }}}
?>
Generator_AppObjectの拡張

こちらも、AppManagerと同様に app/plugin/Generator内にファイルを作成します。
Common_Plugin_Generator_AppObject.php

<?php
// vim: foldmethod=marker
/**
 *  Common_Plugin_Generator_AppObject.php
 *
 *  @author
 *  @license    http://www.opensource.org/licenses/bsd-license.php The BSD License
 *  @package    Ethna
 *  @version    $Id:  $
 */

// {{{ Common_Plugin_Generator_AppObject
/**
 *  スケルトン生成クラス
 *
 *  @author
 *  @access     public
 *  @package    Ethna
 */
class Common_Plugin_Generator_AppObject extends Ethna_Plugin_Generator
{
    /**
     *  アプリケーションオブジェクトのスケルトンを生成する
     *
     *  @access public
     *  @param  string  $table_name     テーブル名
     *  @return bool    true:成功 false:失敗
     */
    function generate($table_name)
    {
        $table_id = preg_replace('/_(.)/e', "strtoupper('\$1')", ucfirst($table_name));

        $app_dir = $this->ctl->getDirectory('object');
        $app_path = ucfirst($this->ctl->getAppId()) . '_' . $table_id .'.php';

        $macro = array();
        $macro['project_id'] = $this->ctl->getAppId();
        $macro['app_path'] = $app_path;
        $macro['app_object'] = ucfirst($this->ctl->getAppId()) . '_' . $table_id;

        $user_macro = $this->_getUserMacro();
        $macro = array_merge($macro, $user_macro);

        $path = "$app_dir/$app_path";
        Ethna_Util::mkdir(dirname($path), 0755);
        if (file_exists($path)) {
            printf("file [%s] already exists -> skip\n", $path);
        } else if ($this->_generateFile("skel.app_object.php", $path, $macro) == false) {
            printf("[warning] file creation failed [%s]\n", $path);
        } else {
            printf("app-object script(s) successfully created [%s]\n", $path);
        }
    }
}
// }}}
?>
Common_Controllerの修正

上記をしただけでは、自動が自動で読み込まれないので、app/Common_Controller.php に追記を行います。


新規作成した app/manager、app/manager/object 内も検索してもらえるように、include_pathの変更を行います。
また、デフォルト設定よりも lib内などを先に読み込むように修正を同時に行います。


app/Common_Controller.php 16行目あたり
修正前

/** include_pathの設定(アプリケーションディレクトリを追加) */
$app = BASE . "/app";
$lib = BASE . "/lib";
ini_set('include_path', ini_get('include_path') . PATH_SEPARATOR . implode(PATH_SEPARATOR, array($app, $lib)));

修正後

/** include_pathの設定(アプリケーションディレクトリを追加) */
$app = BASE . "/app";
$lib = BASE . "/lib";
$manager = $app . "/manager";
$object = $app . "/manager/object";
ini_set('include_path', implode(PATH_SEPARATOR, array($app, $lib, $manager, $object)) . PATH_SEPARATOR . ini_get('include_path'));


アプリケーションディレクトリに追記を行います。
app/Common_Controller.php 90行目あたり
修正前

    /**
     *  @var    array       アプリケーションディレクトリ
     */
    var $directory = array(
        'action'        => 'app/action',
        'action_cli'    => 'app/action_cli',
    (略)
        'tmp'           => 'tmp',
        'view'          => 'app/view',
        'www'           => 'www',
    );

修正後

    /**
     *  @var    array       アプリケーションディレクトリ
     */
    var $directory = array(
        'action'        => 'app/action',
        'action_cli'    => 'app/action_cli',
    (略)
        'tmp'           => 'tmp',
        'view'          => 'app/view',
        'www'           => 'www',
        'manager'       => 'app/manager',
        'object'        => 'app/manager/object',
    );
ためしに動かしてみる

これで app/manager/ 内に新規作成時にも作ってくれるようになります。
例)

$ sh ethna.sh add-app-manager test
file generated [/path/to/common/lib/Ethna/skel/skel.app_manager.php -> /path/to/common/app/manager/Mm_TestManager.php]
app-manager script(s) successfully created [/path/to/common/app/manager/Mm_TestManager.php]

AppObjectも同様です。

$ sh ethna.sh add-app-object test
file generated [/path/to/common/skel/skel.app_object.php -> /path/to/common/app/manager/object/Mm_Test.php]
app-object script(s) successfully created [/path/to/common/app/manager/object/Mm_Test.php]

※このファイルは確認なので消しておいてください。

ついでにスケルトンの変更

AppObjectを使う場合、AppObjectは、テーブルと1対になりますが、AppManagerはビジネスロジック単位なので、テーブルと1対にならない場合があります。
なので、AppObjectを使う場合でも、AppManagerとは別に考えて作成した方がいいです。


Ethna2.3.1のデフォルトで作成される AppObjectのスケルトンファイルには、AppManagerを内包した形になっているので、実際に作業するときには邪魔になってしまう場合が多いので、そちらも修正してしまいます。


以下のファイルから、AppManagerの記述を削除します。
skel/skel.app_object.php
修正前

<?php
/**
 *  {$app_path}
 *
 *  @author     {$author}
 *  @package    Common
 *  @version    $Id: skel.app_object.php,v 1.3 2006/11/06 14:31:24 cocoitiban Exp $
 */

/**
 *  {$app_object}Manager
 *
 *  @author     {$author}
 *  @access     public
 *  @package    Common
 */
class {$app_object}Manager extends Ethna_AppManager
{
}

/**
 *  {$app_object}
 *
 *  @author     {$author}
 *  @access     public
 *  @package    Common
 */
class {$app_object} extends Ethna_AppObject
{
    /**
     *  プロパティの表示名を取得する
     *
     *  @access public
     */
    function getName($key)
    {
        return $this->get($key);
    }
}
?>

修正後

<?php
/**
 *  {$app_path}
 *
 *  @author     {$author}
 *  @package    Common
 *  @version    $Id: skel.app_object.php,v 1.3 2006/11/06 14:31:24 cocoitiban Exp $
 */

/**
 *  {$app_object}
 *
 *  @author     {$author}
 *  @access     public
 *  @package    Common
 */
class {$app_object} extends Ethna_AppObject
{
    /**
     *  プロパティの表示名を取得する
     *
     *  @access public
     */
    function getName($key)
    {
        return $this->get($key);
    }
}
?>


AppManagerのスケルトンファイルが自動で、作成されていないので、コピーしておきます。

$ cp lib/Ethna/skel/skel.app_manager.php skel/

次回

テスト関連のディレクトリ変更について書きます。
Ethnaを業務で使うために(3) テスト関連のディレクトリ構造の変更 - maru.cc@はてな