20200115のlaravelに関する記事は6件です。

Laravel で MySQLのTime型の最大値を超えて集計する

やりたいこと

MySQLのTime型は

'-838:59:59' から '838:59:59'
にまでしか対応していません。

なので仮にDBに○○した時間をtime型で保存し、合計を取り出そうとすると上限に当たる可能性がありませす

集計方法

MySQLのTime_TO_SEC関数を使います。
その名の通りこれは、Timeを秒数に直してくれます。
秒数に直したものを合計し、それを取得します。

取得した秒数をPHPでHH:MMに整形してあげれば、上限を超えた状態になります。

TestController.php
public 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))
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【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() メソッドにてユーザ側で簡単に指定できるようにするためのヘルパートレイト。
.env
SENDGRID_API_KEY=<APIキー>
SENDGRID_IP_POOL_NAME=<デフォルトプール名>
config/services.php
return [

    /* ... */

    'sendgrid' => [
        'api_key' => env('SENDGRID_API_KEY'),
        'ip_pool_name' => env('SENDGRID_IP_POOL_NAME'),
    ],

    /* ... */

];
config/app.php
return [

    /* ... */

    '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';
});
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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;

スクリーンショット 2020-01-01 18.18.04.png

から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になっていても大丈夫です。

.env

DB_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'),
            ]) : [],
        ],
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel-Enum 導入2

はじめに

前提

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'];
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

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;
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Class blade.compiler does not exist

状況

/App/Providers/AppServiceProviderのregister()メソッドにカスタムディレクディブの設定をしたら、
タイトルのエラーが発生しました。

対処方法

boot()メソッドに記述することでエラーが発生しなくなりました。
Upgrade to 5.8 :: Class blade.compiler does not exist

jcobb • 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ファサードが利用できず、エラーが発生したものと考えます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む