Laravel 5.4: Class 'Form' not found エラーが出る
What?
illuminate/html
を使って、フォームを作ろうとすると、Class 'Form' not found (View: /home/vagrant/Code/laravel/resources/views/articles/create.blade.php)
エラーが出る
Why?
- Laravel 5.2 から仕様がちょっと変わった
illuminate/html
ではなく、laravelcollective/html
を使う
Collective\Html\HtmlServiceProvider::class,
のHTML
を大文字にしてた。。。
How to?
composer require laravelcollective/html
する
$ composer require laravelcollective/html Using version ^5.4 for laravelcollective/html ./composer.json has been updated Loading composer repositories with package information Updating dependencies (including require-dev) Nothing to install or update Generating autoload files > Illuminate\Foundation\ComposerScripts::postUpdate > php artisan optimize Generating optimized class loader The compiled services file has been removed. laravel vagrant master *%$ composer dump-autoload -o Generating optimized autoload files
config/app.php
'providers' => [ ... Collective\HTML\HtmlServiceProvider::class, ... ], ... 'aliases' => [ ... 'Form' => Collective\Html\FormFacade::class, 'Html' => Collective\Html\HtmlFacade::class, ... ],
- ん?できない。
- エラーが変わった
FatalThrowableError in ProviderRepository.php line 201: Class 'Collective\HTML\HtmlServiceProvider' not found
$ ls -la vendor/laravelcollective/html/src/HtmlServiceProvider.php -rw-r--r-- 1 vagrant vagrant 1489 Mar 9 15:10 vendor/laravelcollective/html/src/HtmlServiceProvider.php $ composer info | grep laravel laravel/framework v5.4.15 The Laravel Framework. laravel/tinker v1.0.0 Powerful REPL for the Laravel framework. laravelcollective/html v5.4.1 HTML and Form Builders for the Laravel Framework $ grep -r HtmlServiceProvider vendor/composer/ vendor/composer/autoload_classmap.php: 'Collective\\Html\\HtmlServiceProvider' => $vendorDir . '/laravelcollective/html/src/HtmlServiceProvider.php', vendor/composer/autoload_static.php: 'Collective\\Html\\HtmlServiceProvider' => __DIR__ . '/..' . '/laravelcollective/html/src/HtmlServiceProvider.php',
- 3日悩んだ結果。
'providers' => [ ... Collective\Html\HtmlServiceProvider::class, ... ],
- 答え:
HTML
じゃなくてHtml
な。。。- ディレクトリ名なので大文字小文字が厳密に判断される
- composerを使って、オートロードしているので、以下と一緒じゃなきゃだめ
- ディレクトリ名なので大文字小文字が厳密に判断される
$ less vendor/composer/installed.json "autoload": { "psr-4": { "Collective\\Html\\": "src/" },
次、困ったときは順番にこれをやる
- Issue composer require “laravelcollective/html”:“^5.3.0”.
- Verify that the vendor/laravelcollective/html directory exists.
- Verify that your composer.json file has been updated and there’s an entry for laravelcollective/html package in your dependencies (require block).
- Add Collective\Html\HtmlServiceProvider::class to your providers array of config/app.php.
- Add ‘Form’ => Collective\Html\FormFacade::class and ‘Html’ => Collective\Html\HtmlFacade::class to your aliases array.
- Confirm that the API exists: Issue a php artisan tinker command and try playing with Form:: APIs. See if throws any errors.
知見
- ハマったら、キャッシュクリアしたり、再インストールしたりする(今回あんま関係なかったけど)
$ composer dump-autoload $ composer update $ composer clear-cache $ php artisan route:clear $ php artisan cache:clear $ php artisan config:clear $ composer remove laravelcollective/html $ composer require laravelcollective/html
参考
Dependency "laravel/framework" is also a root requirement, but is not explicitly whitelisted. Ignoring.の意味
What?
Dependency "laravel/framework" is also a root requirement, but is not explicitly whitelisted. Ignoring.
と表示されて意味がわからん
$ composer remove laravelcollective/html Dependency "laravel/framework" is also a root requirement, but is not explicitly whitelisted. Ignoring. Dependency "laravel/framework" is also a root requirement, but is not explicitly whitelisted. Ignoring. Dependency "laravel/framework" is also a root requirement, but is not explicitly whitelisted. Ignoring. Dependency "laravel/framework" is also a root requirement, but is not explicitly whitelisted. Ignoring. Dependency "laravel/framework" is also a root requirement, but is not explicitly whitelisted. Ignoring. Loading composer repositories with package information Updating dependencies (including require-dev) Package operations: 0 installs, 0 updates, 1 removal - Removing laravelcollective/html (v5.4.1) Writing lock file Generating autoload files > Illuminate\Foundation\ComposerScripts::postUpdate > php artisan optimize [Symfony\Component\Debug\Exception\FatalThrowableError] Class 'Collective\HTML\HtmlServiceProvider' not found Script php artisan optimize handling the post-update-cmd event returned with error code 1 Removal failed, reverting ./composer.json to its original content.
直訳: Dependency “laravel/framework” is also a root requirement, but is not explicitly whitelisted. Ignoring.
- 依存関係にある"laravel/framework"はrootの必須項目です。しかし、明示的にホワイトリストに入っていません。無視します。
-
- Composerではパッケージ更新時に引数として与えられる依存パッケージリストをホワイトリストと呼んでいる
- e.g.
$ composer update hoge fuga piyo
つまり、今回指定されたのは、
laravelcollective/html
だけで、明示的にlaravel/framework
が引数として指定されたわけではないので、laravel/framework
は消さないよ。ということです。
composer removeとかupdateとかできない
What?
Class hogehoge not found
と表示されて、composerでライブラリ操作ができなくなる
$ composer remove illuminate/html Dependency "laravel/framework" is also a root requirement, but is not explicitly whitelisted. Ignoring. Dependency "laravel/framework" is also a root requirement, but is not explicitly whitelisted. Ignoring. Dependency "laravel/framework" is also a root requirement, but is not explicitly whitelisted. Ignoring. Loading composer repositories with package information Updating dependencies (including require-dev) Package operations: 0 installs, 0 updates, 1 removal - Removing illuminate/html (v5.0.0) Writing lock file Generating autoload files > Illuminate\Foundation\ComposerScripts::postUpdate > php artisan optimize [Symfony\Component\Debug\Exception\FatalThrowableError] Class 'Collective\HTML\HtmlServiceProvider' not found Script php artisan optimize handling the post-update-cmd event returned with error code 1 Removal failed, reverting ./composer.json to its original content.
How to
config/app.php
のproviders
に使っていないものが書いてあるので、消す
'providers' => [ ... // Collective\HTML\HtmlServiceProvider::class, ... ],
- おっけー
$ composer remove illuminate/html Package "illuminate/html" listed for update is not installed. Ignoring. Loading composer repositories with package information Updating dependencies (including require-dev) Nothing to install or update Generating autoload files > Illuminate\Foundation\ComposerScripts::postUpdate > php artisan optimize Generating optimized class loader The compiled services file has been removed.
$ composer require laravelcollective/html Using version ^5.4 for laravelcollective/html ./composer.json has been updated Loading composer repositories with package information Updating dependencies (including require-dev) Package operations: 1 install, 0 updates, 0 removals - Installing laravelcollective/html (v5.4.1) Downloading: 100% Writing lock file Generating autoload files > Illuminate\Foundation\ComposerScripts::postUpdate > php artisan optimize Generating optimized class loader The compiled services file has been removed.
How to その2
php artisan optimize
でコケてるので、--no-scripts
オプションで実行後スクリプトを実行させない
$ composer remove --no-scripts laravelcollective/html Package "laravelcollective/html" listed for update is not installed. Ignoring. Loading composer repositories with package information Updating dependencies (including require-dev) Nothing to install or update Generating autoload files
$ composer require --no-scripts laravelcollective/html Using version ^5.4 for laravelcollective/html ./composer.json has been updated Loading composer repositories with package information Updating dependencies (including require-dev) Nothing to install or update Generating autoload files
Homestead をリロードしようとしたらエラーになる
What?
- カフェに行ってPCを開いて、起動しっぱなしのHomesteadサーバにアクセスしたらエラー
- vagrantからリロードしても以下のエラーが出て立ち上がらない
$ vagrant reload ==> homestead-7: Attempting graceful shutdown of VM... ==> homestead-7: Checking if box 'laravel/homestead' is up to date... ==> homestead-7: Clearing any previously set forwarded ports... ==> homestead-7: Clearing any previously set network interfaces... The specified host network collides with a non-hostonly network! This will cause your specified IP to be inaccessible. Please change the IP or name of your host only network so that it no longer matches that of a bridged or non-hostonly network.
Why?
英語を読もう(雑訳)
- ホストオンリーではないネットワークで、特定のホストネットワークが衝突してます
- これは、あなたが設定したIPにアクセス出来ないということです
- そのホストはブリッジされているもしくはホストオンリーではないネットワークにおいて、もうマッチしていないので、あなたのホストオンリーネットワークのIPか名前を変えてください。
つまりは、外で作業を初めて、今のIP(homesteadのデフォルトIP: 192.168.10.10)が他の人と被ったから
Solution
.homestead/Homestead.yaml
ip: "192.168.10.10"
を
ip: "192.168.10.11"
とかに変更する。
- /etc/hosts も変更することを忘れずに
Laravel 5.4: Model, Controller, Viewワークフロー
Why?
- Articleの一覧、詳細を作ることで、一通りのModel, Controller, Viewワークフローを流す
How to
Articleの一覧を作る
app/Http/routes.php
にRoutingを追加
Route::get('articles', 'ArticlesController@index');
- Controllerを追加 (laravel 5.2から
–plain
オプションはデフォルトになったので不要)app/Http/Controllers/ArticlesController.php
が追加される
$ php artisan make:controller ArticlesController
app/Http/Controllers/ArticlesController.php
にindexメソッドを追加 (まずはviewに渡さずにプレーンに表示)
<?php namespace App\Http\Controllers; use Illuminate\Http\Request; use App\Article; class ArticlesController extends Controller { public function index() { $articles = Article::all(); return $articles; } }
- プレーンなレスポンスが帰ってくる
[ { id: 1 title: "My Update First Article" body: "Lorem ipsum" ... } ]
app/Http/Controllers/ArticlesController.phpView
からViewに渡す
public function index() { $articles = Article::all(); return view('articles.index', compact('articles')); }
- View
resources/views/articles/index.blade.php
を追加
@extends('app') @section('content') <h1>Articles</h1> <hr /> @foreach ($articles as $article) <article> <h2>{{ $article->title }}</h2> <div class="body">{{ $article->body }}</div> </article> @endforeach @stop
Articleの詳細を作る
app/Http/routes.php
にRoutingを追加
Route::get('articles/{id}', 'ArticlesController@show');
app/Http/Controllers/ArticlesController.php
にshowメソッドを追加
public function show($id) { $article = Article::findOrFail($id); return view('articles.show', compact('article')); }
- View
resources/views/articles/show.blade.php
を追加
@extends('app') @section('content') <h1>{{ $article->title }}</h1> <article> <div class="body">{{ $article->body }}</div> </article> @stop
一覧と詳細ページを繋げる
resources/views/articles/show.blade.php
にリンク追加
@extends('app') @section('content') <h1>{{ $article->title }}</h1> <article> <div class="body">{{ $article->body }}</div> </article> <a href="/articles/">< Back to list</a> @stop
resources/views/articles/index.blade.php
にリンク追加
@extends('app') @section('content') <h1>Articles</h1> <hr /> @foreach ($articles as $article) <article> <h2><a href="/articles/{{ $article->id }}">{{ $article->title }}</h2></a> <div class="body">{{ $article->body }}</div> </article> @endforeach @stop
参考
Laravel 5.4: Eloquent ORMを使ってみる
What?
- Eloquent ORM: Laravel5にデフォルトで組み込まれているORマッパー
- RailsのActive Recodeみたいに使える
How to
DBにモデルを保存
- モデルを作る ->
app/Article.php
ができている
$ php artisan make:model Article $ cat app/Article.php <?php namespace App; use Illuminate\Database\Eloquent\Model; class Article extends Model { // }
- モデルができているかtinkerで確認
$ php artisan tinker >>> $article = new App\Article; => App\Article {#668}
- モデルを使う (オブジェクトを作って、値を入れる)
>>> $article = new App\Article; => App\Article {#673} >>> $article->title = 'My First Article'; => "My First Article" >>> $article->body = 'Lorem ipsum'; => "Lorem ipsum" >>> $article->published_at = Carbon\Carbon::now(); => Carbon\Carbon {#682 +"date": "2017-03-04 11:53:09.134952", +"timezone_type": 3, +"timezone": "UTC", } >>> $article; => App\Article {#673 title: "My First Article", body: "Lorem ipsum", published_at: Carbon\Carbon {#682 +"date": "2017-03-04 11:53:09.134952", +"timezone_type": 3, +"timezone": "UTC", }, }
- 作ったオブジェクトをセーブする
>>> App\Article::all()->toArray(); => [] >>> $article->save(); => true >>> App\Article::all()->toArray(); => [ [ "id" => 1, "title" => "My First Article", "body" => "Lorem ipsum", "created_at" => "2017-03-04 11:53:44", "updated_at" => "2017-03-04 11:53:44", "published_at" => "2017-03-04 11:53:09", ], ]
- MySQL上でも確認
$ mysql --user=homestead --password=secret homestead mysql> select * from articles\G; *************************** 1. row *************************** id: 1 title: My First Article body: Lorem ipsum created_at: 2017-03-04 11:53:44 updated_at: 2017-03-04 11:53:44 published_at: 2017-03-04 11:53:09 1 row in set (0.00 sec)
DBからモデルを読み込みアップデートしてみる
- tinker でDBから情報を1行読み込んで、更新後、セーブする
>>> $article = App\Article::all()->first(); => App\Article {#689 id: 1, title: "My First Article", body: "Lorem ipsum", created_at: "2017-03-04 11:53:44", updated_at: "2017-03-04 11:53:44", published_at: "2017-03-04 11:53:09", } >>> $article->title = 'My First Article Updated'; => "My First Article Updated" >>> $article->save(); => true
- DBを確認
mysql> select * from articles\G; *************************** 1. row *************************** id: 1 title: My First Article Updated body: Lorem ipsum created_at: 2017-03-04 11:53:44 updated_at: 2017-03-04 12:09:32 published_at: 2017-03-04 11:53:09 1 row in set (0.00 sec)
色々な方法でデータを検索する
>>> App\Article::find(1); => App\Article {#684 id: 1, title: "My First Article Updated", body: "Lorem ipsum", created_at: "2017-03-04 11:53:44", updated_at: "2017-03-04 12:09:32", published_at: "2017-03-04 11:53:09", } >>> App\Article::where('body', 'Lorem ipsum')->get(); => Illuminate\Database\Eloquent\Collection {#656 all: [ App\Article {#692 id: 1, title: "My First Article Updated", body: "Lorem ipsum", created_at: "2017-03-04 11:53:44", updated_at: "2017-03-04 12:09:32", published_at: "2017-03-04 11:53:09", }, ], } >>> App\Article::where('body', 'Lorem ipsum')->first(); => App\Article {#693 id: 1, title: "My First Article Updated", body: "Lorem ipsum", created_at: "2017-03-04 11:53:44", updated_at: "2017-03-04 12:09:32", published_at: "2017-03-04 11:53:09", }
createメソッドを使ってみる
createメソッドはまとめて値を入力できるので便利
App\Article::create()
でまとめて作ろうとするとMassAssignmentExceptionエラーが出る
>>> $article = App\Article::create(['title' => 'New Article', 'body' => 'Lorem ipsum', 'published_at' => Carbon\Carbon::now()]); Illuminate\Database\Eloquent\MassAssignmentException with message 'title'
app/Article.php
モデルを修正する
<?php namespace App; use Illuminate\Database\Eloquent\Model; class Article extends Model { protected $fillable = [ // 'title', 'body', 'published_at' ]; }
- ん?まだ、MassAssignmentExceptionエラーが出る
>>> $article = App\Article::create(['title' => 'New Article', 'body' => 'Lorem ipsum', 'published_at' => Carbon\Carbon::now()]); Illuminate\Database\Eloquent\MassAssignmentException with message 'title'
- tinkerを立ち上げなおしてリトライ。できた。
>>> $article = App\Article::create(['title' => 'New Article', 'body' => 'Lorem ipsum', 'published_at' => Carbon\Carbon::now()]); => App\Article {#670 title: "New Article", body: "Lorem ipsum", published_at: Carbon\Carbon {#661 +"date": "2017-03-04 12:17:28.029855", +"timezone_type": 3, +"timezone": "UTC", }, updated_at: "2017-03-04 12:17:28", created_at: "2017-03-04 12:17:28", id: 2, }