2020/03/30

ペジネーションビューの書き出し

artisan コマンドで、ペジネーションビューをプロジェクト内に書き出します。


$ php artisan vendor:publish --tag=laravel-pagination

resources/views/vendor/pagination/ にページネーションのBladeファイルが作成されます。

あとで説明しますが、デフォルトは「bootstrap-4」で書き出されますが、ページネーションメソッドで他のBladeファイルを指定することができます。
よって、利用したいBladeファイルをカスタマイズしてください。

Eloquent モデルで取得

Eloquent モデルには、paginate()、simplePaginate() メソッドを利用できます。


$limit = 10;
$offset = 0;
$user = User::paginate($limit, '[*]', 'page', $offset);

AppServiceProvider に追加

AppServiceProvider::boot() でページネーションのBlade ファイル名を指定します。


    public function boot()
    {
        Paginator::defaultView('pagination::bootstrap-4');
        Paginator::defaultSimpleView('pagination::simple-bootstrap-4');
    }

Blade にページネーションを実装

Blade ファイルでは、Eloquent モデルデータの links() メソッドでページネーション表示できます。


{!! $user->links() !!}

また、Blade 側で明示的に指定することもできます。


{{ $paginator->links('pagination::bootstrap-4', ['key' => 'value']) }}

Eloquent のページネーションメソッドは以下を参照してください。

https://readouble.com/laravel/7.x/ja/pagination.html

  2020/03/29

SQL が発行されるたびに Log ファサードを利用して SQLログを書き出してみます。

Laravel のLogファサードの仕様は以下を参照してください。

https://readouble.com/laravel/7.x/ja/logging.html

LogSqlServiceProvider の設定

プロバイダは、AppServiceProvider に登録しても良いですが、今回はカスタムで LogSqlServiceProvider を作成します。


$ php artisan make:provider LogSqlServiceProvider

app/Providers/LogSqlServiceProvider.php が作成されているのを確認します。

AppServiceProvider に登録

config/app.php の providers に LogSqlServiceProvider を登録します。


    'providers' => [
...
        App\Providers\LogSqlServiceProvider::class,
...
    ],

SQLログ処理を記述

app/Providers/LogSqlServiceProvider.php の register() に記述します。


namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;

class AppServiceProvider extends ServiceProvider
{
    const SQL_LOG_ENVIROMENT = [
        'local',
        'development',
    ];
....

    public function register()
    {
        if (in_array(App::environment(), self::SQL_LOG_ENVIROMENT)) {
            DB::listen(function ($query) {
                $sql = $query->sql;
                for ($i = 0; $i < count($query->bindings); $i++) {
                    $sql = preg_replace("/\?/", $query->bindings[$i], $sql, 1);
                }
                Log::channel('sql')->debug("SQL", ["time" => sprintf("%.2f ms", $query->time), "sql" => $sql]);                                                      
            });
        }
    }

App::environment() で現在の環境を取得し、任意に設定した SQL_LOG_ENVIROMENT の場合に、ログを書き出します。

環境による設定は、.env の boolean で設定しても良いかも知れません。

SQLログファイルパス設定

config/logging.php で設定でき、デフォルト「storage/logs/larave.log」となります。

Log::debug() の場合、デフォルトで single チャンネルで書き出されるため、Log::channel('チャンネル名')で、SQL用のログを設定します。
(内部的に、Illuminate\Log\LogManagerクラスで、driver() に設定される模様)


    'channels' => [
...
        'sql' => [
            'driver' => 'sql',
            'path' => storage_path('logs/sql.log'),
            'level' => 'debug',
        ],
...
    ],

またロガーは RFC 5424 の以下の8つのログレベルを提供しています。

  • emergency
  • alert
  • critical
  • error
  • warning
  • notice
  • info
  • debug

Logファサードは、最終的にPsr\Log\LoggerInterface を実装した Monolog\Logger を利用しています。

  2020/03/24

Laravel 7 で認証ページを作成してみます。

※Laravel7 の認証ページ

https://readouble.com/laravel/7.x/ja/authentication.html

プロジェクト作成


$ composer create-project laravel/laravel laravel-auth --prefer-dist
$ chmod -R 777 storage
$ chmod -R bootstrap/cache

この時点で、 config/auth.php などが作成されています。

