ITの隊長のブログ

ITの隊長のブログです。Rubyを使って仕事しています。最近も色々やっているお(^ω^ = ^ω^)

【CakePHP3.x】TableクラスでEnumを使う

DBでステータスのフィールドを用意した場合、0とか1とかでフラグを用意するんだけど、それじゃいまいちよくわからない。

なので、定数にして、DELETEとかCANCELとか名前を付けれるようにする。

CakePHP2.xでは、~/Config/const.phpってファイルを作成して、そこで管理していました。

しかし、定数が多くなると管理が面倒くさい。

CakePHP3.xのModelにはTableってクラスがある。そこで管理すればいいんじゃね!? とひらめく(?)

ぐぐったら、下記リンクが参考になった。

qiita.com

あんまりしっくりこなかった。というのも。

<?php
// ... 省略
define('DELETE', 0);
define('CANCEL', 1);

Configure::write('FLAG', array(
    DELETE => '削除',
    CANCEL => 'キャンセル'
));

CakePHP2.xでは、定数にラベルを用意していたのだ。カスタムしないといけないなと思う。

では、プラグインはないだろうか? ありました。

github.com

しかし、これはTableレベルでのEnumなのだ。できればクラスに書けるプロパティベースのがいい。

あった! ありがとうございます m(_ _ )m

k1low.hatenablog.com

さっきのプラグインを使った上でのプラグインである。

まず、CakeDC/Enumをインストールして、ロードするように設定する。

$ composer require cakedc/enum:~1.0
$ bin/cake plugin load CakeDC/Enum

次に、作っていただいたプラグインをインストール

$ composer require k1low/property-enum

あとは必要なTableクラスと~/Controller/AppController.phpに追記するのみ

  • ~/src/Model/Table/AdminUsersTable.php
<?php
// ... 省略
class AdminUsersTable extends Table
{

    public $enums = [
        'status' => [
            'unapproved' => 'unapproved' // 未承認
        ]
    ];

