PHPStormにコード補完させる in CakePHP3のテンプレート

拡張子ctpで表されるテンプレートファイルはHTMLとPHPが混在するファイルで非常に便利です。

しかし、PHPStormには、テンプレートファイルが何のクラスのインスタンスなのか理解できません。コントローラから$this->set(compact('hoge'))のようにセットされた変数も同様です。

つまりコード補完も効きません。

コード補完を効かせるためには、テンプレートがどのインスタンスなのか等をPHPDocに書いてやる必要があります。

PHPDocで変数の型を補足するのは、 @var クラス 変数名 の書式です。

これをテンプレートファイルの先頭に書きます。

 

<?php
/**
*
* ①対象:テンプレートファイルすべて
* テンプレートはすべてこのインスタンスとなる
* @var \App\View\AppView $this
*
* ②対象:コントローラから変数をセットしているテンプレートすべて
* 変数が存在することを宣言、そして、その型を指定する
* 例1 シンプルな例
* @var String $season
* 例2 配列の場合
* @var \App\Model\Entity\User[][] $users
*
*/
?>

 

参考はここです。

bashalog.c-brains.jp

エンティティのデータを加工して取り出したいとき

仮想プロパティーの生成

アクセサーを定義することによって、現在存在しないフィールド・プロパティーへのアクセスを提供できます。 例えば、users テーブルが first_namelast_name 列を持っていたとして、 フルネームのためのメソッドを作れるということです。

namespace App\Model\Entity;

use Cake\ORM\Entity;

class User extends Entity
{

    protected function _getFullName()
    {
        return $this->_properties['first_name'] . '  ' .
            $this->_properties['last_name'];
    }

}

仮想プロパティーは、エンティティーに存在するかのようにアクセスできます。 プロパティー名は小文字と ”_” を使ってメソッド名を表記します。

echo $user->full_name;

引用元:エンティティー

 

関連のあるテーブルをまとめて持ってくる

アソシエーション - モデル同士を繋ぐ

例えば、
articles(id, title, text, author_id)とauthors(id,name)というテーブルがあるとする。

記事を取得するとき、筆者の名前もまとめて持ってきたいときは、

①$this->belongsTo('Authors')->setForeignKey('author_id');をArticlesTableのinitializeに記述する。
なお、setForeignKeyの引数は、外部キーの列名が被参照テーブル名の単数形 + _idのときは省略できる。つまり今回は省略できる。もしarticles(id, title, text,hissha_id)だったら省略できない。

②find()->contain(['Authors'])という風に、find()するときまとめたいテーブルや列名を指定する

CakePHP3でfind()した結果を自然な順にソートする

intではなくcharに数字を入れているとき

1

10

~~~~~

19

2

20

とソートされる。

自然順にソートするのは


$answers = $this->TfAns->find()
->where(['TfAns.regnum = ' => $regnum])
->toArray();
$answers = new Collection($answers);
$answers = $answers->sortBy('qesnum',SORT_NATURAL);

MVVMのプロジェクトを読む アクティビティのonCreate()編

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//レイアウトをセットしbindingを得る
binding = DataBindingUtil.setContentView(this, R.layout.main_activity);
// ビューモデルを生成する
// ContextはStringリソースの取得と、モデル(Retrofitインスタンス)の取得に使用する
// リスナ(ビューモデルの通知先)としてこのビュー(アクティビティ)を渡す
mainViewModel = new MainViewModel((Context)this,(MainViewModel.DataListener)this);
// ビュー(レイアウト)とビューモデルの紐付け
binding.setViewModel(mainViewModel);
// このbinding.toolbarやbinding.reposRecyclerViewは
// レイアウトのXMLファイルのビューのIDを参照する
this.setSupportActionBar(binding.toolbar);
this.setupRecyclerView(binding.reposRecyclerView);
}

インテント先のアクティビティにstart(Object data)を実装することのメリット

AアクティビティからBアクティビティにインテントする際、

AアクティビティではなくBアクティビティのstaticメソッドでIntentを生成すると、

putExtra()のキーが散らからない。

public static void start(Context context, String fullRepositoryName) {
final Intent intent = new Intent(context, DetailActivity.class);
intent.putExtra(EXTRA_FULL_REPOSITORY_NAME, fullRepositoryName);
context.startActivity(intent);
}

フラグメントのコメントの訳

package com.example.apitestapp;

import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;


/**
* このフラグメントを内包するアクティビティはインタラクションイベントを受け取るために
* BlankFragment.OnFragmentInteractionListenerを実装する必要あり
* このフラグメントのインスタンスを生成するにはBlankFragment#newInstanceを使用する
*/
public class BlankFragment extends Fragment {

private OnFragmentInteractionListener mListener;

public BlankFragment () {
// リフレクションされるため必要
}

public static BlankFragment getInstance () {
return new BlankFragment ();
}

@Override
public void onCreate ( Bundle savedInstanceState ) {
super.onCreate ( savedInstanceState );
}

@Override
public View onCreateView ( LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState ) {
// Inflate the layout for this fragment
return inflater.inflate ( R.layout.fragment_blank, container, false );
}

// TODO: Rename method, update argument and hook method into UI event
public void onButtonPressed ( Uri uri ) {
if ( mListener != null ) {
mListener.onFragmentInteraction ( uri );
}
}

//アクティビティによる利用が始まったとき実行される
@Override
public void onAttach ( Context context ) {
super.onAttach ( context );
//利用元アクティビティがインタラクションリスナを実装しているとき
if ( context instanceof OnFragmentInteractionListener ) {
//アクティビティをリスナとしてメンバ変数に設定
mListener = (OnFragmentInteractionListener) context;
} else {
//例外を投げる
throw new RuntimeException ( context.toString ()
+ " must implement OnFragmentInteractionListener" );
}
}

//アクティビティから切り離されたとき実行される
@Override
public void onDetach () {
super.onDetach ();
mListener = null;
}

//このフラグメントを利用するフラグメントが実装しなければならないリスナインタフェース
public interface OnFragmentInteractionListener {
void onFragmentInteraction ( Uri uri );
}
}