  • config/auth.php
  • app/User.php
  • app/Http/Middleware/Authenticate.php
  • database/migrations/xxxx_create_users_table.php
  • database/migrations/xxxx_create_password_resets_table.php
  • database/factories/UserFactory.php

User モデル

デフォルトで app/User.php が作成されています。


namespace App;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable
{
    use Notifiable;
    protected $fillable = [
        'name', 'email', 'password',
    ];
    protected $hidden = [
        'password', 'remember_token',
    ];
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}

今回は、App/Models/User.php にパスを変更しておきます。
(namespace など修正が必要)

Admin モデル作成

マルチ認証用に、管理者(Admin)モデルを作成してみます。

Models/Admin.php を作成します。


$ php artisan make:model Models/Admin

Admin マイグレートファイル作成

databases/ に Admin用のマイグレーションファイルを作成します。


$ php artisan make:migration create_admins_table

モデル&マイグレートファイルを同時に作成

上記のモデルとマイグレーションファイルを同時に作成することもできます。

Models/Admin.php を作成します。


$ php artisan make:model Models/Admin -m

use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
 
class CreateAdminsTable extends Migration
{
    public function up()
    {
        if (Schema::hasTable('admins')) return;
        Schema::create('admins', function (Blueprint $table) {
            $table->bigIncrements('id');
            $table->timestamps();
            $table->string('email');
            $table->string('name');
            $table->string('password');
            $table->string('remember_token')->nullable();
        });
    }
    public function down()
    {
        Schema::dropIfExists('admins');
    }
}

Guard の設定

Guard は Auth認証用のドライバークラスで、config/auth.php に設定をします。


    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
        'api' => [
            'driver' => 'token',
            'provider' => 'users',
        ],
      'admin' => [
         'driver' => 'session',
         'provider' => 'admins',
      ],
    ],

Guard を設定することにより、Controllerなどに記載するミドルウェアでの認証が可能となります。


$this->middleware('auth:admin');

Eloquent 設定

Eloquent に App\Models\User クラスを設定します。
※User.php の namespace は App\Models\ に変更


    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Models\User::class,
        ],
       'admins' => [
        'driver' => 'eloquent',
        'model' => App\Models\Admin::class,
      ],
    ],

artisan で auth を作成する

make:auth 廃止

Laravel6 から 以下のコマンドは廃止されました。


$ php artisan make:auth

laravel/ui を利用

代わりに、「laravel/ui」でログイン画面を作成するようになりました。

更に、リリースノートには、2.0 を指定するように記載されています。


$ composer require laravel/ui "^2.0"
$ php artisan ui vue --auth
vue の部分は bootstrap などの設定もできます。

認証用ファイル

  • resources/views/auth
  • App/Http/Controllers/Auth
が作成されているので、管理者用にコピーしておくと良いでしょう。
  • resources/views/admin/auth
  • App/Http/Controllers/Admin/Auth

データベース作成

PostgreSQL


$ createdb sample_auth

MySQL


# mysql -u root
mysql > create database sample_auth;

.env

各種DBの設定を合わせる


DB_CONNECTION=pgsql
DB_HOST=postgres
DB_PORT=5432
DB_DATABASE=sample
DB_USERNAME=postgres
DB_PASSWORD=secret

DBマイグレート

DB設定が一通り完了したら、マイグレートしてみます。


$ php artisan migrate

テーブルが作成したことを確認したら、サンプルデータを作成してみます。

Seeder 作成

サンプルデータを作成する場合、artisan に seeder コマンドにも用意されています。

ユーザ、管理者の Seeder を作成すると「database/seeds/」にファイルが書き出されます。


$ php artisan make:seeder UsersTableSeeder
$ php artisan make:seeder AdminsTableSeeder

UsersTableSeeder.php


    public function run()
    {
        DB::table('users')->insert([
            'name' => Str::random(10),
            'email' => Str::random(10).'@gmail.com',
            'password' => Hash::make('password'),
        ]);
    }

AdminsTableSeeder.php


    public function run()
    {
        DB::table('admins')->insert([
                'email' => 'xxxx@xxxx.com',
                'name' => 'Admin',
                'password' => Hash::make('password')
            ]
        );
    }

DatabaseSeeder.php

Seeder ファイルが作成されたら、「database/seeds/DatabaseSeeder.php」に seeder を実行できるよう設定します。


public function run()
{
     $this->call(UsersTableSeeder::class);
     $this->call(AdminsTableSeeder::class);
}

