- 投稿日:2020-01-15T20:37:15+09:00
Laravel で MySQLのTime型の最大値を超えて集計する
やりたいこと
MySQLのTime型は
'-838:59:59' から '838:59:59'
にまでしか対応していません。なので仮にDBに○○した時間をtime型で保存し、合計を取り出そうとすると上限に当たる可能性がありませす
集計方法
MySQLのTime_TO_SEC関数を使います。
その名の通りこれは、Timeを秒数に直してくれます。
秒数に直したものを合計し、それを取得します。取得した秒数をPHPでHH:MMに整形してあげれば、上限を超えた状態になります。
TestController.phppublic function summary() { $user = User::selectRaw('SUM(TIME_TO_SEC('sleep_time')) as total_sleep_time') ->where('name','太郎') ->first(); $time = $user->total_sleep_time; // HH:MM sprintf('%02d:%02d', ($time / 3600),($time / 60 % 60)) }
- 投稿日:2020-01-15T16:41:13+09:00
【Laravel】 Mailable から SendGrid の IP プールを指定できるようにする
背景
現在,プロダクション環境で実際にメールを送信するにあたって SendGrid を使用している。このドライバーとして Laravel では以下のライブラリを利用している。
SendGrid で大量のメールを送信するためには,規制に引っかからないように IP プールを使用することが推奨されるが,このライブラリではオプション指定方法が用意されていない。そのため,少々強引な手段を使って設定できるようにしてみた。
実装
App\Providers\SendgridTransportServiceProvider
クラス
- トランスポーターを上書きするためのサービスプロバイダ。元ライブラリのものを継承。
App\Services\Mail\Transport\SendgridTransport
クラス
- JSON ペイロードの書き換えはここでオーバーライドしたメソッド上で行う。
App\Services\Mail\IpPoolNameSpecifier
クラス
Mailable::withSwiftMessage()
で使用する__invoke()
を実装したコールバック。- キューに投入できるようにするため,シリアライズ不能なクロージャは使用しない。
App\Services\Mail\UsesIpPool
トレイト
Mailable::build()
メソッドにてユーザ側で簡単に指定できるようにするためのヘルパートレイト。.envSENDGRID_API_KEY=<APIキー> SENDGRID_IP_POOL_NAME=<デフォルトプール名>config/services.phpreturn [ /* ... */ 'sendgrid' => [ 'api_key' => env('SENDGRID_API_KEY'), 'ip_pool_name' => env('SENDGRID_IP_POOL_NAME'), ], /* ... */ ];config/app.phpreturn [ /* ... */ 'providers' => [ /* ... */ App\Providers\SendgridTransportServiceProvider::class, /* ... */ ], /* ... */ ];app/Providers/SendgridTransportServiceProvider.php<?php namespace App\Providers; use App\Services\Mail\Transport\SendgridTransport; use GuzzleHttp\Client as Guzzle; use Illuminate\Mail\TransportManager; use Sichikawa\LaravelSendgridDriver\SendgridTransportServiceProvider as BaseSendgridTransportServiceProvider; class SendgridTransportServiceProvider extends BaseSendgridTransportServiceProvider { /** * {@inheritdoc} */ public function extendTransportManager(TransportManager $manager): void { $manager->extend('sendgrid', function () { $config = config('services.sendgrid', []); return new SendgridTransport( new Guzzle($config['guzzle'] ?? []), $config['api_key'], $config['endpoint'] ?? null ); }); } }app/Services/Mail/Transport/SendgridTransport.php<?php namespace App\Services\Mail\Transport; use Sichikawa\LaravelSendgridDriver\Transport\SendgridTransport as BaseSendgridTransport; use Swift_Mime_SimpleMessage; class SendgridTransport extends BaseSendgridTransport { /** * {@inheritdoc} */ protected function setParameters(Swift_Mime_SimpleMessage $message, $data) { $data = parent::setParameters($message, $data); // Swift_Mime_SimpleMessage 上に動的に生やした $ipPoolName プロパティがあればそれを使用 // 無ければデフォルト設定に従う if ($ipPoolName = $message->ipPoolName ?? config('services.sendgrid.ip_pool_name', null)) { $data['ip_pool_name'] = $ipPoolName; } return $data; } }app/Services/Mail/IpPoolNameSpecifier.php<?php namespace App\Services\Mail; use Swift_Message; class IpPoolNameSpecifier { /** * @var null|string */ protected $ipPoolName; /** * IpPoolNameSpecifier constructor. * * @param null|string $ipPoolName */ public function __construct(?string $ipPoolName) { $this->ipPoolName = $ipPoolName; } /** * インスタンス上に動的に $ipPoolName プロパティを作成 * * @param Swift_Message $message * @return Swift_Message */ public function __invoke(Swift_Message $message): Swift_Message { $message->ipPoolName = $this->ipPoolName; return $message; } }app/Services/Mail/UsesIpPool.php<?php namespace App\Services\Mail; use Illuminate\Mail\Mailable; /** * Trait UsesIpPool * * @mixin Mailable */ trait UsesIpPool { /** * @param null|string $ipPoolName * @return $this */ public function useIpPool(?string $ipPoolName) { return $this->withSwiftMessage(new IpPoolNameSpecifier($ipPoolName)); } }使用例
Mail::send()
でMailable
から送るapp/Mails/Welcome.php<?php namespace App\Mail; use App\User; use App\Services\Mail\UsesIpPool; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Mail\Mailable; use Illuminate\Queue\SerializesModels; class Welcome extends Mailable implements ShouldQueue { use Queueable, SerializesModels, UsesIpPool; /** * @var User */ protected $user; /** * Create a new message instance. * * @param User $user */ public function __construct(User $user) { $this->user = $user; } /** * Build the message. * * @return $this */ public function build() { return $this ->text('emails.welcome') ->subject("$user->email さん、こんにちは!") ->with(['user' => $this->user]) ->to($this->user->email) ->useIpPool('information'); } }Mail::send(new Welcome($user));
Mail::raw()
で送るMail::raw('Welcome!!!', function (Message $message) use ($user) { $message ->subject("$user->email さん、こんにちは!") ->to($user->email); $message->getSwiftMessage()->ipPoolName = 'information'; });
- 投稿日:2020-01-15T12:20:26+09:00
laravelでPHPのPDO接続を使用してmysqlに接続する方法
laravelの設定ではSQliteを使用していますが、別途PDOを使用してmysqlからデータを引っ張りたいと思った時にDBの接続って2つ使えるの?という疑問があったので解消してみました。
あああやったこと
blade.phpにphpタグを使いPDO接続
それに必要なもの
- サーバーの立ち上げ
- DB作成または既存のDB
- 上記のDBにテーブル作成
laravelサーバー立ち上げ
$pwd /home/vagrant/laravel_lessons_copy/プロジェクト名その後、
$ php artisan serve --host 192.168.33.10 --port 8000でサーバー立ち上げで接続
DBを確認
※現在のプロジェクト名の位置でmysql -u rootでログイン
mysql> show databases;
からuse DB名でDBを選択
use mysqlその後、table作成
index.blade.phpにPDO接続
index.blade.php<?PHP $pdo=new PDO('mysql:host=localhost;dbname=mysql;charset=utf8', 'root', ''); foreach ($pdo->query('select * from user') as $row){ echo $row['id']; echo $row['name']; echo $row['address']; } ?>.envとdatabase.phpは何も触ってないけど一応添付しておきます。
今回PDOでmysql接続したいが、.envの設定はsqliteになっていても大丈夫です。.envDB_CONNECTION=sqlite #DB_CONNECTION=mysql #DB_HOST=127.0.0.1 #DB_PORT=3306 #DB_DATABASE=dotinstall_todo_app //laravel上でのmysqlのDB #DB_USERNAME=root //mysql -u rootでログインしたから #DB_PASSWORD= //上記のログインに際passwordは設定してないから空白database.php'default' => env('DB_CONNECTION', 'mysql'), 'connections' => [ 'sqlite' => [ 'driver' => 'sqlite', 'url' => env('DATABASE_URL'), 'database' => env('DB_DATABASE', database_path('database.sqlite')), 'prefix' => '', 'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true), ], 'mysql' => [ 'driver' => 'mysql', 'url' => env('DATABASE_URL'), 'host' => env('DB_HOST', '127.0.0.1'), 'port' => env('DB_PORT', '3306'), 'database' => env('DB_DATABASE', 'forge'), 'username' => env('DB_USERNAME', 'forge'), 'password' => env('DB_PASSWORD', ''), 'unix_socket' => env('DB_SOCKET', ''), 'charset' => 'utf8mb4', 'collation' => 'utf8mb4_unicode_ci', 'prefix' => '', 'prefix_indexes' => true, 'strict' => true, 'engine' => null, 'options' => extension_loaded('pdo_mysql') ? array_filter([ PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'), ]) : [], ],
- 投稿日:2020-01-15T11:54:46+09:00
Laravel-Enum 導入2
はじめに
- Laravel-Enum 導入 の続き。
- 主に メソッド などの使い方を記述する
前提
Enum ファイルの中身
app/Enum/TestText.php<?php namespace App\Enums; final class TestText extends Enum { const TEST = "test"; const TEXT = "text"; }日本語ファイルの中身
app/resources/lang/ja/enums.php<?php // php artisan で作成したクラス use App\Enums\TestText; return [ TestText::class=> [ TestText::TEST => 'テスト', TestText::TEXT => 'テキスト', ], ];使ってみる
インスタンスを生成して key/ value を取得
// 全体の インスタンスを取得 $testText = TestText::getInstances(); // 以下のように値が取得できる $testText[TestText::TEST]->key; // TEST $testText[TestText::TEST]->value; // test $testText[TestText::TEST]->description; // テスト// 指定したキーのインスタンスを取得する TestText::TEST()->key; // TEST TestText::TEST()->value; // test TestText::TEST()->description // テストkey の一覧を取得する
TestText::getKeys(); // return['TEST', 'TEXT'];value の一覧を取得する
TestText::getValues(); // return['test', 'text'];
- 投稿日:2020-01-15T10:29:05+09:00
Declaration of <クラス名>::<メソッド名> should be compatible with <クラス名>::<メソッド名>
状況
phpunitのsetUp()メソッドを設定した時に、タイトルのエラーが発生
エラー内容と対象方法
setUp()メソッドは親クラスのメソッドをオーバーライドしているのですが、
オーバーライド元とオーバーライド先でメソッドの引数または戻り値が異なる場合にエラーが発生します。この場合、親クラスの戻り値が以下の通りvoidとなっているため、
オーバーライド先でも同様の指定が必要となります。TestCase.php/** * Setup the test environment. * * @return void */ protected function setUp(): void { if (! $this->app) { $this->refreshApplication(); } $this->setUpTraits(); foreach ($this->afterApplicationCreatedCallbacks as $callback) { $callback(); } Facade::clearResolvedInstances(); Model::setEventDispatcher($this->app['events']); $this->setUpHasRun = true; }
- 投稿日:2020-01-15T10:18:59+09:00
Class blade.compiler does not exist
状況
/App/Providers/AppServiceProviderのregister()メソッドにカスタムディレクディブの設定をしたら、
タイトルのエラーが発生しました。対処方法
boot()メソッドに記述することでエラーが発生しなくなりました。
Upgrade to 5.8 :: Class blade.compiler does not existjcobb • 9 months ago
For me the problem was that I had a custom blade directive in the register() method of /App/Providers/AppServiceProvider and custom Blade directives need to be in the boot() method instead.原因(推測です。要調査)
register()メソッドを通る時点では、サービスコンテナやプロバイダー、エイリアスの登録がされないため、
Bladeファサードが利用できず、エラーが発生したものと考えます。