「laravel.osaka #14」勉強会まとめ


# laravel.osaka とは

> laravel.osaka は「laravelおもろいやん!!」をテーマに、Laravelを愛してやまないPHPer や
これからLaravel/PHPをはじめようする人たちで技術交流を進めていこう、という勉強会です。

[laravel.osaka - connpass](https://laravel.connpass.com/)

ハッシュタグは **[#laravel_osaka](https://twitter.com/search?q=%23laravel_osaka)**

# 日時・場所

- 日時：4月23日（火）19:00 ～ 21:00
- 場所：大阪府大阪市北区同心1丁目11番6号（株式会社 tambourine様）

# 勉強会内容

[[PHP] laravel.osaka #14 - connpass](https://laravel.connpass.com/event/126917/?utm_campaign=event_participate_to_follower&utm_medium=twitter&utm_source=notifications) の勉強会の内容をまとめていきます



## 「Laravelでサービスを作った時にやったこと」

登壇者：[@dala00](https://twitter.com/dala00)さん
スライド：[Laravelでサービスを作った時にやったこと - Speaker Deck](https://speakerdeck.com/dala00/laraveldesabisuwozuo-tutashi-niyatutakoto)
内容：
Qiitaのようなエンジニア向けWEBサービス「[Crieit](https://crieit.net/)」を作った際のお話

※途中参加につきお話聞けず・・・すみません。。。

## 「index.phpの処理を追ってみた」

登壇者：[@choco14t](https://twitter.com/choco14t)さん
スライド：[index.phpの処理を追ってみた / Dive into index.php - Speaker Deck](https://speakerdeck.com/choco14t/dive-into-index-dot-php)
内容：

- index.php
  - この中の

```index.php
$app = require_once __DIR__.'/../bootstrap/app.php';

$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);

$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);
```

について処理を追っていく

- bootstrap/app.php
  - `$app = require_once __DIR__.'/../bootstrap/app.php';`
  - **Application**インスタンス生成
     - サービスプロバイダ
     - エイリアス
  - インスタンス

- `Container::singleton()`
  - `Container::build()`を呼んでいる

```Container\Container.php
    /**
     * Register a shared binding in the container.
     *
     * @param  string  $abstract
     * @param  \Closure|string|null  $concrete
     * @return void
     */
    public function singleton($abstract, $concrete = null)
    {
        $this->bind($abstract, $concrete, true);
    }
```

  - `shared`フラグを`true`にしている

- `Container::bind()`

```Container\Container.php
    /**
     * Register a binding with the container.
     *
     * @param  string  $abstract
     * @param  \Closure|string|null  $concrete
     * @param  bool  $shared
     * @return void
     */
    public function bind($abstract, $concrete = null, $shared = false)
    {
        // If no concrete type was given, we will simply set the concrete type to the
        // abstract type. After that, the concrete type to be registered as shared
        // without being forced to state their classes in both of the parameters.
        $this->dropStaleInstances($abstract);
        if (is_null($concrete)) {
            $concrete = $abstract;
        }
        // If the factory is not a Closure, it means it is just a class name which is
        // bound into this container to the abstract type and we will just wrap it
        // up inside its own Closure to give us more convenience when extending.
        if (! $concrete instanceof Closure) {
            $concrete = $this->getClosure($abstract, $concrete);
        }
        $this->bindings[$abstract] = compact('concrete', 'shared');
        // If the abstract type was already resolved in this container we'll fire the
        // rebound listener so that any objects which have already gotten resolved
        // can have their copy of the object updated via the listener callbacks.
        if ($this->resolved($abstract)) {
            $this->rebound($abstract);
        }
    }
```

- `Application::make()`
  - サービスプロバイダの遅延読み込み（あれば）
  - 依存オブジェクトの解決 

```index.php
$kernel = $app->make(Illuminate\Contracts\Http\Kernel::class);
```

```Foundation/Application.php
    /**
     * Resolve the given type from the container.
     *
     * (Overriding Container::make)
     *
     * @param  string  $abstract
     * @param  array  $parameters
     * @return mixed
     */
    public function make($abstract, array $parameters = [])
    {
        $abstract = $this->getAlias($abstract);
        if (isset($this->deferredServices[$abstract]) && ! isset($this->instances[$abstract])) {
            $this->loadDeferredProvider($abstract);
        }
        return parent::make($abstract, $parameters);
    }
```

```Container/Container.php
    /**
     * Resolve the given type from the container.
     *
     * @param  string  $abstract
     * @param  array  $parameters
     * @return mixed
     */
    public function make($abstract, array $parameters = [])
    {
        return $this->resolve($abstract, $parameters);
    }
```


 - `Container::resolve()`
  - 依存オブジェクトの生成
  - 再帰的に依存オブジェクトを生成
    - `Container::make()`を再呼び出し

```Container/Container.php
    /**
     * Resolve the given type from the container.
     *
     * @param  string  $abstract
     * @param  array  $parameters
     * @return mixed
     */
    protected function resolve($abstract, $parameters = [])
    {
        $abstract = $this->getAlias($abstract);
        $needsContextualBuild = ! empty($parameters) || ! is_null(
            $this->getContextualConcrete($abstract)
        );
        // If an instance of the type is currently being managed as a singleton we'll
        // just return an existing instance instead of instantiating new instances
        // so the developer can keep using the same objects instance every time.
        if (isset($this->instances[$abstract]) && ! $needsContextualBuild) {
            return $this->instances[$abstract];
        }
        $this->with[] = $parameters;
        $concrete = $this->getConcrete($abstract);
        // We're ready to instantiate an instance of the concrete type registered for
        // the binding. This will instantiate the types, as well as resolve any of
        // its "nested" dependencies recursively until all have gotten resolved.
        if ($this->isBuildable($concrete, $abstract)) {
            $object = $this->build($concrete);
        } else {
            $object = $this->make($concrete);
        }
        // If we defined any extenders for this type, we'll need to spin through them
        // and apply them to the object being built. This allows for the extension
        // of services, such as changing configuration or decorating the object.
        foreach ($this->getExtenders($abstract) as $extender) {
            $object = $extender($object, $this);
        }
        // If the requested type is registered as a singleton we'll want to cache off
        // the instances in "memory" so we can return it later without creating an
        // entirely new instance of an object on each subsequent request for it.
        if ($this->isShared($abstract) && ! $needsContextualBuild) {
            $this->instances[$abstract] = $object;
        }
        $this->fireResolvingCallbacks($abstract, $object);
        // Before returning, we will also set the resolved flag to "true" and pop off
        // the parameter overrides for this build. After those two things are done
        // we will be ready to return back the fully constructed class instance.
        $this->resolved[$abstract] = true;
        array_pop($this->with);
        return $object;
    }
```

- Container::build()
  - インスタンスの生成
  - Reflectionを使って実現

- Http\kernal::handle()
  - リクエストを受け取ってレスポンスを返す

```index.php
$response = $kernel->handle(
    $request = Illuminate\Http\Request::capture()
);
```

- ブートストラッピング
  - config
  - facade
  - service provider

- 対応したルーティングの処理実行
- レスポンス返却

```Foundation\Http\Kernel.php
    /**
     * Handle an incoming HTTP request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @return \Illuminate\Http\Response
     */
    public function handle($request)
    {
        try {
            $request->enableHttpMethodParameterOverride();
            $response = $this->sendRequestThroughRouter($request);
        } catch (Exception $e) {
            $this->reportException($e);
            $response = $this->renderException($request, $e);
        } catch (Throwable $e) {
            $this->reportException($e = new FatalThrowableError($e));
            $response = $this->renderException($request, $e);
        }
        $this->app['events']->dispatch(
            new Events\RequestHandled($request, $response)
        );
        return $response;
    }
```


- Http\Kernel.php
  - [\Illuminate\Foundation\Bootstrap\HandleExceptions::class](https://github.com/laravel/framework/blob/5.5/src/Illuminate/Foundation/Bootstrap/HandleExceptions.php)が書かれている処理が少なく読みやすい

```Foundation\Http\Kernel.php
    /**
     * The bootstrap classes for the application.
     *
     * @var array
     */
    protected $bootstrappers = [
        \Illuminate\Foundation\Bootstrap\LoadEnvironmentVariables::class,
        \Illuminate\Foundation\Bootstrap\LoadConfiguration::class,
        \Illuminate\Foundation\Bootstrap\HandleExceptions::class,
        \Illuminate\Foundation\Bootstrap\RegisterFacades::class,
        \Illuminate\Foundation\Bootstrap\RegisterProviders::class,
        \Illuminate\Foundation\Bootstrap\BootProviders::class,
    ];
```

### まとめ

 - 実際に処理が行われるまで膨大な処理が実行されている
 - Laravelのコードを読むことは可能なので読んでみましょう

## 「LaravelでREST API開発（ライブコーディング）」

登壇者：[@_mikakane](https://twitter.com/_mikakane)さん
スライド：なし
内容：

- 開発環境構築について
  - `$ laravel new` で環境構築できる
  - `$ php artisan serve`コマンドでサーバーが立ち上がる

- Laravel Mixを使用する際はnpmビルドする必要がある

- [Laravel Telescope](https://readouble.com/laravel/5.8/ja/telescope.html)
  - 上からキャッシュやリクエストを確認できる

- `Factory`でサンプルのユーザーデータが簡単につくれる

- `Str::random()`でランダムの文字列を生成される → [Str::random()](https://laravel.com/docs/5.8/helpers#method-str-random)

- 画面のテストは`tests\Feature`ディレクトリ内にかく
  - テストの際に`assertStatus(200)`を書いておくだけでもちゃんとレスポンスが返ってくるかの確認ができる
  - テストを実行する際は`phpunit`コマンドをたたく
  - パスワードを検証する際は`Hash::check()`メソッドを使用する
     - これで認証失敗の場合は`abort(403)`を返すようにする
  - この反対のメソッドをテストに書いておくと、正常系は`200`、認証失敗は`403`を返すということを確認できる
  - RESTAPIを作成するときは`postメソッド`等を使用することにより内部的にリクエストを送ることができるのでこれらをつかってテストコードをかく
  - ヘッダを送るときは`$this->withHeader`を使う

- テストコードを書いて実装 いわゆる「テスト駆動開発」

- `@depends メソッド名` とアノテーションを書いてやるとそのテストを実行後でないと実行されない＆返り値をそのメソッドの引数に渡せる
 - ログインのテスト実行後、トークンを引数として渡してやると、以降のテストで認証情報を使える

### まとめ

- Laravel Telescopeは便利だが画面の行き来が発生する
- ほとんどの作業がPhpStorm上で完結する（RESTAPIの開発が可能）


## LT枠：20年目のPHPer、laravelと出会う

登壇者：[@takujiozaki](https://twitter.com/takujiozaki)さん
スライド：なし
内容：

- 専門学校の教師をしている
- プログラマー＝Javaという認識の生徒が多い
- 教え子から現場ではLaravelを使うことが多いという話を聞く
  - Laravelを勉強し始めた

# おわり
- 登壇者の方、主催者の方、ありがとうございました＆お疲れ様でした！
- まとめのくせにまとまってないのはすみません。。
- わかる部分とわからない部分があるのでもっと勉強します