設定したら、artisan コマンドで Seeder を実行します。


$ php artisan db:seed

実際に、テーブルにデータが作成されているか確認してみましょう。

Factory

ここでは割愛しますが、Factory の faker を利用する方法で seeder を実行できます。
Factory ファイルは以下のコマンドで作成できます。


$ php artisan make:factory UserFactory

コントローラー作成

各種コントローラーを作成します。

管理者ホーム

App/Http/Controllers/Admin/ にコントローラーを作成します。


$ php artisan make:controller Admin/HomeController

Admin/HomeController.php

ファイルを作成したら、index の実装と、コンストラクタに認証用のミドルウェアを記述(Guard で設定したパラメータ)をします。
以下の例は、管理者の認証制御となります。

    public function __construct()
    {
        $this->middleware('auth:admin');
    }

    public function index(Request $request)
    {
        return view('admin.index');
    }

ただコントローラが増えてくると、コンストラクタに毎度記述するのも面倒なので、Route のグループ設定で一括管理すると良いでしょう。
(認証用の親コントローラを継承する方法もありますが)

Route の設定

認証が必要・不要のページを考えて、グループ化した Route を設定します。

認証が不要のページ

ログイン、ログアウト、登録ページなどの認証不要のページのルートを作成します。
管理者URIは、admin で統一したいので「admin」プリフィックスを利用しています。

routes/web.php


Route::group(['prefix' => 'admin'], function () {
    Route::get('login', 'Admin\Auth\LoginController@index')->name('admin.login');
    Route::post('login', 'Admin\Auth\LoginController@login')->name('admin.login');
    Route::get('logout', 'Admin\Auth\LoginController@logout')->name('admin.logout');
    Route::post('logout', 'Admin\Auth\LoginController@logout')->name('admin.logout');
});

認証が必要のページ

認証が必要なページのルートを設定します。
ルートグループのパラメータに、ミドルウェアの Guard 設定します。


Route::group(['prefix' => 'admin/topic', 'middleware' => 'auth:admin'], function() {
    Route::get('/', 'Admin\HomeController@index')->name('admin.index');
});

  2020/03/19

2020/03/03 に Laravel7 がリリースされたので、ちょっとだけ見てみました。

(2020/3/19 現在、バージョンは 7.1.3)

https://laravel.com/docs/7.x/upgrade

Symphony 5 リリース

  • Laravel7 では Symphony5 以上
  • PHP 7.2.5 以上
  • laravel/framework ^7.0
  • nunomaduro/collision ^4.1
  • phpunit/phpunit ^8.5
  • facade/ignition ^2.0
  • laravel/tinker ^2.0
  • facade/ignition  ^2.0
  • report()、render() は、Exception から Throwable に変更

use Throwable;
public function report(Throwable $exception);
public function render($request, Throwable $exception);

Authentication

「Authentication Scaffolding」が変更となったようです。

Scaffolding

  • 認証の自動作成の改修
  • Illuminate\Auth\Passwords\TokenRepositoryInterface
  • recentlyCreatedToken メソッドが追加

Eloquent

Date Serialize

  • Eloquent Model で Carbon の日付フォーマット改修
  • ISO-8601 による、timezone と 秒の小数部の対応
  • 現状の仕様をキープしたい場合は、serializeDate をオーバーライド

DB と Eloquent のフォーマットがことなると、Exception になるのでこれが改修されたか?検証が必要

Unique Route Names

  • 同じ Route名を指定できなくなった
  • 重複する場合は、重大なエラーが発生する

CORS サポート

  • Cross-Origin Resource Sharing (CORS) でクロスドメイン通信
  • 「\Fruitcake\Cors\HandleCors::class」を グローバルの Middleware に追加

$ composer require fruitcake/laravel-cors

CastsAttributes

「CastsAttributes」を implements することで、カスタムでキャストすることができます。

カスタムクラスに、get、set メソッドを追加し、Eloquent モデルに $casts を設定することで、自動的にキャストされるようです。

下記の例は、json_decode()、json_encode() を利用して JSON型のキャストを行なっています。


namespace App\Casts;

use Illuminate\Contracts\Database\Eloquent\CastsAttributes;

class Json implements CastsAttributes
{
    public function get($model, $key, $value, $attributes)
    {
        return json_decode($value, true);
    }

