FuelPHP + PhpStorm でプロパティー(メンバ変数？)も含めてコード補完を(強引かも)出来るようにする

FuelPHP + PhpStorm で code completion したい。自作したクラス(モデルとか)のプロパティーも含めて！

また、間違いや、もっと良い方法がある気もします。もし、何かあればツッコミを頂けると嬉しいです！

## FuelPHP 自体のクラスをコード補完

bulblubさんの [PhpStormでFuelPHPのクラス補完を有効にする方法](http://bulblub.com/2012/06/26/phpstorm%E3%81%A7fuelphp%E3%81%AE%E3%82%AF%E3%83%A9%E3%82%B9%E8%A3%9C%E5%AE%8C%E3%82%92%E6%9C%89%E5%8A%B9%E3%81%AB%E3%81%99%E3%82%8B%E6%96%B9%E6%B3%95/) や、kenjisさんの [Eclipse で FuelPHP のコード補完を行わせる冴えたやり方](http://d.hatena.ne.jp/Kenji_s/20120123/1327301678) などで、 FuelPHP 自体の各種クライスはコード補完が効くようになります。

便利！

それっぽい単語を打つと、自動補完してくれるので、学習コストが低くて済みますね。IDE 使う意味の一つですね。

## FuelPHP + PhpStorm でプロパティーも含めたコード補完がしたい！

例えば、以下の様なモデルを作ったとします。

`$ oil g model user email:varchar[255] password:varchar[255] salt:varchar[255] screen_name:varchar[255] status:integer --soft-delete --mysql-timestamp`

そうすると、以下の様なファイルが出来上がるはず。

```./fuel/app/model/user.php
<?php

class Model_User extends \Orm\Model_Soft
{
	protected static $_properties = array(
		'id',
		'email',
		'password',
		'salt',
		'screen_name',
		'status',
		'deleted_at',
		'created_at',
		'updated_at',
	);
// (略)
}
```

この Model_User は PhpStorm でちゃんとコード補完されます。

こんなふうに。

![Model_User がちゃんとコード補完されている](https://qiita-image-store.s3.amazonaws.com/0/3243/c212ed44-aab9-81c8-5bb9-d6d8c39cbd5f.png)

これだけでも嬉しいのですが、出来れば、プロパティもコード補完して欲しい。

たとえば、以下の様な状態($user_ore->sc まで打った状態)で、コード補完に"screen_name"が出てきて欲しいわけです。

```./fuel/app/classes/controller/user.php
$user_ore = Model_User::find('first', array(
	'where' => array(
		'screen_name' => 'ore',
	),
));
$user_ore->sc
```

実際にこのコード補完を(強引にですが)行う方法は後述として、先に結果を載せると、以下の画像のような事を実現したいわけです！

![ちゃんと補完されてる！](https://qiita-image-store.s3.amazonaws.com/0/3243/4fa4e1a6-7139-24db-6e20-7fd2e96307ab.png)

これで、 View 内とか、 Controller 内とか、 Model 内で他のモデル参照する時とか、なんだったらリレーションも含めて、ガシガシ書いていくのが捗りそう！

な、気がします。

また、 Git へのコミット時なども PhpStorm がコードレビューする時に、ちゃんと検査が通っているかを(ある程度)示してくれるので、 PhpStrom の Review 機能がちゃんと役立つようになります！これは嬉しい！！

で、それを(強引に)実現する方法を検討してみました。

## FuelPHP + PhpStorm で自作クラス(モデルなど)のプロパティーもコード補完する方法

結論から書くと、"コード補完専用のファイルを用意してアノテーションを使いましょう！"です。

例えば、以下の様なファイル(ファイル名はお好きに)を用意します。

```./__auto_completion.php
<?php
/**
 * Class Model_User
 */
class Model_User {
	/** @var string Screen Name */
	public $screen_name;
}
```

これだけ。

これで、 (先ほどと同じ)以下の画像の様な自動補完が効くようになります。

![ちゃんと補完されてる！](https://qiita-image-store.s3.amazonaws.com/0/3243/4fa4e1a6-7139-24db-6e20-7fd2e96307ab.png)

#### プロパティーに対するアノテーションの書き方

```
/** @var (ココに型を書きます) (ここに説明文を書きます) */
```

で、あってるはず。。

型の部分が大切です。

string, int, array, boolean, double, float, などなど。

#### 例えば、 has_many なリレーションのプロパティーの場合のアノテーションの書き方

Model_User は、 has_many Model_Thread だったとします。

`$some_user->threads` という状況です。

これも自動補完して欲しい。

そんな場合は、以下のように書いておきます。

※ oil コマンドで生成したその他のプロパティーも同様に書いておくと良いですが、とりあえず参考までに記載していません。

```./__auto_completion.php
/**
 * Class Model_User
 */
Class Model_User {

	/** @var string Screen Name */
	public $screen_name;

	/** @var Model_Thread[] Thread */
	public $threads;
}
```

大切なのは、"[]"部分です。

これで、`$user_ore->thr`まで書けば、`threads`が正しく`Model_Thread[]`としてコード補完されます。

![ちゃんと補完されてる！](https://qiita-image-store.s3.amazonaws.com/0/3243/9dc5c196-6959-40ac-79fa-37a827937888.png)

※複数の型を保持する可能性がある時は、`/** @var Model_Hoge|array Model_Hogeの配列かnullを返します */`の様に書きます。

同様に、./__auto_completion.php に Model_Thread のアノテーションも書いておけば、それもちゃんと補完されます。(当然ですが。)

例えば以下のようにします。

```./__auto_completion.php
<?php
/**
 * Class Model_User
 */
class Model_User {

	/** @var string Screen Name */
	public $screen_name;

	/** @var Model_Thread[] Thread */
	public $threads;
}

class Model_Thread {

	/** @var Model_User User */
	public $user;

	/** @var string Thread Title */
	public $title;
}
```

すると、以下の図のようにコード補完されます。

![補完されてる！](https://qiita-image-store.s3.amazonaws.com/0/3243/b6fd7f1b-33f2-5926-c631-33d486209ed8.png)

`__auto_completion.php` に追記したように、 title も user もありますね。

で、 `./__auto_completion.php` の Model_Thread 側に、 $user の型が Model_User であることをアノテーションで示しているため、以下の図ように、`$thread->user->`もちゃんと、 Model_User のアノテーションが効いて補完されます。

![ちゃんと補完されてる！](https://qiita-image-store.s3.amazonaws.com/0/3243/4a89bd77-33b2-2da1-f70c-b8fa549a0bff.png)

これで、ずいぶんと書くのが楽になりそうです。

## View 内でもコード補完されるようにしたい！

ただ、このままだと、 views 内では、コード補完されません。

以下の図のように、コード補完が効きません。

`$user` が黄色いし、 `$item->e` まで打っても何も出ない。。

![コード補完されてない](https://qiita-image-store.s3.amazonaws.com/0/3243/ed4bcf6b-9eb5-a34a-888f-b7ef03ab3190.png)

これは、パスの設定とかの解決もありそうですが、手っ取り早く、アノテーションで解決してしまおうと思います。

で、どうするかというと、以下の様なアノテーションを追記します。

```
<?php /** @var Model_User[] $users */ ?>
<h2>Listing <span class='muted'>Users</span></h2>
```

これを追記すると以下の図のように、ちゃんとコード補完されるようになります。

![ちゃんと補完されてる！](https://qiita-image-store.s3.amazonaws.com/0/3243/3c9435e9-c1f6-92e8-06fe-b4e8c8893f5d.png)

便利！

この1行を書くだけで、 View 内でもガシガシ書けそうな気がします！

また、`__auto_completion.php`の中で、ちゃんとプロパティーの型を指定しておくと、表示が妥当かとか、その関数やメソッドへの引数には型が一致せんで！とか、諸々も PhpStorm が教えてくれます！

便利！

※ `$item->email` が補完されているのは、`__auto_completion.php` に書いておいたからですが、今までの説明では省略しています。

#### プロパティーのアノテーションとの違いに注意しましょう

```
/** @var (ココに型を書きます) (ここに変数名を書きます) */
```

"変数名"を書きましょう。

説明文ではないです。

書いてみるとあわかりますが、変数名部分の背景色がハイライトされます。

## アノテーションで強引に実現している副作用

少しだけ気になる副作用が出てしまいます。

先ほどの View 内のアノテーション上にカーソルを持って行くと`Multiple definitions exist for class...`と出ますね。

![Multiple definitions exist for class...](https://qiita-image-store.s3.amazonaws.com/0/3243/fc2786e6-90fb-30d4-703a-a848e4992305.png)

複数箇所で定義されとるよ？というアナウンスです。

出来ることならば、この辺りも出ないようにちゃんとコード補完されるのが望ましですが、それは Plug-in を開発すれば解決するんやろうなーとか思ってます。

とりあえず、害はないしいいや。という感じなのが"強引に実現"なん気がしてます。

## アノテーション自体を書くときも PhpStorm に楽をさせてもらう方法

上記のように、アノテーションを使うと便利です。

で、アノテーション自体を書くときも PhpStorm は便利です。

例えば、プロパティーのアノテーションを書く時は以下の順番で書くようにすると良さげです。

1. まず、プロパティーである `public $hoge;` を書く
2. 次に、上の行に移動して、`/**`まで書いてから、半角スペースを押す
3. すると、自動的に`/** @var  (この位置にカーソルが居る) */`という状態で、アノテーションの書き始め状態となる

※複数行のアノテーションがお好きなら、上記の 2. にて、半角スペースではなく、改行すると自動的に複数行のアノテーションになります。

## その他・まとめきれてないもの

なんで、 Model_User 自体に書かないのかの説明は省略。(まぁいいよね。)

Model のプロパティーに Observer_Typing 用の data_type が指定されていれば、 Task とか作って、型を判断して、アノテーションを詰め込んだ `__auto_completion.php`を自動生成も可能だなーとか思ってます。

なんだったら、 oil を拡張するほうが楽かもなーとか。(※他にも oil コマンダの特に generate には少し足りない感があるし。)

なんか、他にも書くべきことがある気がするんですが、とりあえず、今はココまで。