|
|
112行目: |
112行目: |
|
| |
|
| 「[https://packagist.org/search/?tags=search Packagist]」の検索結果をみても、tntsearchが特に人気の模様。 | | 「[https://packagist.org/search/?tags=search Packagist]」の検索結果をみても、tntsearchが特に人気の模様。 |
|
| |
| == CakePHP ==
| |
|
| |
| === Basic ===
| |
|
| |
| ==== Structure ====
| |
|
| |
| * bin: cakeコマンド類。
| |
| * config: CakePHPの全体設定にかかるファイル群。
| |
| * logs
| |
| * plugins
| |
| * src
| |
| * tests
| |
| * tmp
| |
| * vendor
| |
| * webroot: アプリケーションルート。
| |
|
| |
| ===== Convention =====
| |
| Ref: [https://book.cakephp.org/3/ja/intro/conventions.html CakePHP の規約 - 3.10].
| |
|
| |
| テーブル名は小文字、複数形、アンダーバー区切り。
| |
|
| |
| ===== Routing =====
| |
| Ref: [https://book.cakephp.org/3/ja/development/routing.html#index-0 ルーティング - 3.10].
| |
|
| |
| config/routes.phpでルーティングの基本が設定される。ここのコードで、後述のMVCがある程度自動設定されている。
| |
|
| |
| ほかに、アプリケーショントップの/アクセス時の処理を行う、重要な設定もここで行う。/はMVCの命名規則になっていないので、ここは手動設定?的なことが必要になる。基本はここがLoginになる。
| |
|
| |
| Router::scopeとRouter::connectを使って処理する。
| |
|
| |
| scopeはルーティングのグループ化。connectで個別に紐づける。<syntaxhighlight lang="php">
| |
| Router::scope('/blog', ['plugin' => 'Blog'], function ($routes) {
| |
| $routes->connect('/', ['controller' => 'Articles']);
| |
| });
| |
| </syntaxhighlight>例えば、上記は/blogへのアクセスをArticlesController.index()に紐づける。
| |
|
| |
| connectの第二引数にいろいろパラメーターを指定できて、actionのメソッドを指定できたりする。
| |
|
| |
| ==== Controller ====
| |
| AppControllerを継承して定義する。indexメソッドを最低限実装しておく。
| |
|
| |
| XXXControllerのXXXの小文字部分がURLになっていて、これでアクセスするとindexが発動する。
| |
|
| |
| メソッド名が、パスになっていて、それで表示される。このパスメソッドを一般的にacitonと呼んでいる。
| |
|
| |
| $this->request
| |
|
| |
| リクエストに関する情報が入っている。PHPの$_FILESとか$_POSTなどを使わなくも、これを使えばよくなる。
| |
|
| |
| 2次元配列にもなっているが、1次元配列部分はプロパティーとしてもアクセスできる。
| |
|
| |
| * params: 送信されたすべてが入っている。
| |
| * data: POSTのボディー。
| |
| * query: URLクエリー。
| |
| * url
| |
| * base
| |
| * webroot
| |
| * here:
| |
|
| |
| 特にdataをよく使うだろう。
| |
|
| |
| ===== Component =====
| |
| Ref: [https://book.cakephp.org/3/ja/controllers/components.html コンポーネント - 3.10].
| |
|
| |
| コントローラー間で共有されるロジックのパッケージ。認証など処理を共通化できる。
| |
| $this->loadComponent('コンポーネント');
| |
| これでコンポーネントを読み込めて、以降は$this->コンポーネントでインスタンスにアクセスできる。
| |
|
| |
| ==== View ====
| |
| Ref: [https://book.cakephp.org/3/ja/views.html ビュー - 3.10].
| |
|
| |
| Controllerで表示もできるものの、Viewで表示部分をメインにすることもできる。
| |
|
| |
| Viewはビューテンプレートとレイアウトで大きく構成される。
| |
|
| |
| テンプレートは実際のページ表示用。レイアウトは、テンプレートを含み、ヘッダー、フッターなどをまとめている。
| |
|
| |
| レイアウトを用意して、その中にビューテンプレートを埋め込んで表示するイメージ。これにより、ページ全体でレイアウトを統一しやすくなる。
| |
|
| |
| テンプレートファイルのデフォルトの拡張子は.ctp (CakePHP Templateの略)。
| |
|
| |
| ===== Template =====
| |
| src/TemplateがViewテンプレート。ここにコントローラー名に対応したディレクトリーを作って、そこにViewテンプレートを作成する。
| |
|
| |
| 例えば、src/Template/Helloにindex.ctpを用意する。
| |
|
| |
| Controller側で、public $autoRender = true;があると、テンプレートを使う。命名規則で自動的に。
| |
|
| |
| そして、$this->viewBuilder()->autoLayout(false) でレイアウトの使用可否を設定する。
| |
|
| |
| index.ctpはテンプレートなので、ここにPHPコードを記入してもOK。
| |
|
| |
| テンプレート内では変数が使える。この変数は、コントローラーで$this->setで設定されたものになる。
| |
|
| |
| 基本的には以下のようなphpコードで埋め込む。
| |
| <?php echo $variable; ?>
| |
| <?= $variable ?>
| |
|
| |
| ===== Layout =====
| |
| デフォルトで使用するレイアウトは、src/Template/Layout/default.ctpにある。
| |
|
| |
| ここにファイルを追加することが、レイアウトの作成になる。
| |
|
| |
| レイアウト内で、テンプレートを表示する関数類がある。
| |
|
| |
| * $this->fetch('content'): ビューテンプレート
| |
|
| |
| Controller側では、$this->viewBuilder()->layout('Hello');でレイアウトを指定できる。
| |
|
| |
| ===== Element =====
| |
| レイアウトよりも小さいパーツ。ボタンなど、流用するようなものをElementとして用意できる。
| |
|
| |
| $this->element(エレメント名, [キー=>値,...])で表示できる。
| |
|
| |
| src/Template/Element内に作成する。エレメント名.ctpで作成する。キー=>値の関係で、パラメーターを渡せる。
| |
|
| |
| Controllerのaction内でsetで、layout内で使用する変数を指定できる。これで、layout-element間で変数を渡せる。
| |
|
| |
| ==== Model ====
| |
| DBを処理する部分。
| |
|
| |
| ===== 具体的には、テーブルクラス (テーブルへのアクセス処理) とエンティティークラス (テーブルから取り出した1行分のデータのための列の表現) で実現する。 =====
| |
| CakePHP内では、モデル名Table/モデル名でそれぞれ命名する。テーブルクラスは複数形、エンティティークラスは単数形で扱う。テーブル自体も複数形。
| |
|
| |
| CakePHPでDBにアクセスする際には、まず設定ファイルにDBの情報を用意する。Config/app.phpのDatasourcesのdefaultに入力する。
| |
|
| |
| モデル自体は、src/Model内に配置する。EntityとTableディレクトリーでそれぞれ用意する。
| |
|
| |
| 継承するだけで、基本的な動作は機能する。
| |
|
| |
| Controllerから、これらのモデルにアクセスする。
| |
|
| |
| DBへのアクセスにはORMのQueryBuilderとSQLベースのConnectionManagerがある。
| |
|
| |
| ===== ConnectionManager =====
| |
| Ref: [https://book.cakephp.org/3/ja/orm/database-basics.html データベースの基本 - 3.10].
| |
|
| |
| SQLをそのまま発行するタイプのクラス。
| |
| $conn = ConnectionManager::get('設定名');
| |
| $statement = $conn->execute('SQL');
| |
| $statement->fetchAll('num' | 'assoc');
| |
| ConnectionManagerからConnectionインスタンスを取得し、DBオブジェクトとして扱う。
| |
|
| |
| executeでステートメントを取得し、statementのメソッド呼び出しのタイミングでSQLが実行される。
| |
|
| |
| 実行結果は配列。numを指定すると、キーが数字、assocだと項目名 (カラム名) がキーになる。基本はassocを指定するとよい模様。
| |
|
| |
| ===== TableRegistry =====
| |
| Ref: [https://book.cakephp.org/3/en/orm/saving-data.html Saving Data - 3.10].
| |
| use Cake\ORM\TableRegistry;
| |
|
| |
| // Prior to 3.6 use TableRegistry::get('Articles')
| |
| $articlesTable = TableRegistry::getTableLocator()->get('Articles');
| |
| $article = $articlesTable->get(12); // Return article with id 12
| |
|
| |
| $article->title = 'CakePHP is THE best PHP framework!';
| |
| $articlesTable->save($article);
| |
| 組み込まれていないテーブルはgetで取得する必要がある。
| |
|
| |
| ===== Basic =====
| |
|
| |
| ====== Query logging ======
| |
| Ref: [https://book.cakephp.org/3/en/orm/database-basics.html#query-logging Database Basics - 3.10].
| |
| // クエリーログを有効
| |
| $conn->logQueries(true);
| |
|
| |
| // クエリーログを停止
| |
| $conn->logQueries(false);
| |
| CakePHPのクエリービルダーの実際のSQLを確認できる。
| |
|
| |
| 「[https://qiita.com/cranpun/items/09be1b43f115305e108e [cakephp] Queryオブジェクトから実行したSQL生成 #MySQL - Qiita]」にあるように、他に、sql()やgetValueBinder()->bindings();でも取得できる。
| |
| $this->log($this->MBase->findMBase($options)->sql());
| |
|
| |
| ====== データの取り出しと結果セット ======
| |
| Ref: [https://book.cakephp.org/3/ja/orm/retrieving-data-and-resultsets.html#finder データの取り出しと結果セット - 3.10].
| |
|
| |
| hydrate(false)でfindなどした際の結果を、オブジェクトではなく配列にできる。
| |
|
| |
| ==== Migration ====
| |
| Ref:
| |
|
| |
| * [https://book.cakephp.org/migrations/3/ja/index.html Migrations - 3.x]
| |
| * [https://qiita.com/ozawan/items/8144e02ca70519f3dcaf CakePHP3のマイグレーションまとめ #cakephp3 - Qiita]
| |
| * [https://book.cakephp.org/phinx/0/en/index.html Phinx Documentation - 0.13]
| |
|
| |
| PHPファイルでDBのスキーマ変更を行うための仕組み。VCSでDB設定を管理でき、コマンドでDBの設定などを行える利点がある。
| |
|
| |
| CakePHPでは、Phinxをマイグレーションに使っており、コマンド類はPhinxのラッパーになっている。細かいことはPhinxにあたる必要がある。
| |
|
| |
| config/Migrationsディレクトリーに、マイグレーションファイルを配置し、以下のmigrationsコマンドの実行でDBにテーブルを作成できる。
| |
| bin/cake migrations migrate
| |
| bin/cake migrations rollback
| |
| 戻す場合はrollback。
| |
|
| |
| マイグレーションファイルは、config/Migrationディレクトリーで、YYYYmmddHHMMSS_MigrationName.phpというように、作成日を入れて用意する。
| |
|
| |
| 自分で手作業でマイグレーションファイルを作成できるが、bakeコマンドでひな形を用意できる。これを使ったほうがおそらくいい。
| |
|
| |
| ===== マイグレーションファイル =====
| |
|
| |
| ====== Valid Column Types ======
| |
| <code>Phinx</code> で一般的に利用可能なフィールドの型は次の通り:
| |
|
| |
| * string
| |
| * text
| |
| * integer
| |
| * biginteger
| |
| * float
| |
| * decimal
| |
| * datetime
| |
| * timestamp
| |
| * time
| |
| * date
| |
| * binary
| |
| * boolean
| |
| * uuid
| |
|
| |
| このほかに、以下も可能。
| |
|
| |
| In addition, the MySQL adapter supports <code>enum</code>, <code>set</code>, <code>blob</code>, <code>tinyblob</code>, <code>mediumblob</code>, <code>longblob</code>, <code>bit</code> and <code>json</code> column types (<code>json</code> in MySQL 5.7 and above). When providing a limit value and using <code>binary</code>, <code>varbinary</code> or <code>blob</code> and its subtypes, the retained column type will be based on required length (see [[/book.cakephp.org/phinx/0/en/migrations.html#limit-option-and-mysql|Limit Option and MySQL]] for details);
| |
|
| |
| In addition, the Postgres adapter supports <code>interval</code>, <code>json</code>, <code>jsonb</code>, <code>uuid</code>, <code>cidr</code>, <code>inet</code> and <code>macaddr</code> column types (PostgreSQL 9.3 and above).
| |
|
| |
| ====== 既存のテーブルにカラムを追加 ======
| |
| 以下のコマンドでカラム追加を含むコードを作成できる。
| |
| bin/cake bake migration AddPriceToProducts price:decimal
| |
|
| |
| <?php
| |
| use Migrations\AbstractMigration;
| |
|
| |
| class AddPriceToProducts extends AbstractMigration
| |
| {
| |
| public function change()
| |
| {
| |
| $table = $this->table('products');
| |
| $table->addColumn('price', 'decimal')
| |
| ->update();
| |
| }
| |
| }
| |
| addColumnの3引数にいろいろパラメーターを指定できる。
| |
| public function change()
| |
| {
| |
| $table = $this->table('m_grade');
| |
| $table->addColumn('image_data', 'blob', [
| |
| 'default' => null,
| |
| 'limit' => Phinx\Db\Adapter\MysqlAdapter::BLOB_MEDIUM,
| |
| 'null' => true,
| |
| 'after' => 'image_path',
| |
| ]);
| |
| $table->update();
| |
| }
| |
| afterで直前の列を指定できる。
| |
|
| |
| ====== Blobの対応 ======
| |
|
| |
| * [https://qiita.com/oppara/items/a903e174136049aa9137 CakePHP Migrations の limit オプションについて #PHP - Qiita]
| |
| * [https://qiita.com/1roh/items/0e40585214c26fbdf5cb cakephp3 の Migration で mediumblob を認識させる #MySQL - Qiita]
| |
|
| |
| CakePHP自体は、MySQLのblobには直接は対応していない。binaryでひな形を作って、手動でlimitを変更する。
| |
|
| |
| ====== 列の更新 ======
| |
| <blockquote>Updating columns name and using Table objects
| |
|
| |
| If you use a CakePHP ORM Table object to manipulate values from your database along with renaming or removing a column, make sure you create a new instance of your Table object after the <code>update()</code> call. The Table object registry is cleared after an <code>update()</code> call in order to refresh the schema that is reflected and stored in the Table object upon instantiation.
| |
|
| |
| https://book.cakephp.org/migrations/3/en/#updating-columns-name-and-using-table-objects</blockquote>
| |
|
| |
| ===== updateした後に、CakePHPのORMを使う模様。 =====
| |
| // Update exisiting column default row data from path.
| |
| $mbaseTable = TableRegistry::get('m_base');
| |
| foreach($mbaseTable->find() as $row) {
| |
| $file_path = WWW_ROOT . $row->LOGO_PATH;
| |
| if (is_readable($file_path)) {
| |
| $raw_data = file_get_contents($file_path);
| |
| if ($raw_data) {
| |
| $row->LOGO_DATA = $raw_data;
| |
| $mbaseTable->save($row);
| |
| }
| |
| }
| |
| }
| |
| こういうイメージ。
| |
|
| |
| ===== Debug =====
| |
| Ref:
| |
|
| |
| * [https://book.cakephp.org/3/ja/development/debugging.html デバッグ - 3.10]
| |
| * [https://www.sejuku.net/blog/28383 【CakePHP入門】デバッグ(debug)を使ってみよう! | 侍エンジニアブログ]
| |
|
| |
| CakePHP関係のクラスであればlogメソッドがある。
| |
|
| |
| 他に、[[/book.cakephp.org/3/ja/core-libraries/logging.html#Cake%5CLog%5CLog::write|<code>Cake\Log\Log::write()</code>]]のstaticメソッドもある。
| |
|
| |
| Log::debug('text')などで使う。
| |
|
| |
| * pr: print_r+pre
| |
| * debug:
| |
| * dd: debug+die
| |
| Log::debug()を使うと、logs/debug.logに出力される。
| |
|
| |
| === Topic ===
| |
|
| |
| ==== Pagination ====
| |
| コントローラーのpublic $paginateプロパティーに、ページネーションの設定を記載する。
| |
|
| |
| その後、$this->paginate(テーブル)で自動的にページネーションされたデータを取得できる。
| |
|
| |
| ==== Test ====
| |
| Ref: [https://book.cakephp.org/3/ja/development/testing.html テスト - 3.10].
| |
|
| |
| CakePHPはPHPUnitでのテストに対応している。
| |
|
| |
| まずDBをテスト用に置換する。config/app.phpのDatasourcesにtestを追加しておく。
| |
|
| |
| bakeコマンドの中で、fixtureとtestが関係するコマンド。
| |
|
| |
| まずfixtureでテストデータを作成する。
| |
| cake bake fixture <model>
| |
| modelでMVCの一単位を指定する。
| |
|
| |
| 続いて以下のコマンド群でMVCのテストファイルを作成。
| |
| cake bake test controller <Controller>
| |
| cake bake test entiity <Entity>
| |
| cake bake test table <nowiki><Table></nowiki>
| |
| testsディレクトリー内の以下に生成される。
| |
|
| |
| * Fixture: テーブル名Fixture.php
| |
| * TestCase: クラス名Test.php
| |
|
| |
| Test.php内で、以下のコードで該当Fixtureを自動読み込みする。
| |
| public $fixtures ['app.テーブル名'];
| |
| TestCaseクラスがCakePHP特有で、これでうまくやっている模様。<syntaxhighlight lang="php">
| |
| namespace App\Test\TestCase\Model\Table;
| |
|
| |
| use App\Model\Table\ArticlesTable;
| |
| use Cake\ORM\TableRegistry;
| |
| use Cake\TestSuite\TestCase;
| |
|
| |
| class ArticlesTableTest extends TestCase
| |
| {
| |
| public $fixtures = ['app.Articles'];
| |
|
| |
| public function setUp()
| |
| {
| |
| parent::setUp();
| |
| $this->Articles = TableRegistry::getTableLocator()->get('Articles');
| |
| }
| |
|
| |
| public function testFindPublished()
| |
| {
| |
| $query = $this->Articles->find('published');
| |
| $this->assertInstanceOf('Cake\ORM\Query', $query);
| |
| $result = $query->enableHydration(false)->toArray();
| |
| $expected = [
| |
| ['id' => 1, 'title' => 'First Article'],
| |
| ['id' => 2, 'title' => 'Second Article'],
| |
| ['id' => 3, 'title' => 'Third Article']
| |
| ];
| |
|
| |
| $this->assertEquals($expected, $result);
| |
| }
| |
| }
| |
| </syntaxhighlight>そして、setUp内で、まずはテーブルをメンバー変数に格納して、それを参照する形。
| |
|
| |
| === Error ===
| |
|
| |
| ==== PHP message: PHP Warning: file_put_contents(/var/www/html/logs/error.log) [<nowiki><a href='http://php.net/function.file-put-contents'>function.file-put-contents</a></nowiki>]: failed to open stream: Permission denied in /var/www/html/vendor/cakephp/cakephp/src/Log/Engine/FileLog.php on line 133 ====
| |
| 起動してトップ画面を開くと、logs/error.logに以下のエラー。
| |
| 2024/04/04 07:27:48 [error] 30#30: *1 FastCGI sent in stderr: "PHP message: PHP Warning: file_put_contents(/var/www/html/logs/error.log) [<nowiki><a href='http://php.net/function.file-put-contents'>function.file-put-contents</a></nowiki>]: failed to open stream: Permission denied in /var/www/html/vendor/cakephp/cakephp/src/Log/Engine/FileLog.php on line 133
| |
| PHP message: PHP Warning: file_put_contents(/var/www/html/logs/error.log) [<nowiki><a href='http://php.net/function.file-put-contents'>function.file-put-contents</a></nowiki>]: failed to open stream: Permission denied in /var/www/html/vendor/cakephp/cakephp/src/Log/Engine/FileLog.php on line 133
| |
| パーミッションの設定がDockerに不足している?
| |
|
| |
| 「[https://qiita.com/keisukeYamagishi/items/44163d2c6df002a87d5e CakePHP Error Warning: file_put_contents(/var/www/html/logs/error.log) #PHP - Qiita]」にあるように、
| |
|
| |
| docker exec -ti php_jaccs_auto bashでchmod a+w ./logs/*相当を実行すると解決した。ただし、事前にWindowsのExplorerで書き込みを許可しておく必要がある。git bashのchmodはWindowsには機能しない。
| |
|
| |
| ==== Warning: Warning (512): SplFileInfo::openFile(/var/www/html/tmp/cache/persistent/myapp_cake_core_translations_cake_en__u_s) [<nowiki><a href='http://php.net/splfileinfo.openfile'>splfileinfo.openfile</a></nowiki>]: failed to open stream: Permission denied in [/var/www/html/vendor/cakephp/cakephp/src/Cache/Engine/FileEngine.php, line 398] ====
| |
| Ref: [https://blog.s-giken.net/383.html CakePHP3でWarning Error: SplFileInfo::openFile()エラーが発生した場合の対処方法 | エス技研].
| |
|
| |
| app.phpにmask=>0666を追加する。既存のキャッシュファイルは削除しておく。
| |
|
| |
| dockerのアクセス権www-dataの問題の気がする。
| |
|
| |
|
| [[Category:PHP]] | | [[Category:PHP]] |