    public function set($model, $key, $value, $attributes)
    {
        return json_encode($value);
    }
}

namespace App;

use App\Casts\Json;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    protected $casts = [
        'options' => Json::class,
    ];
}

Blade

The component Method

  • 「Blade::component」 から 「Blade::aliasComponen」に名称変更

Blade Component Tags

Viewコンポーネントクラスにプロパティやメソッドを設定することで、Blade の記述をシンプルにできます。

下記の例は、Alert コンポーネントクラスを作成し「alert.blade.php」に対して、class を動的に設定します。


namespace App\View\Components;

use Illuminate\View\Component;

class Alert extends Component
{
    public $type;

    public function __construct($type)
    {
        $this->type = $type;
    }

    public function classForType()
    {
        return $this->type == 'danger' ? 'alert-danger' : 'alert-warning';
    }

    public function render()
    {
        return view('components.alert');
    }
}

Factory Types

  • Laravel7 から factory types が削除された

プロジェクト作成

実際に、認証処理を実装していきます。

※Laravel7 の認証ページ

https://readouble.com/laravel/7.x/ja/authentication.html


$ composer create-project laravel/laravel laravel-auth --prefer-dist
$ chmod -R 777 storage
$ chmod -R bootstrap/cache

バージョン確認


$ php artisan --version
Laravel Framework 7.1.3

この時点で、 config/auth.php などが作成されています。

  • config/auth.php
  • app/User.php
  • app/Http/Middleware/Authenticate.php
  • database/migrations/xxxx_create_users_table.php
  • database/migrations/xxxx_create_password_resets_table.php
  • database/factories/UserFactory.php

app/User.php


namespace App;

use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;

class User extends Authenticatable
{
    use Notifiable;
    protected $fillable = [
        'name', 'email', 'password',
    ];
    protected $hidden = [
        'password', 'remember_token',
    ];
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];
}

最近のバージョンアップが早く、仕様も日々変わりつつあるのでチェックが必要ですね。

  2020/03/15

Laravel + Vue.js 環境において、Vue コンポーネントを利用してみます。

プロジェクト作成

Laravel プロジェクトを作成します。


$ composer create-project --prefer-dist laravel/laravel laravel-vuemix
$ cd laravel-vue-mix
$ chmod 777 storage
$ chmod 777 bootstrap/cache/

Laravel Vue UI 追加

Vue に対応した Laravel UI を作成します。


$ composer require laravel/ui --dev
$ php artisan ui vue
$ npm install

ファイルを確認する

Webpack Mix

webpack.mix.js が作成されています。


const mix = require('laravel-mix');

mix.js('resources/js/app.js', 'public/js') 
    .sass('resources/sass/app.scss', 'public/css'); 

デフォルトでは、以下が作成&設定されています。

  • resources/js/app.js
  • resources/sass/app.scss

resources/js/app.js


Vue.component('example-component', require('./components/ExampleComponent.vue').default);

const app = new Vue({
    el: '#app',
}
});

サンプル Vue コンポーネント

Vue UIを作成すると、「resources/js/components/ExampleComponent.vue」が作成されています。

このコンポーネントファイルは、app.js で設定されています。


Vue.component('example-component', require('./components/ExampleComponent.vue').default);

第1引数に「タグ名」、第2引数にコンポーネントを設定します。


Vue.component('タグ名', require('.vueファイルパス').default)

コンテンツ作成

コントローラー、ビュー(レイアウト、ページ)を作成し「app.js」「app.css」も読み込むようにします。

Controller

SampleController 作成


$ php artisan make:controller SampleController --resource

SampleController.php の index() を修正


    public function index()
    {
        return view('sample.index');
    }

Route 追加

sample/index にアクセスできるように、route/web.php に追記します。


Route::get('/sample', 'SampleController@index')->name('sample');

ビュー作成

レイアウトファイル

resources/views/layouts/app.blade.php を作成

head タグに app.js 用の scriptタグと app.css 用の linkタグを blade で追記します。


src="{{ asset('js/app.js') }} //script タグで head などに追記
href="{{ asset('css/app.css') }}  //link タグ head などにで追記

ページファイル

resources/views/sample/index.blade.php を作成し、ExampleComponent.vue を読み込みます。

app.js で設定した example-component タグで利用可能です。

カスタム Vue コンポーネント作成

「resources/js/components/」に MessageComponent.vue コンポーネントを作成します。