    public function initialize(array $config)
    {
        parent::initialize($config);
        // ... 省略
        $this->addBehavior('PropertyEnum.Enum', ['lists' => [
            'status' => [
                'strategy' => 'property'
            ]
        ]]);
// ... 省略
  • ~/src/Controller/AppController.php
<?php
// ... 省略
    public function initialize()
    {
        // ... 省略
        $this->loadComponent('PropertyEnum.AutoSet');
     }
// ... 省略

これでできた!

と、思われた。。。

ラベルをつけるの忘れていた。。。あと多言語化が必要なので、翻訳も取り入れたい。どうしたものか。。。

綺麗じゃないと思うんだけど、初期化の処理にプロパティに追加する方法を選んだ。

<?php
// ... 省略
class AdminUsersTable extends Table
{

    public $enums = [];

    /**
     * Initialize method
     *
     * @param array $config The configuration for the Table.
     * @return void
     */
    public function initialize(array $config)
    {
        parent::initialize($config);

        $this->enums = [
            'status' => [
                __('unapproved'),
                __('approved'),
                __('cancel')
            ]
        ];
        // ... 省略
        $this->addBehavior('PropertyEnum.Enum', ['lists' => [
            'status' => [
                'strategy' => 'property'
            ]
        ]]);
    }
// ... 省略

これでよし(一応)

【MySQL & CakePHP2.x】任意の順番でソートしたい時

「順番を1、2、3ではなくて、2,3,1にしてほしい」

順番がゲシュタルト崩壊(?)

データベース設計時、ここは順番が変わるかもしれない。ってどうやって予想すればいいかな。確かに順番が必要、って最初からわかっていたら、ソートキーのカラムを作れば回避できると思うけど。

さてさて、その順番を任意の順番に変更したい場合、どうすればいいんやと思ったけど、探したらあった。

http://snowland.net/nucleus/item/2984

ありがとうございますm(_ _ )m

mysql> select 
  table1.type 
from 
  table1 
order by field(type,2,5,3);
+------+
| type |
+------+
|    2 |
|    2 |
|    2 |
|    2 |
|    2 |
|    5 |
|    3 |
|    3 |
|    3 |
|    3 |
|    3 |
|    3 |
|    3 |
|    3 |
|    3 |
|    3 |
+------+

しゅごい。。。

これをCakePHP2.x側でどうやって実装するのか。

まぁ普通に考えつくのがこれだよね。

<?php
// ... 省略
$queryParameter = array(
    'order' => array(
        'field(type,2,5,3)'
    )
);

$data = $this->Table1->find('all', $queryParameter);

これでおkです。うまくいきました。

【CakePHP3】認証が必要なActionでのテスト

公式のサイトを見たらありました。

Testing - 3.10

<?php
// ...省略
    public function testDelete()
    {
        $deleteId = 1;
        $this->session([
            'Auth' => [
                'User' => [
                    'id' => 1,
                    'email' => 'test2@gmail.com',
                    'password' => 'Lorem ipsum dolor sit amet',
                    'created' => '2016-08-31 00:44:23',
                    'modified' => '2016-08-31 00:44:23'
                ]
            ]
        ]);
        $this->post('/posts/delete/' . $deleteId);
        $this->assertEquals($this->__initialCount - 1, $this->post->find()->count());
    }

これ見つけるのは早かったんだけど、中々うまくいかないと思っていたら、配列の構造が間違っていました。。。無念。

【CakePHP3】phpunitでテストしてみた

CakePHP2では結構お世話になりました(不具合の方向で。。。)

CakePHP3ではすんなりいくかな?と思っていたけど、ダメでした。むー。なんででしょう?

とりあえずphpunitインストール

composerでインストールしました。

$ composer require --dev phpunit/phpunit

自作プラグインのロードエラー

テスト - 3.10

チュートリアル通り、実行しようとするとエラーが発生。

$ ./vendor/bin/phpunit
Cannot load Xdebug - extension already loaded
Exception: Plugin MyPlugins could not be found. in [../TestController.php]

???

色々試してみたら、phpunitだけじゃなくて、/bin/cakeコマンドもエラーがでているっぽい

???

デバッグしてたらわかった。

<?php
    // ...省略
    // 112行目ぐらい
    public static function load($plugin, array $config = [])
    {
        // ... 省略
        if (empty($config['path'])) {
            $paths = App::path('Plugin');
            $pluginPath = str_replace('/', DIRECTORY_SEPARATOR, $plugin);
            foreach ($paths as $path) {
                if (is_dir($path . $pluginPath)) {
                    $config['path'] = $path . $pluginPath . DIRECTORY_SEPARATOR;
                    break;
                }
            }
        }

        if (empty($config['path'])) {
            // ここでエラーが発生している
            throw new MissingPluginException(['plugin' => $plugin]);
        }

どうやら自作したPluginがロードできていないっぽい。なぁーぜぇー?

あ!

  • ~/config/bootstrap.php
<?php
// ...省略
Plugin::load('MyPlugins', ['autoload' => true, 'bootstrap' => true, 'routes' => true]);

実際のディレクトリは~/plugins/my_plugins/だったので、キャメルケース変換とかそんな処理がないからエラーになっているっぽい。

  • ~/config/bootstrap.php
<?php
// ...省略
// plugin名修正
Plugin::load('my_plugins', ['autoload' => true, 'bootstrap' => true, 'routes' => true]);

修正したらうまくいった。(ってかphpunitのエラーと関係ない。凡ミス)

何故かIDEでの実行結果とコンソールの実行結果が違う。

これも自分のところだけ。ってか考え方でした。

IDEのコマンドはこんな感じ

$ ~/vendor/bin/phpunit

コンソールはこんな感じ

$ ./vendor/bin/phpunit

おわかりいただけただろうか・・・・?

ようは相対なのか絶対なのかって話ですよ。この場合絶対パス指定のIDEはただphpunitを実行するだけで、help内容が出力されるだけ。

IDEで使いたい場合はパラメータも含めすべて絶対パスで指定してあげてください。

$ ~/vendor/bin/phpunit --bootstrap ~/tests/bootstrap.php ~/tests/

何故かtableが認識されない

$ ./vendor/bin/phpunit
...
Cake\Database\Exception: SQLSTATE[42S02]: Base table or view not found: 1146 Table 'test_table.post_meta' doesn't exist
...

こんなエラーが。。。と思いきや、単純にアプリケーション側のモデルロード処理の名前が間違っていました。。。。orz

2016/09/18 追記

実行するコマンド間違えていました。。。

$ ~/vendor/bin/phpunit --configuration ~/phpunit.xml.dist

雑な感想

やっとテストできたお! (^ω^ = ^ω^)

エラーはいっぱいでたけど、phpunit全然関係なかった。。。