「PHP」の版間の差分

提供:senooken JP Wiki
(PHPからLaravelを別ページに分離。Category:PHP付与。)
(PHPからCakePHPを分離。)
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]]

2024年8月23日 (金) 10:22時点における版

Library

Framework

  • Symfony
  • CakePHP
  • FuelPHP: 2010年誕生。
  • Codeigniter: シンプル、軽量。
  • Zend
  • Laravel: 2011年誕生。
  • Phalcon
  • Yii - Wikipedia

Template

いろいろある。

  • Blade: Laravel標準。
  • DIV: 1ファイルでシンプル。大規模には向かない。
  • Smarty: 万能。
  • Twig: 拡張はしにくい。

使うとしたら、歴史の長いSmarty。

高速らしい。

そもそもテンプレートエンジンがいるのかどうかという議論がある。

UI/UXを突き詰めると、JavaScriptを使わざるを得ず、サーバーテンプレートエンジンは初回だけなので、いっそのことJSで全部やろうというのが最近の流れの模様。

PHP自体が一種のテンプレートエンジンという主張がある。が、関数をあれこれ書く必要があり、可読性が悪い。

SmartyよりTwigのほうが性能が上とか。

Volt: テンプレートエンジン — Phalcon 3.0.2 ドキュメント (Japanese / 日本語)」。高速フレームワークのPhalconではVoltを使っている。

Twig

Twig v3のほうが速いらしいが、Smarty v3のほうが速いというデータもある。

Smarty

Pure PHP/HTML views VS template engines views - Stack Overflow」が決定的だった。Smartyの開発者がSmartyのほうがTwigより速いと回答していた。2012年。Smartyでいいと思う。

ORM

Ref:

いろいろある。Doctrineが有名。

  • Doctrine: Symfonyで採用。有名。
  • Eloquent
  • Propel: Symfony v1.2で採用されていた。
  • PHP activerecord
  • PHPDAO
  • PDO: PHP標準。
  • Xyster

ただ、速度を優先する場合、PDOが最速になるらしい。

ORMは別になくてもいいか。

Migrate

  • Phinx
  • Doctrine Migrations

PHPで「Doctrine Migrations」を使ってみる

CakePHPに採用されているPhinxのほうが人気なのでPhinxを使ったほうがよいだろう。

Test

  • PHPUnit

Search

検索キーワードをフォームから受信後、DBにSQLで検索をかけて取得結果を返すのが基本。

それとは別に、検索用のアプリにリクエストを受け渡しして検索するという方法がある。どちらでもいけるような、ドライバーのライブラリーがある。

検索サービスで有名なのは以下。

Laravel Scoutでtntsearchを使う方法がある (Laravel Scout + TNTSearchによる小規模プロジェクトへの全文検索機能の追加 #PHP - Qiita/Laravel ScoutとTNTSearchを使用してサイト全文検索を実装してみる – helog)。

Packagist」の検索結果をみても、tntsearchが特に人気の模様。