template 部分

script 部分

script タグで以下を記述します。


export default {
    data: function() {
        return {
            message: "Message Component Message!",
        }
    }
}

app.js

app.js に「MessageComponent.vue」の設定を追記します。


Vue.component('message-component', require('./components/MessageComponent.vue').default);

ビルド

npm または yarn でビルドし、app.js を書き出します。

書き出し先は、「webpack.mix.js」で設定した通りです。


$ npm install
$ npm run dev
//または
$ yarn install
$ yarn run dev

watch で監視

毎回、run dev するのは面倒なので、watch を使ってファイル修正を監視します。


$ npm run watch
//または
$ yarn run watch

Laravel で確認

実際に、Laravel にアクセス(SampleController@index)すると、 「example-component」「message-component」に対応して表示されます。

  2020/03/02

composer update したところ、ext-dom がないから PHPUnitが入れられないようです。


$ composer update
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - phpunit/phpunit 8.5.x-dev requires ext-dom * -> the requested PHP extension dom is missing from your system.
...

php-xml をインストール


# aptitude update
# aptitude install php-xml

再度 composer update する

今度は、インストールが進み、vendor もインストールされた。


$ composer update
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 87 installs, 0 updates, 0 removals
As there is no 'unzip' command installed zip files are being unpacked using the PHP zip extension.
This may cause invalid reports of corrupted archives. Besides, any UNIX permissions (e.g. executable) defined in the archives will be lost.
Installing 'unzip' may remediate them.
  - Installing symfony/polyfill-ctype (v1.14.0): Loading from cache
...

  2020/03/01

Eloquent で DBから日付を扱う場合、$date にカラム指定することで自動キャストされます。
(ただし、DBデータの日付フォーマットには注意が必要です)

日付カラム指定


    protected $dates = [
        'created_at',
        'updated_at',
        'posted_at',
    ];

Carbon フォーマット

$datesで指定したカラムは、DB取得データで Carbon にキャストされているため、以下のように Blade でも読みやすい記述ができます。

 
@foreach ($values as $value)
{{ $value->posted_at->format('Y/m/d') }}
@endforeach

フォーマット指定

日付フォーマットも指定できる。


protected $dateFormat = 'Y-m-d H:i:s.u'; 

が、DBデータフォーマットと不整合があると、Exception(Carbon の Create.php)が発生するので注意が必要です。

個人的には「Y-m-d H:i:s」にした方が無難な気がします。

PostgreSQLの場合

  • created_at は CURRENT_TIMESTAMP
  • timstamp without time zone
  • timestamp(0) 

明示的に指定する場合は、


$table->timestamp('created_at')->default(DB::raw('now()::timestamp(0)'));

  2020/02/06

Freee SDK

ありそうでなかった会計向けSDK
freee が国内初なようで、2020/02時点の対応言語は「C#」「Java」「PHP」

freee API と統制をとるために「OpenApi generator」を利用して有志が開発しているとのこと

C#

https://github.com/freee/freee-accounting-sdk-csharp/

Java

https://github.com/freee/freee-accounting-sdk-java

PHP

https://github.com/freee/freee-accounting-sdk-php/

PHPの場合は、composer で用意されており、さらにサンプル用に Docker & Laravel が公開されている。

サンプルの動作例

freee API

freee API

Docker & Laravel でサンプルを動かす

コールバックURL

freee APIアプリの「コールバックURL」は以下を設定しておく
※デフォルト:urn:ietf:wg:oauth:2.0:oob
※Laravel dでも後に設定する


http://localhost:8000/auth-callback

サンプルダウンロード & 設定

サンプルは SDK の中に入っているので git clone


$ git clone https://github.com/freee/freee-accounting-sdk-php.git

.env を設定する


$ cd freee-accounting-sdk-php.git
$ cd samples/BasicWebApp
$ cp .env.example .env

freeeアプリ の Client ID、Secret ID を記述


FREEE_ACCOUNTING_CLIENT_ID=Client ID
FREEE_ACCOUNTING_CLIENT_SECRET=Secret ID

Dockerの起動

freee-accounting-sdk-php にあるサンプルを利用する

$ cd freee-accounting-sdk-php/samples/BasicWebApp
$ cd samples
$ docker-compose build
$ docker-compose up -d
$ docker exec -it samples_webapp_1 /bin/bash

docker-compose.yaml


