ええやんブログ

ええやないかのええやんブログ

Codeigniterでcontrollerをディレクトリ分けする(その2)

どうもー。
今回は前回に引き続き、Codeigniterのcontrollerをディレクトリ分けする方法についてです。

さて、controllerをこんな風にディレクトリの下にサブディレクトリを作成しようとすると、Codeigniterはデフォルトではuserまで(第1階層)しか認識しません。

controller
  └ user
    └ pc
    └ smartphone
      └ foo.php

http://example.com/user/pc/foo/indexにアクセスすると、config/route.phpにどう記述しても、そのままではpcコントローラーのfooメソッドにアクセスしてしまいます。

というわけで、第2階層まで認識させるには、こちらを参考にして、下記の手順で変更すればOKです。

MY_Routerを作成

/application/coreの直下にMY_Router.phpを作成して、次のコードをコピペします。

<?php

/*
 * Custom router function v 0.1
 *
 * Add functionality : read into more than one sub-folder
 *
 */
Class MY_Router extends CI_Router
{

    /**
     * Validates the supplied segments.  Attempts to determine the path to
     * the controller.
     *
     * @access private
     * @param  array
     * @return array
     */
    function _validate_request($segments)
    {
        if (count($segments) == 0)
        {
            return $segments;
        }

        // Does the requested controller exist in the root folder?
        if (file_exists(APPPATH.'controllers/'.$segments[0].'.php'))
        {
            return $segments;
        }

        // Is the controller in a sub-folder?
        if (is_dir(APPPATH.'controllers/'.$segments[0]))
        {
            // Set the directory and remove it from the segment array
            $this->set_directory($segments[0]);
            $segments = array_slice($segments, 1);

            /* ----------- ADDED CODE ------------ */

            while(count($segments) > 0 && is_dir(APPPATH.'controllers/'.$this->directory.$segments[0]))
            {
                // Set the directory and remove it from the segment array
                $this->set_directory($this->directory . $segments[0]);
                $segments = array_slice($segments, 1);
            }

            /* ----------- END ------------ */

            if (count($segments) > 0)
            {
                // Does the requested controller exist in the sub-folder?
                if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$segments[0].'.php'))
                {
                    if ( ! empty($this->routes['404_override']))
                    {
                        $x = explode('/', $this->routes['404_override']);

                        $this->set_directory('');
                        $this->set_class($x[0]);
                        $this->set_method(isset($x[1]) ? $x[1] : 'index');

                        return $x;
                    }
                    else
                    {
                        show_404($this->fetch_directory().$segments[0]);
                    }
                }
            }
            else
            {
                // Is the method being specified in the route?
                if (strpos($this->default_controller, '/') !== FALSE)
                {
                    $x = explode('/', $this->default_controller);

                    $this->set_class($x[0]);
                    $this->set_method($x[1]);
                }
                else
                {
                    $this->set_class($this->default_controller);
                    $this->set_method('index');
                }

                // Does the default controller exist in the sub-folder?
                if ( ! file_exists(APPPATH.'controllers/'.$this->fetch_directory().$this->default_controller.'.php'))
                {
                    $this->directory = '';
                    return array();
                }

            }

            return $segments;
        }


        // If we've gotten this far it means that the URI does not correlate to a valid
        // controller class.  We will now see if there is an override
        if ( ! empty($this->routes['404_override']))
        {
            $x = explode('/', $this->routes['404_override']);

            $this->set_class($x[0]);
            $this->set_method(isset($x[1]) ? $x[1] : 'index');

            return $x;
        }


        // Nothing else to do at this point but show a 404
        show_404($segments[0]);
    }

    // --------------------------------------------------------------------

    /**
     *  Set the directory name
     *
     * @access public
     * @param  string
     * @return void
     */
    function set_directory($dir)
    {
        /* ----------- CHANGED CODE ------------ */
        // $this->directory = str_replace(array('/', '.'), '', $dir).'/';
        $this->directory = str_replace(array('.'), '', $dir).'/';
    }

}

_validate_requestメソッドの引数で渡される$segmentsには、route.phpに書かれたパス情報がdirectory・controller・functionの順で配列に格納されています。
なので、directoryが格納されている$segments[0]をスライスして、$this->directoryに "/" 区切りで設定するように変更します。
注意点としては、set_directoryメソッドもオーバーライドしておかないと、せっかく設定したディレクトリから "/" を削除してしまいます。

ルーティングを設定

あとはconfig/route.phpにルーティングさせたいディレクトリを書けば、そこに飛ばしてくれます。

$route['pc/(:any)'] = "user/pc/$1";

http://example.com/user/pc/foo/indexにアクセスすると、ちゃんとfooコントローラーのindexメソッドを呼び出してくれます。

ディレクトリ分けをしておかないと、ちょっと大きな案件になった場合にすぐcontrollerだらけになってしまいますよね。
ぜひ参考にして下さい。