- 投稿日:2020-12-07T23:37:52+09:00
hintを追加したらtype errorで動かなくなった話
概要
laravelでmockeryを用いてunit testを作成中、以下のエラーが出た。
TypeError: Argument 1 passed to App\Http\Services\hoge::__construct() must be an instance of App\Http\Services\hoge or null, instance of Mockery_0__Tests_Feature_hoge given, called in /var/www/hoge/tests/Feature/hogeTest.php on line 277
hoge
型かnull
のみ受け付けるコードに、Mockery_0__Tests_Feature_hoge
を与えたというエラーである。エラーについて
エラーを起こしたコード
php-テストコード.php# testServiceで利用するモック $hogeServiceMock = \Mockery::mock(hogeService::class); $hogeServiceMock->shouldReceive('gethoge') ->andReturn($gethoge); // テスト対象のサービス、コンストラクタでモックと連携 $testService = new testService($hogeServiceMock); // テスト対象の関数実行 $response = $testService->issue($testInput); // テスト結果の確認 $this->assertSame($expected, $response);php-テスト対象.phpclass TestService { /** @var hogeService */ private $hogeService; /** * AuthController constructor. * * @param hogeService $hogeService */ public function __construct(hogeService $hogeService) { $this->hogeService = $hogeService; } /** * テスト対象関数 * * @param string $testInput * @return 実行結果の文字列 */ public function issue(string $testInput) { # いろいろする }エラーの経緯
当初、
testService
側のhintを記載漏れしており、コードレビューを経てhintを全て追加することに。
すると今まで正常稼働していてたテストコードが上記のtype errorを出力するようになった。エラーが起きた原因
実はテストコードphp側に記載した
hogeService
への名前空間(use
)にタイポがあり、hogeserviceをうまく呼び出せていなかった。
そのためmockeyが独自型のMockery_0__Tests_Feature_hoge
型として動作しており、hintを追加したことでそのエラーに気が付いた。エラー解消
ちゃんと
hogeService
を呼び出せるように名前空間のtypoを直す。
するとテストコード自体には一切手を入れずとも、hintのエラーが解消する。
- 投稿日:2020-12-07T21:57:54+09:00
laravelでフォローしたユーザーの投稿を取得する
フォローしたユーザーの投稿を取得します
以下にテーブル構造やモデルの設定を簡単に示しておきます以前にもフォロー機能作成記事を書いているので詳しくはそっちで
https://qiita.com/mitsu-0720/items/0c2fcdd367e8a6c5999cXXXX_XX_XX_XXXXXX_create_follow_users_table.phpSchema::create('follow_users', function (Blueprint $table) { $table->bigIncrements('id'); $table->unsignedBigInteger('followed_user_id')->index(); $table->unsignedBigInteger('following_user_id')->index(); $table->foreign('followed_user_id')->references('id')->on('users')->onDelete('cascade'); $table->foreign('following_user_id')->references('id')->on('users')->onDelete('cascade'); $table->timestamps(); });User.php// フォロワー→フォロー public function followUsers() { return $this->belongsToMany('App\User', 'follow_users', 'followed_user_id', 'following_user_id'); } // フォロー→フォロワー public function follows() { return $this->belongsToMany('App\User', 'follow_users', 'following_user_id', 'followed_user_id'); }PostController.phppublic function timeline() { $posts = Post::query()->whereIn('user_id', Auth::user()->follows()->pluck('followed_user_id'))->latest()->get(); return view('posts.timeline')->with([ 'posts' => $posts, ]); }$posts = Post::query()->whereIn('user_id', Auth::user()->follows()->pluck('followed_user_id'))->latest()->get();
について日本語で解説してみると
Post::query() ポストモデルの中の
whereIn('user_id') user_idが
Auth::user()->follows()->pluck('followed_user_id') 自分がフォローしているユーザーの中でフォロワーが自分であるユーザーを取得して
latest()->get() 最新順に取得するといった感じになります
whereInはまだ自分も理解が浅いのですが第二引数が配列となる場合はこっちを使わないと想定した結果を取得できないイメージ
今回みたいに条件指定が複雑な場合はwhereよりwhereInを使った方がいいと思います
実際このtimeline()関数もwhereだと何も取得できませんでしたpluckメソッドは引数の値だけを取得できるメソッド
今回はフォローしてるユーザーのIDだけを取得したかったのでpluck('followed_user_id')でIDのみを取得していますつまり今回自分がuser_id1、2、3のユーザーをフォローしているとすると上の関数は
Post::query()->whereIn('user_id', [1,2,3])->latest()->get();
といった意味を持ちますハマった点
以前自分が書いたメソッドはこう
PostsController.php$posts = Post::query()->whereIn('user_id', Auth::user()->follows()->pluck('following_user_id'))->latest()->get();フォローしてるユーザーのIDが欲しいんだから取得するのはfollowed_user_idではなくfollowing_user_idや!
と思ってdd($posts)してみたところ取得されたのは自分自身の投稿のみだった当時は、は?????????????なんで??????????????????
ってなってましたが今考えればそれもそのはずフォローユーザーは自分なのだからフォローしているユーザーのidを取得しても自分のIDしか取得できないのだ
まとめ
フォローしているユーザーの投稿を取得したいのだからフォロワーのIDなんか使わないだろうと頭でっかちになって考えていたが
「フォロワーが自分であるユーザー」を取得することにより結果的に「自分がフォローしているユーザー」を取得できるという結論になったのはいい経験になった
プログラミングの面白さをしれたいい経験でしたおまけ
「フォローしているユーザー」+「自分自身」の投稿を取得したい場合
PostsController.php$posts = Post::query()->whereIn('user_id', Auth::user()->follows()->pluck('followed_user_id'))->orWhere('user_id', Auth::user()->id)->latest()->get();
- 投稿日:2020-12-07T19:55:17+09:00
Laravel6をさくらレンタルサーバーにデプロイ 備忘録
手順
sshでサーバにログイン
ssh user@xxx.comLaravel プロジェクトをgit経由でダウンロードする
/home/user/mkdir laravel cd laravel git clone ~~composerインストールをする
/home/user/laravel/project_name/curl -sS https://getcomposer.org/installer | phpインストールできたか確認してみる
/home/user/laravel/project_name/php composer.pharVenderのインストール
/home/user/laravel/project_name/php composer.phar install.envファイルの設定をする
/home/user/laravel/project_name/.envAPP_ENV=production APP_DEBUG=false DB_CONNECTION=mysql DB_HOST=mysql000.db.sakura.ne.jp DB_PORT=3306 DB_DATABASE=さくらインターネットのレンタルサーバで作成したデータベース名 DB_USERNAME=アカウント名 DB_PASSWORD=データベースパスワードphp artisan ○○をする
/home/user/laravel/project_name/php artisan key:generate php artisan migrate php artisan storage:link.htaccessを編集する
/home/user/laravel/project_name/public/.htaccess<IfModule mod_rewrite.c> <IfModule mod_negotiation.c> Options -MultiViews -Indexes </IfModule> RewriteEngine On # Handle Authorization Header RewriteCond %{HTTP:Authorization} . RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}] # Redirect Trailing Slashes If Not A Folder... RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_URI} (.+)/$ RewriteRule ^ %1 [L,R=301] # Handle Front Controller... RewriteCond %{REQUEST_FILENAME} !-d RewriteCond %{REQUEST_FILENAME} !-f RewriteRule ^ index.php [L] </IfModule>index.phpを編集する
/home/user/laravel/project_name/public/index.phprequire '/home/user/laravel/project_name/vendor/autoload.php'; $app = require_once '/home/user/laravel/project_name/bootstrap/app.php';wwwフォルダー下にシンボリックリンクを作成する
ln -s /home/user/laravel/project_name/public/ /home/user/www/project_nameブラウザからアクセスして確認してみる
https://xxx.com/project_name/以上。
自分が実際にデプロイした際の手順をまとめておきました。
いろいろなサイトを飛び回って探して苦労したので忘れない為に。
- 投稿日:2020-12-07T18:12:51+09:00
【LaravelExcel】LaravelExcelのバージョンアップでハマったことまとめ
経緯
Laravelをバージョンアップするに伴い、PHPやライブラリであるLaravelExcelやPHPExcelなどもバージョンアップされ、いくつかの変更点でハマった点をまとめてみた
新旧のバージョン情報
Laravel
新:6.18.42
旧:5.1.46PHP
新:7.4.11
旧:5.6.30ハマった点と解決方法
Excel::load()の廃止
元々はこんな感じでExcelを読み込んでいました。
test.phpExcel::load('file.xlsx', function ($file) { // PHPExcelを使った処理 など });→後述のPHPSpreadsheetの機能で読み込む方法に変更しました。
多分、Excelファイルを読み込んで値を返すだけならLaravelExcelの3以降だとExcel::import()を使用するのがいいと思います。
PHPExcelなどを使ってシート、列、行、セルなどを操作している場合はPHPSpreadsheetを使用する形へ変更した方がいいと思います。PHPExcelの廃止→PHPSpreadsheetへ移行
PHPExcel自体が非推奨・廃止となり、PHPSpreadsheetの使用を推奨されています。
使用するクラスなどが変更となっています。ちなみにExcelファイルの読み込みは下記のような形で実装しました。
namespace App\Http\Controllers; use PhpOffice\PhpSpreadsheet\Reader\Xlsx as Reader; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; class ImportExcelController extends Controller { // エクセル読み込み処理 $reader = new Reader(); $sheet = $reader->load('/test.xlsx'); }※前述した通り、色々な操作をする場合のExcel::import()での読み込みが上手く構築出来ず…もし何か良い方法などをご存知の方がいらっしゃいましたらご教示くださいますと嬉しいです。
セルオブジェクトの値取得時、列番号の指定が変更
PHPSpreadsheetへ移行したことでセルオブジェクトにおける列番号の指定が変更になりました。これが地味に混乱させる要因に…
旧処理
test.php$col = 0; // 列 $row = 0; // 行 // A1のセルオブジェクトを取得 $cell = $sheet->getCellByColumnAndRow($col, $row)->getValue();新処理
test.php$col = 1; // 列 $row = 0; // 行 // A1のセルオブジェクトを取得 $cell = $sheet->getCellByColumnAndRow($col, $row)->getValue();旧処理では列はA=0,B=1…と0始まりで指定されますが、新処理ではA=1,B=2…と1始まりに変更になっています。
普段プログラミングからもずれており、ややこしさを感じますね。結論
・Excelを使う処理はシンプルであるべき!
特にテンプレートに可変部分を持たせないようにした方がいいですマジで参考資料
- 投稿日:2020-12-07T18:12:51+09:00
LaravelExcelのバージョンアップでハマったことまとめ
経緯
Laravelをバージョンアップするに伴い、PHPやライブラリであるLaravelExcelやPHPExcelなどもバージョンアップされ、いくつかの変更点でハマった点をまとめてみた
新旧のバージョン情報
Laravel
新:6.18.42
旧:5.1.46PHP
新:7.4.11
旧:5.6.30ハマった点と解決方法
Excel::load()の廃止
元々はこんな感じでExcelを読み込んでいました。
test.phpExcel::load('file.xlsx', function ($file) { // PHPExcelを使った処理 など });→後述のPHPSpreadsheetの機能で読み込む方法に変更しました。
多分、Excelファイルを読み込んで値を返すだけならLaravelExcelの3以降だとExcel::import()を使用するのがいいと思います。
PHPExcelなどを使ってシート、列、行、セルなどを操作している場合はPHPSpreadsheetを使用する形へ変更した方がいいと思います。PHPExcelの廃止→PHPSpreadsheetへ移行
PHPExcel自体が非推奨・廃止となり、PHPSpreadsheetの使用を推奨されています。
使用するクラスなどが変更となっています。ちなみにExcelファイルの読み込みは下記のような形で実装しました。
namespace App\Http\Controllers; use PhpOffice\PhpSpreadsheet\Reader\Xlsx as Reader; use PhpOffice\PhpSpreadsheet\Cell\Coordinate; class ImportExcelController extends Controller { // エクセル読み込み処理 $reader = new Reader(); $sheet = $reader->load('/test.xlsx'); }※前述した通り、色々な操作をする場合のExcel::import()での読み込みが上手く構築出来ず…もし何か良い方法などをご存知の方がいらっしゃいましたらご教示くださいますと嬉しいです。
セルオブジェクトの値取得時、列番号の指定が変更
PHPSpreadsheetへ移行したことでセルオブジェクトにおける列番号の指定が変更になりました。これが地味に混乱させる要因に…
旧処理
test.php$col = 0; // 列 $row = 0; // 行 // A1のセルオブジェクトを取得 $cell = $sheet->getCellByColumnAndRow($col, $row)->getValue();新処理
test.php$col = 1; // 列 $row = 0; // 行 // A1のセルオブジェクトを取得 $cell = $sheet->getCellByColumnAndRow($col, $row)->getValue();旧処理では列はA=0,B=1…と0始まりで指定されますが、新処理ではA=1,B=2…と1始まりに変更になっています。
普段プログラミングからもずれており、ややこしさを感じますね。結論
・Excelを使う処理はシンプルであるべき!
特にテンプレートに可変部分を持たせないようにした方がいいですマジで参考資料
- 投稿日:2020-12-07T14:42:09+09:00
LaravelでAWSのSESからメール送信する方法
環境
Laravel:7.3
AWS SESリージョン:Tokyo(ap-northeast-1)前提
・メールアドレスがある
やること
①composerでAmazon AWS SDK forPHPをインストールする
②SESにメールアドレスを登録する
③サンドボックスの解除
④SESのAPI使えるようにAIMでユーザー作る
⑤Laravelの設定(.env)
⑥試しにメール送信①composerでAmazon AWS SDK forPHPをインストールする
composer.jsonに以下を記載し
composer update
する。"aws/aws-sdk-php": "~3.0"②SESにメールアドレスを登録する
Mails
>Verify a New Email Address
の順でクリックメールアドレスを入力して
Verify This Email Address
をクリック入力したメールアドレスに認証用のURLが記載されたメールが届きますので、URLを開いて認証を完了します。
③サンドボックスの解除
https://laraweb.net/knowledge/7083/
これ参考にしてくれぇ
④SESのAPI使えるようにAIMでユーザー作る
サービス(左上)
>IAM
>ユーザー
>ユーザーの追加
>任意の名前入力 + プログラムによるアクセスにチェック入れる
>次のステップ(右下の青いやつ)
>[既存のポリシーを直接アタッチ]をクリック
>[AmazonSESFullAccess] をアタッチ
> 後はなんもいじらないで青いボタン押す。重要↓
※
最後まで進むと、「アクセスキー」と「シークレットアクセスキー」が表示されますので、CSVでダウンロードするかメモしておきます。
⑤Laravelの設定(.env)
MAIL_MAILER=ses //他の記事だと MAIL_DRIVER=ses ※config/mail.phpで確認してください MAIL_FROM_ADDRESS=上で登録したメアド MAIL_FROM_NAME="メールの送り主の名前になる"(何も書かないとExampleで送られる) SES_KEY=上でメモした[アクセスキー] SES_SECRET=上でメモした「シークレットアクセスキー」 SES_REGION=ap-northeast-1 //これ東京リージョンです⑥試しにメール送信
sudo php artisan tinker >>> Mail::raw('mail 本文', function($message) { $message->to('送りたいメールアドレス')->subject('subjectだよーん'); }); => null ←これ成功!メール確認して届いてたら成功!
※上で成功したのに仮にお問い合わせフォームとかでエラー出たら自分で書いたソースを疑った方がいいかもです。。。知らんけど。
終了
- 投稿日:2020-12-07T10:21:12+09:00
【Laravel】public staticとは何か?簡単に解説
public static についての解説
クラスプロパティもしくはメソッドを static として宣言することで、 クラスのインスタンス化の必要なしにアクセスすることができます。 static なプロパティは、インスタンス化されたクラスオブジェクトから アクセスすることはできません (static なメソッドにはアクセスできます)。
引用:公式サイト要するに
static
をつければ
・インスタン化せずにアクセス
・アクセスのやり方はクラス::プロパティ
・逆にstaticをつけたプロパティにはインスタンスからのアクセス不可staticをつけないとどうなる?
付けない時はインスタンス化してからアクセスする必要がある
変数 = new クラス 変数→メソッド 変数→プロパティこんな感じ。
- 投稿日:2020-12-07T07:25:31+09:00
LaravelでMailableクラスでメールを送信する方法
【メモです。】
コントローラーの作成
php artisan make:controller SampleMailControllerルーティングの追加
Route::get('/mail', 'SampleMailController@send');コントローラーに処理を追加
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Mail\SendTestMail; use Mail; class MailSendController extends Controller { public function send() { $to = [ [ 'email' => 'XXXXX@XXXXX.jp', 'name' => 'Test', ] ]; Mail::to($to)->send(new SendTestMail()); } }Mailableクラスの作成
php artisan make:mail SendTestMailSendTestMail.phpの編集
public function build() { return $this->view('emails.test') ->from('XXX@XXXX','Test') ->subject('This is a test mail'); }views/emailsの下にtest_text.blade.phpファイルを作成し、メール本文を記述
好きなように書けばOK
【余談】複数人にメールを送信したい場合
コントローラーの処理を下記のように変える。
$to = User::all(); Mail::to($to)->send(new SendTestMail());【余談2】引数を渡す
コントローラーで下記のように引数に値を渡す。
$user = User::find(1); Mail::to($user)->send(new SendTestMail($user));あとはMailbleクラスの方で好きなように記述。
public function __construct($user) { $this->user = $user; } public function build() { return $this->text('emails.test_text') ->from('XXX@XXXXX','Reffect') ->subject('This is a test mail') ->with(['user' => $this->user]); }
- 投稿日:2020-12-07T02:41:42+09:00
Laravelプロジェクト作成時に"Could not find package laravel/laravel with stability stable."と出る
筆者の環境
- macOS Catalina バージョン10.15.6
- PHP 7.4.13
- Composer 2.0.8
発生問題
久しぶりに新規Laravelプロジェクトをローカルに作成しようと思い、いつも通りターミナルから以下のコマンドを打つと…
$ composer create-project laravel/laravel laravel_sample --prefer-dist以下のエラーが。
[InvalidArgumentException] Could not find package laravel/laravel with stability stable.仕方がないのでlaravel/installerを使おうと思い、以下のようにlaravel/installerをインストールするコマンドを打つと…
$ composer global require "laravel/installer"以下のエラーが。
[InvalidArgumentException] Could not find package laravel/installer. Did you mean one of these? laravel/installer codemyviews/vanilla-installer解決策
結論、Composer自体を完全にアンインストールし、インストールし直したら無事エラーも起きずLaravelプロジェクトが作成でき、laravel/installerもインストールできました…(詳細な原因は分からず…)
アンインストール手順については以下の記事を参考させて頂きました。
(アンインストール時に必要となる.composerとcomposer.pharのパスはMacでは、「/Users/ユーザ名/.composer」、「/usr/local/bin/composer/composer.phar」となります。)[PHP]Composer自体を完全にアンインストールする方法 | akamist blog
問題の原因は特定できませんでしたが、ひとまずアンインストールすることで解決できました。
「Could not find package laravel/laravel with stability stable」に遭遇時の対処法はネット上ではあまり見つからなかったため、今回投稿致しました。
同じような問題に遭遇した方の参考になれば幸いです。