version: "3.7"
services:
  console:
    build:
      context: .
      dockerfile: Dockerfile
    image: freee-accounting-sdk-php-console
    volumes:
      - "./BasicConsole:/usr/src/app"
    command: /bin/sh -c "while sleep 1000; do :; done"
  webapp:
    build:
      context: .
      dockerfile: Dockerfile
    image: freee-accounting-sdk-php-webapp
    ports:
      - "80:80"
      - "8000:8000"
    volumes:
      - "./BasicWebApp:/usr/src/app"
    command: /bin/sh -c "while sleep 1000; do :; done"

Dockerfile


FROM php:7.3-cli
RUN apt-get update; \
    curl -sL https://deb.nodesource.com/setup_12.x | bash -; \
    apt-get install -y --no-install-recommends \
        git \
        libzip-dev \
        nodejs \
        unzip \
        zlib1g-dev \
    ; \
    rm -rf /var/lib/apt/lists/*

RUN docker-php-ext-install zip
WORKDIR /tmp
RUN curl https://raw.githubusercontent.com/composer/getcomposer.org/76a7060ccb93902cd7576b67264ad91c8a2700e2/web/installer -o - -s | php -- --quiet; \
    mv composer.phar /usr/local/bin/composer
WORKDIR /usr/src/app
RUN composer global require laravel/installer
ENV PATH /root/.composer/vendor/bin:$PATH
EXPOSE 8000

Composer インストール

webpackが用意されているので、すぐインストールできる


# composer install

composer、Laravel を直にインストールする場合


$ composer require freee/freee-accounting-sdk
$ composer require socialiteproviders/generators
$ composer require socialiteproviders/manager

artisan で socialiteproviders/generators を実行


$ php artisan make:socialite FreeeAccounting --spec=oauth2 --authorize_url=https://accounts.secure.freee.co.jp/public_api/authorize --access_token_url=https://accounts.secure.freee.co.jp/public_api/token --user_details_url=https://api.freee.co.jp/api/1/users/me
$ composer dumpautoload

Laravel/UI を作成


$ composer require laravel/ui --dev
$ php artisan ui vue --auth
$ npm install && npm run dev

Laravel artisanサーバ起動


# php artisan key:generate
# php artisan serve
# php artisan serve --host 0.0.0.0

プロジェクトルートは「samples/BasicWebApp/」

認証処理

routes/web.php


Auth::routes([
    'register' => false,
    'reset' => false,
]);

Route::get('login', 'Auth\LoginController@redirectToProvider')->name('login');
Route::get('auth-callback', 'Auth\LoginController@handleProviderCallback')->name('authCallback');

config/service.php

「client_id」「client_secret」「redirect」をそれぞれ設定 (リダイレクトURLは、freeeのアプリ管理と合わせる)


 'freeeaccounting' => [
        'client_id' => env('FREEE_ACCOUNTING_CLIENT_ID'),
        'client_secret' => env('FREEE_ACCOUNTING_CLIENT_SECRET'),
        'redirect' => 'http://localhost:8000/auth-callback',
    ],

config/auth.php

freee用ドライバー、プロバイダー設定

    'defaults' => [
        'guard' => 'freee',
        'passwords' => 'users',
    ],
....
    'guards' => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],
        'api' => [
            'driver' => 'token',
            'provider' => 'users',
            'hash' => false,
        ],
        'freee' => [
            'driver' => 'freee',
            'provider' => 'freee',
        ],
    ],
...
    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\User::class,
        ],
        'freee' => [
            'driver' => 'freee',
        ],
    ],

app\Http\Auth\LoginController.php

ログイン処理は、Laravel Socialite ドライバーを利用し、GenericUser で認証する


use App\Http\Controllers\Controller;
use Illuminate\Auth\GenericUser;
use Illuminate\Support\Facades\Auth;
use Socialite;

...

    public function redirectToProvider()
    {
        return Socialite::driver('freeeaccounting')->redirect();
    }

    public function handleProviderCallback()
    {
        $user = Socialite::driver('freeeaccounting')->user();

        $genericUser = $user->getRaw();
        $genericUser['token'] = $user->token;
        $genericUser['remember_token'] = '';
        Auth::login(new GenericUser($genericUser));

        return redirect()->intended($this->redirectTo);
    }

    public function logout()
    {
        Auth::logout();
        return redirect()->intended('/');
    }

認証用サービスプロバイダー

app/Providers/AuthServiceProvider.php


namespace App\Providers;

use App\Extensions\SampleSessionGuard;
use App\Extensions\FreeeUserProvider;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Auth;

class AuthServiceProvider extends ServiceProvider
{
  protected $policies = [
    // 'App\Model' => 'App\Policies\ModelPolicy',
  ];
  public function boot()
  {
    $this->registerPolicies();

    Auth::extend('freee', function ($app, $name, array $config) {
      return new SampleSessionGuard(
        $name,
        Auth::createUserProvider($config['provider']),
        $app['session.store']
      );
    });

    Auth::provider('freee', function ($app, array $config) {
      return new FreeeUserProvider();
    });
  }
}

イベントサービスプロバイダー

app/Providers/EventServiceProvider.php


namespace App\Providers;

use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
use SocialiteProviders\Manager\SocialiteWasCalled;
use SocialiteProviders\FreeeAccounting\FreeeAccountingExtendSocialite;

class EventServiceProvider extends ServiceProvider
{
    protected $listen = [
        Registered::class => [
            SendEmailVerificationNotification::class,
        ],
        SocialiteWasCalled::class => [
            FreeeAccountingExtendSocialite::class,
        ],
    ];

    public function boot()
    {
        parent::boot();
    }
}

SocialiteProviders設定

SocialiteProviders/src/FreeeAccounting/Provider.php

https://api.freee.co.jp/api/1/users/me からユーザを返す関数を作成


    protected function getUserByToken($token)
    {
        $response = $this->getHttpClient()->get('https://api.freee.co.jp/api/1/users/me', [
            'headers' => [
                'Authorization' => 'Bearer '.$token,
            ],
        ]);

        $body = json_decode($response->getBody(), true);
        return $body['user'];
    }

User のマッピング


    protected function mapUserToObject(array $user)
    {
        $user['name'] = $user['last_name'] . ' ' . $user['first_name'];
        return (new User())->setRaw($user)->map([
            'id'       => $user['id'],
            'name'     => $user['name'],
            'email'    => $user['email'],
            'display_name' => $user['display_name'],
            'first_name' => $user['first_name'],
            'last_name' => $user['last_name'],
            'first_name_kana' => $user['first_name_kana'],
            'last_name_kana' => $user['last_name_kana'],
        ]);
    }

事業所と取引(収入/支出)一覧の取得

app/Http/AccountController.php

ログイン認証したユーザトークンを、Configuration クラスに設定


$user = Auth::user();
$config = Configuration::getDefaultConfiguration()->setAccessToken($user->token);

ちなみに、getAccessToken() でアクセストークンを確認できる。

$config->getAccessToken()

CompaniesApi で事業所IDを取得


$companiesApiInstance = new CompaniesApi(null, $config);
$companiesResponse = $companiesApiInstance->getCompanies();
$targetCompanyId = $companiesResponse->getCompanies()[0]->getId();

DealsApi で取引(収入/支出)一覧の取得


$limit = 5;
$dealsApiInstance = new DealsApi(null, $config);
$dealsResponse = $dealsApiInstance->getDeals(
            $targetCompanyId,
            null, null, null, null, null, null, null, null, null, null, null, null,
            $limit);
$deals = $dealsResponse->getDeals();

getDeals() の引数がちょっとどうなんだろ?

  2020/01/12

Laravel 6.x Laravel Homestead を利用して Laravel 6.x の環境を構築する。 Homestead は Laravel の vagrant box 版です。

一からコマンドベースで構築するとかなり大変(というか npm の依存とかでエラー多発)なので、公式でも Homestead を推奨しています。

Vagrant バージョンの確認

Download Vagrant から最新の vagrant をインストール(アップデートする) Laravel 6.x Homestead は 2.2.6 以上が必要

$ vagrant --version
Vagrant 2.2.6

プラグインアップデート

Vagrant アップデートした場合は、プラグインもアップデートする必要がある。

$ vagrant plugin update
Updating installed plugins...
Updated 'vagrant-vbguest' to version '0.23.0'!

Vagrant に Homestead を追加

$ vagrant box add laravel/homestead
==> box: Loading metadata for box 'laravel/homestead'
    box: URL: https://vagrantcloud.com/laravel/homestead
==> box: Adding box 'laravel/homestead' (v9.2.2-alpha1) for provider: virtualbox
    box: Downloading: https://vagrantcloud.com/laravel/boxes/homestead/versions/9.2.2-alpha1/providers/virtualbox.box
    box: Download redirected to host: vagrantcloud-files-production.s3.amazonaws
...

Vagrant Box の確認

$ vagrant box list
bento/ubuntu-18.04 (virtualbox, 201906.18.0)
centos/7           (virtualbox, 1905.1)
debian/stretch64   (virtualbox, 9.9.1)
laravel/homestead  (virtualbox, 9.2.2-alpha1)
ubuntu/trusty64    (virtualbox, 20190429.0.1)

Homestead 設定

Git から Homestead 設定を cloneする

$ cd
$ git clone https://github.com/laravel/homestead.git Homestead

初期化

$ bash init.sh
Homestead initialized!

SSH鍵ファイルの作成

$ ssh-keygen -t rsa
Generating public/private rsa key pair.
Enter file in which to save the key (/Users/yoo/.ssh/id_rsa):                   
Enter passphrase (empty for no passphrase): 
Enter same passphrase again: 
...

id_rsa と id_rsa.pub が作成される。

Homestead.yaml 編集

Homestead の起動設定ファイル Homestead.yaml を設定する


ip: "192.168.10.10" #プライベートIPを設定する
memory: 2048
cpus: 2
provider: virtualbox

authorize: ~/.ssh/id_rsa.pub

keys:
    - ~/.ssh/id_rsa

folders:
    - map: ~/vagrant/homestead/projects #ホスト側のプロジェクトパスを設定
      to: /home/vagrant/projects #Vagrant側のプロジェクトパスを設定
      type: "nfs" #nfs を追記する

sites:
    - map: homestead.test #サーバホストを設定する
      to: /home/vagrant/projects/blog/public #Laravel Webルートを設定

databases:
    - homestead

features:
    - mariadb: false
    - ohmyzsh: false
    - webdriver: false

# ports:
#     - send: 50000
#       to: 5000
#     - send: 7777
#       to: 777
#       protocol: udp

上記の設定は、以下のようなパスを設定している


・ホスト側(Mac)
~/vagrant/homestead/projects #プロジェクトパス

・リモート側(Vagrant)
/home/vagrant/projects #プロジェクトパス
/home/vagrant/projects/blog/public #Laravel の public

注意すべくは「folders:」の設定 デフォルトの設定だとNFSマウント(同期)できないので「type: "nfs"」を追記する

vagrant-bindfs プラグインインストール

NFSを利用した場合、ファイルやフォルダへのアクセス権限を維持する為に、vagrant-bindfs プラグインのインストールが必要

$ vagrant plugin install vagrant-bindfs

Vagrant 起動

$ vagrant up

Homestead Vagrant

Vagrant SSHログイン

$ vagrant ssh

各バージョン確認

$ cat /etc/issue
Ubuntu 18.04.3 LTS \n \l
$ laravel -V
Laravel Installer 3.0.1
$ composer -V
Composer version 1.9.1 2019-11-01 17:20:17
$ node --version
v12.14.0
$ yarn --version
1.21.1
$ npm --version
6.13.4
$ php --version
PHP 7.4.1 (cli) (built: Dec 18 2019 14:44:22) ( NTS )
$ psql -V
psql (PostgreSQL) 11.6 (Ubuntu 11.6-1.pgdg18.04+1)

Laravel プロジェクト作成

Vagrant側で Laravel プロジェクトを作成する。 (あらかじめ、~/projects/ ディレクトリ作成済み)

$ cd projects/
$ composer create-project --prefer-dist laravel/laravel blog

ブラウザから Webサーバにアクセス

http://homestead.local にアクセスできるか確認する。 Homestead Laravel

PostgreSQL設定のロケール

en_US.UTF-8 がデフォルトになっているので、ja_JP.UTF-8 に変更する ロケールの再構築 参照

  2019/08/09
try-catch でエラー検出する場合、namespace内でException を待ち受けするため「 Exception」と記述する必要がある。

Laravel の QueryException を検知する場合

    use  Illuminate Database QueryException;
....
    public function store(Request $request)
    {
        try {
            $user = new User;
            $user->fill($request->all())->save();
        } catch ( QueryException $e) {

        }
    }
QueryException
<< 最初 < 前ページ 次ページ > 最後 >>