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

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

## 参考

みんな困ってます。

* [cakephp - How to load a component in console/shell - Stack Overflow](http://stackoverflow.com/questions/28511023/how-to-load-a-component-in-console-shell) どうやってコンポーネントをshellでつかうの？
* [cakephp 3.0 - Calling a Component function from helper - Stack Overflow](http://stackoverflow.com/questions/27818635/calling-a-component-function-from-helper) 
どうやってコンポーネントをHelperの中でつかうの？


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

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

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

Cakephp3はsrc/Controllerなどのディレクトリがありますが、srcの下にディレクトリを掘って、適切なnamespaceを設定してあげると、その配下においたクラスは、自由に他の場所でも使えるようになります。（[psr-4のおかげですが](http://book.cakephp.org/3.0/ja/appendices/3-0-migration-guide.html)）


```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でも呼び出せます。