- 投稿日:2020-06-02T23:41:46+09:00
マイグレーション実行時にmysqlでユーザーを作成していなかった為エラー
マイグレーション実行時エラー
laravel7で新しくプロジェクトを作成したので
とりあえずマイグレーションの実行ししてみたらエラー発生
SQLSTATE[HY000] [1045] Access denied for user 'user_name'@'172.20.0.4' (using password: YES) (SQL: select * from information_schema.tables where table_schema =table_name and table_name = migrations and table_type = 'BASE TABLE')原因
ただ単に.envに設定したユーザーとパスワードを登録していなかっただけ
解決方法
mysqlでユーザーを作成をする
create user 'user_name' identified by 'pass';権限の確認
新規作成したユーザには
何も権限がないことを意味するUSAGEが付いているmysql> show grants for user_name@'%'; +---------------------------------------+ | Grants for phper@% | +---------------------------------------+ | GRANT USAGE ON *.* TO `user_name`@`%` | +---------------------------------------+ 1 row in set (0.00 sec)全てのDBが対象となるグローバル権限【CREATE権限】の付与
GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, RELOAD, PROCESS, REFERENCES, INDEX, ALTER, SHOW DATABASES, CREATE TEMPORARY TABLES, LOCK TABLES, EXECUTE, REPLICATION SLAVE, REPLICATION CLIENT, CREATE VIEW, SHOW VIEW, CREATE ROUTINE, ALTER ROUTINE, CREATE USER, EVENT, TRIGGER ON *.* TO 'user_name'@'%' WITH GRANT OPTION;実行後もう一度マイグレーションを実行したら成功
- 投稿日:2020-06-02T21:13:58+09:00
homebrewを使ってPHPのバージョンアップグレード
概要
homebrewを使ってPHPのバージョンアップグレードを行います。
php7.2系 → php7.3系homebrewのインストール
Homebrewのインストールがまだの方は、以下の記事を参考に導入をおこなってください。
手順
現在のバージョンを確認します。
$ php -v PHP 7.2.30 (cli) (built: Apr 23 2020 01:23:39) ( NTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies with Zend OPcache v7.2.30, Copyright (c) 1999-2018, by Zend Technologies現在バージョンはPHP 7.2.30であることが確認できました。
続いて
brew search
コマンドでインストール可能なPHPのバージョンを確認します。$ brew search php@7 ==> Formulae php@7.2 ✔ php@7.3 php@7.4現在インストールされているバージョンの横にチェックマークがついています。
brew install
コマンドでphp@7.3をインストールしましょう。brew install php@7.3これでphp@7.3をインストールすることができました。
続いてPATHを通す作業をします。
さきほどのインストール実行文の中に、PATHをまだ通してなかったら以下のコマンドを実行してくださいと書いてあります。If you need to have php@7.3 first in your PATH run: echo 'export PATH="/usr/local/opt/php@7.3/bin:$PATH"' >> ~/.bash_profile echo 'export PATH="/usr/local/opt/php@7.3/sbin:$PATH"' >> ~/.bash_profileこれをこのままコピー&ペーストして実行します。
$ echo 'export PATH="/usr/local/opt/php@7.3/bin:$PATH"' >> ~/.bash_profile$ echo 'export PATH="/usr/local/opt/openldap/sbin:$PATH"' >> ~/.bash_profileこちらも実行文の中に書かれているのですが、
PHP を自動起動するよう設定をしてから再起動すればphp@7.3になるとのことです。To have launchd start php@7.3 now and restart at login: brew services start php@7.3 Or, if you don't want/need a background service you can just run: php-fpm以下のコマンドを実行します。
$ brew services start php実行後、ターミナルアプリを開き直して
$ php -v
でバージョンを確認$ php -v PHP 7.3.17 (cli) (built: Apr 29 2020 17:27:16) ( NTS ) Copyright (c) 1997-2018 The PHP Group Zend Engine v3.3.17, Copyright (c) 1998-2018 Zend Technologies with Zend OPcache v7.3.17, Copyright (c) 1999-2018, by Zend Technologies無事 php@7.2系 から php@7.3系 にバージョンアップすることができました。
以上でhomebrewを使ってPHPのバージョンアップグレードは終了です。
お疲れ様でした。
- 投稿日:2020-06-02T21:11:27+09:00
DockerでWebアプリ環境構築
はじめに
本記事は動画( https://youtu.be/vY2z-fOOh6s )で説明に使用している
スライドを記事化したものです。動画と合わせて御覧ください。
※記事化する際に補足説明を加筆しており、内容は動画のスライドと異なります。
※本記事の内容は2020年3月時点の内容となります。OSやミドルウェア、Dockerのバージョンが異なることで記載通りの内容で完了しない場合があります。
構築する環境の構成
- O S : Cent OS 7.7
- Webサービス : Apache 2.4.6
- DBサービス :MariaDB 10.4.6
- Webアプリ言語:PHP 7.3.x
OSの準備
前回の動画: https://www.youtube.com/watch?v=oT-GSZD8bE4
前回の動画の概要:Dokcerインストール、CentOSのインストール。
1. コンテナ起動dos > docker run --privileged -d -p 22:22 -p 80:80 -p 8080:8080 -p 443:443 --name [作成コンテナ名] [イメージ名] /sbin/init dos > docker exec -it [コンテナ名] /bin/bash コンテナ > yum update
- ユーザの追加
root > useradd [ユーザ名] root > passwd [ユーザ名]
- SSHインストールと接続!
root > yum install openssh-server root > systemctl enable sshd.service root > systemctl start sshd.service接続はTeraTermをインストールして接続。
Webサービスの準備
- Apacheをインストール
root > yum install httpd※CentOS標準のapacheをインストール
DBサービスの準備
- MariaDBリポジトリの追加
root > curl -sS https://downloads.mariadb.com/MariaDB/mariadb_repo_setup | bash
- MariaDBのインストール
root > yum install MariaDB-server ※MariaDBパッケージにアップデートがある場合は root > yum update MariaDB-server
- DBサーバの設定
root > vi /etc/my.ini/
- サーバ自動起動の設定とサーバ起動
root > systemctl enable mariadb root > systemctl start mariadb
- ユーザの設定
root > mysql mysql > GRANT ALL PRIVILEGES ON *.* TO 'ユーザー名'@'ホスト名' IDENTIFIED BY 'パスワード' WITH GRANT OPTION; mysql > FLUSH PRIVILEGES;
Webアプリ言語のインストール
- リポジトリの追加
> yum -y install http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
- バージョンの確認
> yum info --enablerepo=remi,remi-php73 php php-mbstring php-xml php-xmlrpc php-gd php-pdo php-pecl-mcrypt php-mysqlnd php-pecl-mysql
- PHPインストール
> yum -y install --enablerepo=remi,remi-php73 php php-mbstring php-xml php-xmlrpc php-gd php-pdo php-pecl-mcrypt php-mysqlnd php-pecl-mysql
- PHPのインストール確認
> php -v
Webサービスの設定
- ドキュメントルートの設定
root > mkdir /var/www/webapp root > chown takemi:takemi webapp root > vi /etc/grouptakemi: x :1000: → takemi : x : 1000 : apache
※takemiはadduser作成した一般ユーザです。adduserしたタイミングでユーザと同名のグループも作成されます。root > systemctl restart httpd user > vi /var/www/webapp/index.htmlindex.html<html> <head> <title>Takemi Index</title> </head> <body> <div>Test Page</div> </body> </html>root > vi /etc/httpd/conf/httpd.confhttpd.confDocumentRoot=/var/www/html → DocumentRoot=/var/www/webapp <Directory “/var/www/html”> → <Directory “/var/www/webapp”> Options Indexes FollowSymLinks → Options Indexes FollowSymLinks ExecCGI AllowOverride None → AllowOverride All
設定の確認
ブラウザでhttp://<コンテナのIP>にアクセスするPHPの動作確認
ブラウザでhttp://<コンテナのIP>にアクセスするPHPの動作確認
user > vi /var/www/webapp/info.phpinfo.php<?php phpinfo();ブラウザで http://<コンテナのIP>/info.php にアクセスする。
phpinfo()の内容が表示される。
以上です!
これでHTMLもPHPも動作し、Webアプリの環境が整いました!
おつかれさまでした~
- 投稿日:2020-06-02T19:21:29+09:00
LaravelプロジェクトからFirebaseAPIを利用する前準備
環境について
OS:AmazonLinux21.サービスアカウントキーを作成する
GoogleCloudPlatformの認証サービス画面より
「サービスアカウントキー」を作成する
※APIキーではないサービスアカウント
「firebase-adminsdk」を選択キータイプ
「JSON」
を選択して、作成する2.環境変数を設定する
1.で取得したJSONファイルをLaravelプロジェクトのディレクトリに配置し
環境変数(GOOGLE_APPLICATION_CREDENTIALS)にファイルパスをセットするexport GOOGLE_APPLICATION_CREDENTIALS="Laravelプロジェクトのディレクトリ/*****.json"3.gRPC For PHPのインストール
こちらのGoogleのガイドを参考にgrpcをインストール
https://cloud.google.com/php/grpc?hl=ja
# pecl install grpc Build complete. Don't forget to run 'make test'. running: make INSTALL_ROOT="/var/tmp/pear-build-rootyXfFt6/install-grpc-1.26.0" install Installing shared extensions: /var/tmp/pear-build-rootyXfFt6/install-grpc-1.26.0/usr/lib64/php/modules/ running: find "/var/tmp/pear-build-rootyXfFt6/install-grpc-1.26.0" | xargs ls -dils 9083594 0 drwxr-xr-x 3 root root 17 12月 23 20:06 /var/tmp/pear-build-rootyXfFt6/install-grpc-1.26.0 11304125 0 drwxr-xr-x 3 root root 19 12月 23 20:06 /var/tmp/pear-build-rootyXfFt6/install-grpc-1.26.0/usr 19801702 0 drwxr-xr-x 3 root root 17 12月 23 20:06 /var/tmp/pear-build-rootyXfFt6/install-grpc-1.26.0/usr/lib64 27955984 0 drwxr-xr-x 3 root root 21 12月 23 20:06 /var/tmp/pear-build-rootyXfFt6/install-grpc-1.26.0/usr/lib64/php 3604422 0 drwxr-xr-x 2 root root 21 12月 23 20:06 /var/tmp/pear-build-rootyXfFt6/install-grpc-1.26.0/usr/lib64/php/modules 3604421 35144 -rwxr-xr-x 1 root root 35985152 12月 23 20:06 /var/tmp/pear-build-rootyXfFt6/install-grpc-1.26.0/usr/lib64/php/modules/grpc.so Build process completed successfully Installing '/usr/lib64/php/modules/grpc.so' install ok: channel://pecl.php.net/grpc-1.26.0 configuration option "php_ini" is not set to php.ini location You should add "extension=grpc.so" to php.iniPHPのgrpc拡張機能を有効にする。
# vi /etc/php.d/20-grpc.ini ; Enable gRPC extension module extension=grpc.so # systemctl restart httpd4.FirebaseAPIライブラリを追加
LaravelプロジェクトにFirebaseAPIライブラリを追加します。
#composer require "grpc/grpc:^v1.1.0" #composer require "google/protobuf:^v3.3.0" #composer require google/cloud-firestore
- 投稿日:2020-06-02T18:12:04+09:00
MacでLaravel開発環境構築
概要
環境
macOS Mojave 10.14.6
Homebrewのインストール
Homebrewとはパッケージのインストールやアンインストールを簡単に行うことのできるパッケージ管理システムのひとつです。
Homebrewページに移動し、インストールコマンドをターミナルで実行します。
$ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"インストールできたか確認
$ brew -v Homebrew 2.2.15 Homebrew/homebrew-core (git revision 5385; last commit 2020-05-05)HomebrewでPHPをインストールする
以下のコマンドでインストールするPHPパッケージを確認する。
$ brew search php ==> Formulae brew-php-switcher php-code-sniffer php@7.2 ✔ phplint phpmyadmin phpunit php php-cs-fixer php@7.3 ✔ phpmd phpstan ==> Casks homebrew/cask/eclipse-php導入したいバージョンのPHPをインストールする。
$ brew install php@7.3インストールできたか確認
$ php -vComposerをインストールする
Composerとは、PHP向けのパッケージ管理システムです。
Homebrewでインストールする
$ brew install composerインストールできたか確認
$ composer -V※直接Composerをインストールする方法
Homebrewを利用せずこちらでComposerファイルを直接ダウンロードして配置する方法もあります。
ここから、最新バージョンのリンクをクリックしてください。
composer.pharというファイルがダウンロードフォルダにダウンロードされます。
続いて以下のコマンドを実行します。$ cd ~/Download/ $ sudo mv composer.phar /usr/local/bin/composerこれでいつでもcomposerが呼び出せるようになりました。
配置したcomposerのパーミッション(アクセス権)を変更します。
$ chmod a+x /usr/local/bin/composerこれでcomposerが実行できるようになりました。
Homebrewでインストールした時と同様に、
「composer -V」
で正常にインストールできているか確認しましょう。Laravelのインストール
Composerを用いてLaravelをインストールします。
#Laravelインストール $ composer global require "laravel/installer"環境変数PATHの設定
$ echo "export PATH=~/.composer/vendor/bin:$PATH" >> ~/.bash_profile source ~/.bash_profilelaravelのバージョン確認
$ php artisan -V以上で、Laravel開発環境の構築は終了です。
お疲れ様でした。
- 投稿日:2020-06-02T17:02:07+09:00
LaravelでどうしてもSESSIONが追加できないときにすること
こんなにもシンプルなSESSIONが追加できない
app/Http/Controllers/HogeController.phppublic function show() { if (!Session::has('token')) { Session::put('token', 'token!'); var_dump('saved!'); } var_dump(Session::get('token')); return view('welcome'); }初回のみ「saved!token!」と表示され、2回目以降は「token!」となってほしい。
しかし、何度試しても「saved!token!」が表示される。不用意にダンプしたらダメなんだってさ
https://laracasts.com/discuss/channels/laravel/sessions-are-not-saving?page=1
sessions work fine, but only if your code exits normally and runs the terminable middleware. If you dd() in your code then the session is not saved
https://laravel.com/docs/5.5/middleware#terminable-middleware
you should also run php artisan route:list and check that you have web against each route, once only per route
テストコードのvar_dumpを削除したらセッションにちゃんと保存できた。
app/Http/Controllers/HogeController.phppublic function show() { if (!Session::has('token')) { Session::put('token', ’token!’); } return view('welcome'); }
- 投稿日:2020-06-02T16:53:02+09:00
【Laravel】Laravel上でスーパーグローバル「$_SERVER」を参照する。
メモとして残します。
$_SERVER
でも普通に参照できますが、フレームワークを使っている以上、スーパーグローバル変数を直接参照するのはどうかということで、一応、お作法にのっとって、Laravel上でスマートに参照する方法を紹介。下記の例ではLaravelのヘルパ
request
を使用して、帰ってきたオブジェクトのserver
プロパティを参照しています。■確認方法
$_SERVER要素全て
request()->server; //↓実行結果 // "MIBDIRS" => "C:/hoge/php/extras/mibs" // "MYSQL_HOME" => "\xampp\mysql\bin" // "OPENSSL_CONF" => "C:/hoge/apache/bin/openssl.cnf" // "PHP_PEAR_SYSCONF_DIR" => "\xampp\php" // "PHPRC" => "\xampp\php" // "TMP" => "\xampp\tmp" // "HTTP_HOST" => "hoge.www.com" // "HTTP_CONNECTION" => "keep-alive" // "HTTP_PRAGMA" => "no-cache" // "HTTP_CACHE_CONTROL" => "no-cache" // "HTTP_UPGRADE_INSECURE_REQUESTS" => "1" // "HTTP_USER_AGENT" => "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36" // "HTTP_ACCEPT" => "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9" // "HTTP_REFERER" => "http://hoge.www.com/" // "HTTP_ACCEPT_ENCODING" => "gzip, deflate" // "HTTP_ACCEPT_LANGUAGE" => "ja,en-US;q=0.9,en;q=0.8" // "HTTP_COOKIE" => "remember_web_59ba36addc2b2f9401580f014c7f58ea4e30989d=eyJpdiI6IjBIU1JxWVFCeG96T1RWeDFBcUtrVVE9PSIsInZhbHVlIjoieU5pRnVudTJub1wvTzJpUndLZlQ4MzNlaVlqdEZqK24xUTlQNX ▶" // "PATH" => "hoge" // "SystemRoot" => "C:\WINDOWS" // "COMSPEC" => "C:\WINDOWS\system32\cmd.exe" // "PATHEXT" => ".COM;.EXE;.BAT;.CMD;.VBS;.VBE;.JS;.JSE;.WSF;.WSH;.MSC" // "WINDIR" => "C:\WINDOWS" // "SERVER_SIGNATURE" => "<address>Apache/2.4.39 (Win64) OpenSSL/1.1.1c PHP/7.3.8 Server at hoge.www.com Port 80</address>" // "SERVER_SOFTWARE" => "Apache/2.4.39 (Win64) OpenSSL/1.1.1c PHP/7.3.8" // "SERVER_NAME" => "hoge.www.com" // "SERVER_ADDR" => "127.0.0.1" // "SERVER_PORT" => "80" // "REMOTE_ADDR" => "127.0.0.1" // "DOCUMENT_ROOT" => "C:/Develop/hogeproject/public" // "REQUEST_SCHEME" => "http" // "CONTEXT_PREFIX" => "" // "CONTEXT_DOCUMENT_ROOT" => "C:/Develop/hogeproject/public" // "SERVER_ADMIN" => "hoge@hoge.test.com" // "SCRIPT_FILENAME" => "C:/Develop/hogeproject/public/index.php" // "REMOTE_PORT" => "59332" // "GATEWAY_INTERFACE" => "CGI/1.1" // "SERVER_PROTOCOL" => "HTTP/1.1" // "REQUEST_METHOD" => "GET" // "QUERY_STRING" => "" // "REQUEST_URI" => "/" // "SCRIPT_NAME" => "/index.php" // "PHP_SELF" => "/index.php" // "REQUEST_TIME_FLOAT" => 1591082776.119 // "REQUEST_TIME" => 1591082776要素を指定して参照
//request()->server->get('要素名');//SERVER_NAMEなど request()->server->get('SERVER_NAME'); //↓実行結果 //localhost.hoge.com
- 投稿日:2020-06-02T15:26:20+09:00
Laravelの認証でwebとapiの両方を使う
LaravelでのAPIの認証は、こちをご参照ください。
→ LaravelでのJWT認証Laravelの認証は、
config/auth.php
にのguardにて設定しますが、defaultをapiに設定するとwebでの認証ができなくなってしまいます。config/auth.php'defaults' => [ 'guard' => 'api', // ← ここです。 'passwords' => 'users', ],一つのLaravelプロジェクトで、webとapiの両方を実装したいときの対応になります。
Laravelでは
auth()
や、Auth::login()
などで使用する認証は、guardのデフォルトの方となるようです。
デフォルト以外のものを使うときは、Auth::guard('[guard名]')->login()
とguardを指定して使用します。
そうすることで、webとapiの両立を実現します。defaultの設定
guardのdefaultはwebにしておきます。
make:authのコントローラーもそのまま使えるので便利です。config/auth.php'defaults' => [ 'guard' => 'web', 'passwords' => 'users', ],API側の認証のコントローラにてguardを指定する
実装例のAuthControllerは、LaravelでのJWT認証で使用したものです。
Quick startで紹介されているものから少しだけ修正しています。
それに対して、上記のようにauth()
をAuth::guard('api')
に変更します。app/Http/Controllers/Api/AuthController.php<?php namespace App\Http\Controllers\Api; use Illuminate\Http\Request; use Illuminate\Auth\Events\Registered; use Illuminate\Support\Facades\Auth; use App\Http\Controllers\Controller; class AuthController extends Controller { /** * Create a new AuthController instance. * * @return void */ public function __construct() { // $this->middleware('auth:api', ['except' => ['login']]); } /** * Get a JWT via given credentials. * * @return \Illuminate\Http\JsonResponse */ public function login() { $credentials = request(['email', 'password']); if (! $token = Auth::guard('api')->attempt($credentials)) { return response()->json(['error' => 'Unauthorized'], 401); } return $this->respondWithToken($token); } /** * Get the authenticated User. * * @return \Illuminate\Http\JsonResponse */ public function me() { return response()->json(auth()->user()); } /** * Log the user out (Invalidate the token). * * @return \Illuminate\Http\JsonResponse */ public function logout() { Auth::guard('api')->logout(); return response()->json(['message' => 'Successfully logged out']); } /** * Refresh a token. * * @return \Illuminate\Http\JsonResponse */ public function refresh() { try { return $this->respondWithToken(Auth::guard('api')->refresh()); } catch (\Tymon\JWTAuth\Exceptions\JWTException $e) { return response()->json(['error' => 'Unauthorized'], 401); } } /** * Get the token array structure. * * @param string $token * * @return \Illuminate\Http\JsonResponse */ protected function respondWithToken($token) { return response()->json([ 'access_token' => $token, 'token_type' => 'bearer', 'expires_in' => Auth::guard('api')->factory()->getTTL() * 60 ]); } }認証後のコントローラー
auth()->user()
は、変更しなくてもユーザー情報の取得はできているようなので、この認証を使って作成するAPI側は特にguardの指定はしなくてもよさそうです。
- 投稿日:2020-06-02T10:44:18+09:00
CakePHPのCounterCacheで関連件数を自動カウント
CakePHP には、紐づく別テーブルの件数が変わるとカウンター用カラムを自動的に更新してくれる、「CounterCache」というビヘイビアがあります。
ドキュメントにある利用例です。
たとえば、記事のリストを表示するときに、記事のコメントの数を表示することができます。 または、ユーザーを表示するときに、彼女が持っている友人/フォロワーの数を表示することもできます。 CounterCache ビヘイビアーは、これらの状況を想定しています。
https://book.cakephp.org/4/ja/orm/behaviors/counter-cache.htmlこのビヘイビアを使ってみようと思います。
テーブルを作成
まず、テーブルを作成します。
以下のようなテーブル構成とし、記事テーブルがコメント数とタグ数のカラムを持つものとします。
- 記事:コメント = 1:N (hasMany/belongsTo)
- 記事:タグ = N:N (belongsToMany)
/* PostgreSQL */ -- -- 記事 -- CREATE TABLE articles ( id SERIAL PRIMARY KEY, -- ID title TEXT NOT NULL, -- 記事タイトル body TEXT, -- 記事本文 name TEXT NOT NULL, -- 記事作者氏名 comment_count INTEGER, -- コメント数 tag_count INTEGER -- タグ数 ); -- -- コメント -- CREATE TABLE comments ( id SERIAL PRIMARY KEY, -- ID article_id INTEGER NOT NULL REFERENCES articles(id), -- 記事ID body TEXT, -- コメント本文 name TEXT NOT NULL -- コメント作者氏名 ); -- -- タグ -- CREATE TABLE tags ( id SERIAL PRIMARY KEY, -- ID tag TEXT UNIQUE NOT NULL -- タグ ); -- -- 記事 <-> タグ(中間テーブル) -- CREATE TABLE articles_tags ( article_id INTEGER REFERENCES articles(id), -- 記事ID tag_id INTEGER REFERENCES tags(id), -- タグID PRIMARY KEY (article_id, tag_id) );1. hasMany アソシエーションの場合
記事テーブルのコメント数カラム (
articles.comment_count
) を CounterCache で更新します。
なお、これはドキュメントの例と同じです。1-1. モデルの設定
cake bake
でコードを自動生成します。$ bin/cake bake model articles $ bin/cake bake model comments $ bin/cake bake model tags $ bin/cake bake model articles_tagsカウント対象の
CommentsTable
で、CounterCache ビヘイビアをロードします。/* src/Model/Table/CommentsTable.php(変更あり) */ public function initialize(array $config) { // ... 省略 ... $this->belongsTo('Articles', [ 'foreignKey' => 'article_id', 'joinType' => 'INNER', ]); // *** 以下 3行を追加 **** $this->addBehavior('CounterCache', [ 'Articles' => ['comment_count'] ]); }カウンターカラムを持つ
ArticlesTable
はcake bake
の自動生成コードのままです。/* src/Model/Table/ArticlesTable.php(変更なし) */ public function initialize(array $config) { // ... 省略 ... $this->hasMany('Comments', [ 'foreignKey' => 'article_id', ]); }1-2. 動作確認
save()
だけ試すのに Controller と Template を用意するのも面倒なので、ユニットテストで試してみます。テストファイルに、以下のようなコードを追加します。
/* tests/TestCase/Model/Table/ArticlesTableTest.php */ public function testCommentCount() { $this->Articles->Comments->deleteAll(['id IS NOT NULL']); $this->Articles->deleteAll(['id IS NOT NULL']); $data = [ 'title' => 'テスト記事タイトル', 'body' => 'テスト記事本文', 'name' => 'テスト記事作者', 'comments' => [ [ 'name' => 'テストコメント(1) 作者', 'body' => 'テストコメント(1) 本文', ], [ 'name' => 'テストコメント(2) 作者', 'body' => 'テストコメント(2) 本文', ], ], ]; $entity = $this->Articles->newEntity($data); $result = $this->Articles->save($entity); $article = $this->Articles->get($result->id, [ 'contain' => ['Comments'] ]); pr($article->toArray()); }また、テスト用のデータは不要なので、tests/Fixture/ 以下のファイルの
init()
で$this->records
の中身を空にしておきます。/* tests/Fixture/* */ public function init() { $this->records = []; parent::init(); }実行して
save()
後のget()
結果を見てみると、「comment_count」が更新されていることがわかります。$ vendor/bin/phpunit tests/TestCase/Model/Table/ArticlesTableTest.php --filter testCommentCount Array ( [id] => 1 [title] => テスト記事タイトル [body] => テスト記事本文 [name] => テスト記事作者 [comment_count] => 2 [tag_count] => [comments] => Array ( [0] => Array ( [id] => 1 [article_id] => 1 [body] => テストコメント(1) 本文 [name] => テストコメント(1) 作者 ) [1] => Array ( [id] => 2 [article_id] => 1 [body] => テストコメント(2) 本文 [name] => テストコメント(2) 作者 ) ) )=> TABLE articles; id | title | body | name | comment_count | tag_count ----+--------------------+----------------+----------------+---------------+----------- 1 | テスト記事タイトル | テスト記事本文 | テスト記事作者 | 2 | (1 row) => TABLE comments; id | article_id | body | name ----+------------+------------------------+------------------------ 1 | 1 | テストコメント(1) 本文 | テストコメント(1) 作者 2 | 1 | テストコメント(2) 本文 | テストコメント(2) 作者 (2 rows)2. belongsToMany アソシエーションの場合
記事テーブルのタグ数カラム (
articles.tag_count
) を CounterCache で更新します。ドキュメントに、belongsToMany アソシエーションで使うには、という説明があるのですが、例もなく、で、結局使えるのか?と不安になります。(StackOverflow でも解決したのか不明な質問が。。)
https://book.cakephp.org/4/ja/orm/behaviors/counter-cache.html#id2
CounterCache ビヘイビアーは、 belongsTo アソシエーションに対してのみ機能します。 たとえば、 "Comments belongsTo Articles" の場合、Article テーブルの comment_count を生成するために、 CommentsCache ビヘイビアーを CommentsTable に追加する必要があります。これを belongsToMany アソシエーションに対して機能させることは可能ですが、 アソシエーションオプションで設定されたカスタム through テーブルで CounterCache ビヘイビアーを有効にして cascadeCallbacks 設定オプションを true にする必要があります。 カスタム JOIN テーブルを設定する方法は 'through' オプションの使用 を参照してください。
結論としては、以下のとおり利用できました。
2-1. モデルの設定
CounterCache ビヘイビアを、中間テーブル
ArticlesTagsTable
でロードします。
(ドキュメントに、中間テーブルで、と書いていないのがわかりづらい・・・)/* src/Model/Table/ArticlesTagsTable.php(変更あり) */ public function initialize(array $config) { // ... 省略 ... $this->addBehavior('CounterCache', [ 'Articles' => ['tag_count'], ]); }次に
ArticlesTable
で belongsToMany アソシエーションを指定する箇所で、中間テーブルを指定するのに「joinTable
」の代わりに「through
」を使い、「cascadeCallbacks
」をTRUE
にします。belongsToMany アソシエーションの配列で可能なキー
https://book.cakephp.org/4/ja/orm/associations.html#belongstomany/* src/Model/Table/ArticlesTable.php (変更あり)*/ public function initialize(array $config) { // ... 省略 ... $this->belongsToMany('Tags', [ 'foreignKey' => 'article_id', 'targetForeignKey' => 'tag_id', // *** 以下の 1 行を削除かコメントアウト *** // 'joinTable' => 'articles_tags', // *** 以下の 2 行を追加 *** 'through' => 'articles_tags', 'cascadeCallbacks' => TRUE, ]); }なお、
TagsTable
は自動生成コードのまま変更ありません。/* src/Model/Table/TagsTable.php(変更なし) */ public function initialize(array $config) { // ... 省略 ... $this->belongsToMany('Articles', [ 'foreignKey' => 'tag_id', 'targetForeignKey' => 'article_id', 'joinTable' => 'articles_tags', ]); }2-2. 動作確認
同じく、ユニットテストで試します。
テストファイルに、以下のようなコードを追加します。/* tests/TestCase/Model/Table/ArticlesTableTest.php */ public function testTagCount() { $data = [ 'title' => 'テスト記事タイトル', 'body' => 'テスト記事本文', 'name' => 'テスト記事作者', 'tags' => [ [ 'tag' => 'タグ (1)', ], [ 'tag' => 'タグ (2)', ], ], ]; $entity = $this->Articles->newEntity($data); $result = $this->Articles->save($entity); $article = $this->Articles->get($result->id, [ 'contain' => ['Tags'] ]); pr($article->toArray()); }実行して
save()
後のget()
結果を見てみると、「tag_count」が更新されていることがわかります。$ vendor/bin/phpunit tests/TestCase/Model/Table/ArticlesTableTest.php --filter testTagCount Array ( [id] => 1 [title] => テスト記事タイトル [body] => テスト記事本文 [name] => テスト記事作者 [comment_count] => [tag_count] => 2 [tags] => Array ( [0] => Array ( [id] => 1 [tag] => タグ (1) [_joinData] => Array ( [article_id] => 1 [tag_id] => 1 ) ) [1] => Array ( [id] => 2 [tag] => タグ (2) [_joinData] => Array ( [article_id] => 1 [tag_id] => 2 ) ) ) )=> TABLE articles; id | title | body | name | comment_count | tag_count ----+--------------------+----------------+----------------+---------------+----------- 1 | テスト記事タイトル | テスト記事本文 | テスト記事作者 | | 2 (1 row) => TABLE tags; id | tag ----+---------- 1 | タグ (1) 2 | タグ (2) (2 rows) => TABLE articles_tags; article_id | tag_id ------------+-------- 1 | 1 1 | 2 (2 rows)補足
ドキュメントの最初に、以下のような注意書きがあります。
カウンターの値は、エンティティーが保存または削除されるたびに更新されます。 updateAll() または deleteAll() を使用するか、作成した SQL を実行すると、 カウンターは更新 されません。
https://book.cakephp.org/4/ja/orm/behaviors/counter-cache.html#id1これは、CounterCache ビヘイビアは 内部的 には、
save()
時に afterSave イベント として、カウンターカラムをUPDATE
していることによります。(delete()
時は afterDelete イベント)。
updateAll()
やdeleteAll()
では afterSave/afterDelete イベントが発生しないので、カウンターは更新されないことになります。https://book.cakephp.org/4/ja/orm/saving-data.html#Cake\ORM\Table::updateAll
- 投稿日:2020-06-02T07:25:09+09:00
Laravelのコレクションでユーザー(グループ)ごとに最新のメッセージを取得
うちでLaravelで質問回答アプリを実装しています。
対話者のメッセージボックスを作りたい、要件をまとめました:ログイン中のユーザーはuser_meとし、他のユーザーごとに一番新しいメッセージを提示するメッセージリストを作りたいです。
そこでクリックしたら、そのユーザーとのメッセージモダルに飛ぶ。
ユーザー名は相手の名前、メッセージは対話中の一番新しいメッセージ(自分からメッセージのも含む)SQLよりLaravelのコレクションはもっと使いやすいと思い、以下で案を。
まずuser_meと関わる全てのメッセージを時間順に並べて取得、次に対話両方をグループとし、一番新しいメッセージだけ、リストにプッシュする。
リストに登録済のグループのメッセージはプッシュしません。以下はMessageRepositoriesのメソッドの一部です。
namespace App\Repositories; public function selectMessageByEachUser() { $me_id = user('api')->id; $messages = Message::with(['fromUser', 'toUser']) ->where('to_user_id', $me_id) ->orwhere('from_user_id', $me_id) ->orderBy('created_at', 'desc') ->get(); $chat_room_groups = []; $new_messages = collect(); foreach ($messages as $message) { $match_ids_1 = [$message->from_user_id, $message->to_user_id]; $match_ids_2 = [$message->to_user_id, $message->from_user_id]; if ($new_messages->isEmpty()) { $new_messages->push($message); array_push($chat_room_groups, $match_ids_1); } else { $res = !in_array($match_ids_1, $chat_room_groups, true) && !in_array($match_ids_2, $chat_room_groups, true); if ($res) { $new_messages->push($message); array_push($chat_room_groups, $match_ids_1); } } } return $new_messages; }次にメッセージコントローラは処理したリストをもらい、APIリソースをフロントエンドに発信
namespace App\Http\Controllers; public function messageList() { $message=$this->message->selectMessageByEachUser(); return new MessageCollection($message); }どうせチャットルームグループは必要なら、グループに入るユーザーのIDと最新メッセージを保存するチャットルームのテーブルを作る方がいいかも?
メーセージを送信する際、新しいメッセージをテーブルに保存し、後処理はなしで、効率は上がります。今は勉強でLaravelとVue.jsで質問回答アプリを実装しています。
ソースコードは以下に公開:
https://github.com/joychoinjapan/syukudai.net
興味があれば、ご覧ください。
- 投稿日:2020-06-02T00:12:54+09:00
docker上のphpコンテナでcomposer installしたら、メモリ不足で落ちた話
はじめに
docker上でlaravelの開発していて、必要なライブラリをcomposerでインストールしようとしたら下記のエラーが出て詰まった、、、
↓エラーメッセージ
Using version ^4.3 for laravel/socialite ./composer.json has been updated Loading composer repositories with package information Updating dependencies (including require-dev) Fatal error: Allowed memory size of 1610612736 bytes exhausted (tried to allocate 4096 bytes) in phar:///usr/bin/composer.phar/src/Composer/DependencyResolver/Solver.php on line 223原因調査
コンテナに入って、以下のコマンドを実行
$ php -r 'phpinfo();' | grep memory_limit $ memory_limit => 128M => 128M確かにデフォルトのphpのメモリが少ない、、、
ちなみに -r は <?php を略したもので、
コマンドライン上でphpのプログラムを実行するためのオプションです!↓参照元 phpコマンドのオプション
https://www.php.net/manual/ja/features.commandline.options.php対処方法
- phpのコンテナのdockerファイルに以下を追加
php/DockerfileCOPY php.ini /usr/local/etc/php/
- php.iniをdockerファイルのディレクトリに作成
php/php.inimemory_limit = -1-1は上限なしという意味
- コンテナを再起動し中に入ってメモリを確認する
$ php -r 'phpinfo();' | grep memory_limit $ memory_limit => -1 => -1php.iniの設定に切り替わってる〜!
ナイスですね〜〜〜と全裸の監督から聞こえてきそうです!結果
もう一度composer installしたら、、、
Package manifest generated successfully無事インストールできました!マーベラス!