cakephp3

cakephp3 ビジネスロジックを書くためにServiceクラスを作る

More than 1 year has passed since last update.

ビジネスロジック書くところ無い

cakephpでは、Helper,Component,ShellHelper,Cellなどもろもろロジックを使いまわすための機構がありますが、バッチなどを動かすShellと、ウェブ上で動かすcontroller等のソースで、ロジックを共有したいのに既存のものだとロジックを置く場所がないです。

参考

みんな困ってます。

ということで、Serviceクラスを作ってみました

正直DDDはよく分かってません。

cakephp3では適当なディレクトリとnamespaceを勝手に作れる

Cakephp3はsrc/Controllerなどのディレクトリがありますが、srcの下にディレクトリを掘って、適切なnamespaceを設定してあげると、その配下においたクラスは、自由に他の場所でも使えるようになります。(psr-4のおかげですが

tree.log
cake-app
├── bin
├── config
├── logs
├── plugins
├── src
│   ├── Console
│   ├── Controller
│   ├── Model
│   ├── 省略....
│   ├── Service // ここに適当にディレクトリを作る
│   └── View
├── tmp
├── vendor
└── webroot
    ├── css
    ├── img
    └── js

Serviceディレクトリを作成、classのphpを起き、クラスのnamespaceをApp\Serviceに

src/Service/EnqueteFileService.php
<?php
namespace App\Service;
class EnqueteFileService {

    public function imageFileExist($file_path) {
        return file_exist($file_path);
    }
}

とすると、

SellやControllerやModelやHelperやCellやEntity、Tableなどいろんなところで、use句で読み込んであげて、このように使えます。

use App\Service\EnqueteFileService;

// snip

$service = new EnqueteFileService();
$service->imageFileExist($file_path);

一生懸命componentに実装したのにShellでつかえねーし、一生懸命componentに実装したのにHelperにcomponentってまじどうやって渡すの…。また同じこと書くのかよコレ!!!またTableクラスに書くの…。このロジックEntityに書いてもいい…??って陳謝しながら許しを請うになったらご利用ください。

AppServiceクラスを作ってみました。

それなりに使えそうな、AppServiceクラスを作ってみました。

App/Service/AppService.php
<?php
namespace App\Service;

use Cake\Datasource\ModelAwareTrait;
use Cake\ORM\Locator\LocatorAwareTrait;
use Cake\Log\LogTrait;

class AppService {

    use LocatorAwareTrait;
    use LogTrait;
    use ModelAwareTrait;

    public $name = null;
    public $plugin = null;

    public function __construct($name = null)
    {
        if ($name !== null) {
            $this->name = $name;
        }

        if ($this->name === null) {
            list(, $name) = namespaceSplit(get_class($this));
            $this->name = substr($name, 0, -10);
        }
        $this->initialize();
    }

    public function initialize() {

    }

    /**
     * Magic accessor for model autoloading.
     *
     * @param string $name Property name
     * @return bool|object The model instance or false
     */
    public function __get($name)
    {
        return $this->loadModel($name);
    }
}

これを基底クラスにするとTableクラスのロードとかがControllerとおんなじ感じで簡単にできます。phpdocの@propertyのおかげだけど

App/Service/EnqueteFileService.php
<?php
namespace App\Service;

/**
 * @property \App\Model\Table\EnqueteTable $Enquete
 * @property \App\Model\Table\EnqueteImageTable $EnqueteImage
 */
class EnqueteFileService extends AppService{

    public function deleteRemainImages($id) {
        $_enquetes = $this->Enquete->get($id, [
            'contain' => ['EnqueteImage']
        ]);
        foreach($_enquetes as $_enquete) {
            if(file_exist($_enquete->enquete_image->file_path)){
                unlink($_enquete->enquete_image->file_path);
            }

        }
    }
}

これが、コントローラーでもshellでもhelperでもcomponentでも呼び出せます。