Laravel8 瞬間MEMO

スポンサーリンク

このビデオがターミナルのカスタマイズからAuthまで網羅してえらく長かった(6時間!)けどよかったです。途中何度も寝落ちしながらなんとか最後まで見ました。

動画観ながらメモったものをそのままずらっと残しておきます。

composer create-project --prefer-dist laravel/laravel firstproject

---
iTerm2

---
php artisan serve


Ctrl+Z

php artisan serve --port=8081

---
sudo nano /etc/hosts

127.0.0.1 firstproject.test


---
Visual Studio Code
Atom
PHPStorm
Sublime Text

---
Visual Studio Code
extensions
Laravel Artisan
Laravel Blade Snippets
Laravel Blade Spacer
Laravel goto view
Laravel Snippets
Laravel Extra Intellisense
Live Sass Compiler
Beautify css/sass/scss/less
PHP Intellisense
Getter and Setter Generator (created by Augustin
Bracket Pair Colorizer
Emmet Live
GitHub (created by KnisterPeter
Javascript (ES6) code snippets
VScode Great Icons

---
PHPstorm (58:55)
extensions
Laravelのみ?

---
VSCode
Shift + Cmd + P
「file icon theme」
VSCode Great Icons

---
Http/Controllers
Models
Resources/css
Resources/js
Resources/views
database/
routes/
storage/
---
.env

routes/web.php
Route::get('/', function () {
    return view('welcome');
});

.env
CREATOR_NAME=Shiraishi

routes/web.php
Route::get('/', function () {
    return env('CREATOR_NAME');
});


--
composer

require
">= 4 < 5"

require-dev
でも動くけど、クラッシュするほど必要なわけではない開発中の試しみたいなもの


composer.lockは、実際にインストールされた状態
composer.lockを削除して、再度、composer installを実行すると更新されて、またlockファイルが作成される


---
Packagist
composerに記述することなく、記述してインストールしたかのように追加できる

packagist.orgにて
mollieを検索
composer require mollie/mollie-api-php
を実行するだけ

---
composer show --tree

composer dump-autoload

---
Basic Route

routes/web.php
Route::get('/', function () {
    return view('welcome');
});
↓
resources/views/welcome.blade.php

//JSON
Route::get('/', function () {
    return response()->json([
        'hoge' => 'aaa',
        'fuga' => 'bbb'
    ]);
});

//function
Route::get('/users', function () {
    return redirect('/');
});

----
php artisan list

php artisan make:controller ProductsController
php artisan make:controller ProductsController --force (強制上書き)

web.php
use App\Http\Controllers\ProductsController;
Route::get('/products', [ProductsController::class, 'index']);
or
Route::get('/products', 'App\Http\Controllers\ProductsController@index']);

before Laravel 8
Route::get('/products', 'ProductsController@index']); → error

ProductsController.php
class ProductsController extend Controller
{
    public function index(){
        return view('products.index');
    }
}

(view)
resources/views/products/index.blade.php
doc+TAPキー(VSCode)

-----
Passing Data to View

ProductsController.php
class ProductsController extend Controller
{
    public function index(){
        $title = 'Hello Laravel 8';
        $desc = 'hoge hoge hoge hoge'
        //return view('products.index', compact('title', 'desc'));
        return view('products.index')->with('title', $title);
    }
}

index.blade.php
{{ $title }} {{ $desc }}

-
ProductsController.php
class ProductsController extend Controller
{
    public function index(){
        $title = 'Hello Laravel 8';
        $desc = 'hoge hoge hoge hoge'

        $data = [
            'productOne' => 'iPhone',
            'productTwo' => 'Android'
        ]
        return view('products.index')->with('data', $data);
        or
        return view('products.index', [
            'data' => $data
        ]);
    }
}

index.blade.php
@foreach($data as $item)
    <p>{{ $item }}</p>
@endforeach

----
web.php
use App\Http\Controllers\ProductsController;
Route::get('/products/{id}', [ProductsController::class, 'show']);

public function show($id){
    return $id;
}

--
Route::get('/products/{name}', [ProductsController::class, 'show']);

public function show($name){
    $data = [
        'iphone' => 'iPhone',
        'samsung' => 'Samsung'
    ];
    return view('products.index', [
        'products' => $data[$name] ?? 'Product '.$name.' does not exist.';
    ]);
}

index.blade.php
<p>{{ $products }}</p>

--
Pattern
Route::get('/products/{id}', [ProductsController::class, 'show'])->where('id', '[0-9]+');

Route::get('/products/{name}', [ProductsController::class, 'show'])->where('name', '[a-zA-Z]+');

Route::get('/products/{name}{id}', [ProductsController::class, 'show'])->where([
    'name' => '[a-z]+', 'id' => '[0-9]+'
]);

--
ルート定義に名前をつける?

Route::get('/products/{id}', [ProductsController::class, 'index'])->name('products');

<a href="{{ route('products') }}">Product</a>

----
VIEW

views
    layout
        header.blade.php
        app.blade.php
        footer.blade.php

--app.blade.php
<header>
    @include('layouts.header')
</header>

@yield('content')

<footer>
    @include('layouts.footer')
</footer>


--index.blade.php
@extends('layouts.app')
@section('content')
indexの内容
@endsection

--about.blade.php
@extends('layouts.app')
@section('content')
aboutの内容
@endsection


--header.blade.php
<a href="/" class='{{ request()-is('/') ? 'active' : '' }}'>Home</a>
<a href="about" class='{{ request()-is('about/*') ? 'active' : '' }}'>About</a>

----
Asset 

public/images
{{ print_r(URL()) }}
<img src="{{ URL('images/hoge.jpg') }}" >

--
Storage
php artisan storage:link
rootにstorageへのシンボリックリンクを作成

<img src="{{ URL('storage/hoge.jpg') }}" >
<img src="{{ asset('storage/hoge.jpg') }}" >


------
VIEW(blade.php)

@[structure]
 {{ $name }}
@[endstructure]

@if()
@elseif()
@endif

@unless(empty($name))
@endunless

@if(!empty($name))
@endif

@isset($name)
@endisset

@swith (swithと入力してTAP)

For loop
Foreach loop
For else loop
While loop

@for ($i = 0; $i < 10; $i++ )
    <h2>The number is {{ $i }}</h2>
@endfor

@foreach ($names as $name)
    <h2>The name is {{ $name }}</h2>
@endforeach

@forelse ($names as $name)
    <h2>The name is {{ $name }}</h2>
@empty
    <h2>There are no names!</h2>
@endforelse

{{ $i = 0 }}
@while ($i < 10)
    <h2>{{ $i }}</h2>
    {{ $i++ }}
@endwhile

-----
Compiling Assets (2:50:00)
webpack.mix.js

sassに書き換え
mix.js('resources/js/app.js', 'public/js')
    .sass('resources/scss/app.scss', 'public/css', [
        //
    ]);

npm install(必要なものがインストールされる)
npm run dev
npm run dev(もう一度)

(その後の自動化は失敗。PHPStormのFile Watcherがエラー・・)

----
Laravel Frontend Preset 2:59:15
php artisan present react
php artisan present bootstrap
「Laravel frontend presets」で検索

Tailwindcss
A Tailwind CSS frontend preset for the Laravel Framework - GitHub - laravel-frontend-presets/tailwindcss: A Tailwind CSS frontend preset for the Laravel Framewo...
composer require laravel-frontend-presets/tailwindcss --dev ---- #27 Databases & MIgrations php artisan make:migration create_posts_table php artisan make:model Post -m Created Migration: 2021_10_28_121339_create_posts_table.php public function up() { Schema::create('posts', function (Blueprint $table) { $table->increments('id'); $table->string('title'); $table->mediumText('body'); $table->timestamps(); }); } php artisan migrate mysql -u root -p {password} mysql> show databases; mysql> use _databasename; mysql> show tables; mysql> desc users; php artisan migrate:reset php artisan migrate:refresh php artisan migrate:fresh php artisan migrate:rollback php artisan migrate:status -- Factory php artisan make:factory PostFactory use Illuminate\Support\Str; public function definition() { return [ 'title' => $this->faker->title, 'body' => $this->faker->paragraph, 'created_at' => now() ]; } php artisan tinker Psy Shell v0.10.9 >>> \App\Models\Post::factory()->count(2)->create(); class ProductsController extends Controller { public function index(){ $posts = DB::select('select * from posts'); dd($posts); } } ----- Query Builder (3:23:23) $posts = DB::select('select * from posts WHERE id = ?', [7]); $posts = DB::select('select * from posts WHERE id = :id', ['id' => 7]); $posts = DB::table('posts') ->where('id', $id) ->get(); $posts = DB::table('posts') ->select('body') ->get(); $posts = DB::table('posts') ->where('created_at', '>', now()->subDay()) ->get(); $posts = DB::table('posts') ->where('created_at', '>', now()->subDay()) ->orWhere('title', 'Prof') ->get(); $posts = DB::table('posts') ->whereBetween('id', [7, 9]) ->get(); $posts = DB::table('posts') ->whereNotNull('title') ->get(); $posts = DB::table('posts') ->whereRaw('title') ->get(); $posts = DB::table('posts') ->select('title') ->distinct() ->get(); $posts = DB::table('posts') ->orderBy('title', 'asc') ->get(); $posts = DB::table('posts') ->latest() ->get(); $posts = DB::table('posts') ->oldest() ->get(); $posts = DB::table('posts') ->inRandomOrder() ->get(); $posts = DB::table('posts') ->orderBy('created_at', 'desc') ->first(); $posts = DB::table('posts') ->orderBy('created_at', 'desc') ->first(); $id = 7; $posts = DB::table('posts') ->find($id); $posts = DB::table('posts') ->where('id', $id); ->count(); $posts = DB::table('posts') ->count(); $posts = DB::table('posts') ->min('id'); $posts = DB::table('posts') ->max('id'); $posts = DB::table('posts') ->sum('id'); $posts = DB::table('posts') ->avg('id'); $posts = DB::table('posts') ->insert([ 'title' => 'New Post', 'body' => 'New Body' ]); $posts = DB::table('posts') ->where('id', '=', 15 ) ->update([ 'title' => 'Update Post', 'body' => 'Updated Body' ]); $posts = DB::table('posts') ->where('id', '=', 15 ) ->delete(); ------- #30 Eloquent (3:40:35) 3:59:42 ----- #32 Relations One To Many php artisan make:model Car -m -- CreateCarsTable public function up() { Schema::create('cars', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->integer('founded'); $table->longText('description'); $table->timestamps(); }); Schema::create('car_models', function (Blueprint $table) { (CreateCarTableで同時に作ってる例 $table->increments('id'); $table->unsignedInteger('car_id'); $table->string('model_name'); $table->timestamps(); $table->foreign('car_id') ->references('id') ->on('cars') ->onDelete('cascade'); }); } php artisan make:model CarModel -m (CarModel で car_modelsテーブル) 上記CreateCarTableで作ってる場合 php artisan make:model CarModel php artisan make:model Engine -m -- CreateEnginesTable public function up() { Schema::create('engines', function (Blueprint $table) { $table->increments('id'); $table->unsignedInteger('model_id'); $table->string('engine_name'); $table->timestamps(); $table->foreign('model_id') ->references('id') ->on('car_models') ->onDelete('cascade'); }); } mysql -u root -p {password} mysql> use _databasename; mysql> show tables; mysql> desc users; --モデルに関係性を定義 class Car extends Model { use HasFactory; protected $table = 'cars'; protected $primaryKey = 'id'; protected $fillable = ['name', 'founded', 'description']; public function carModels() { return $this->hasMany(CarModel::class); } } carModels() (キャメルケースで) class CarModel extends Model { use HasFactory; protected $table = 'car_models'; protected $primaryKey = 'id'; public function car(){ return $this->belongsTo(Car::class); } } show.blade.php @forelse ($car->carModels as $model) <li> {{ $model['model_name'] }} </li> @empty <p> No models found </p> @endforelse #33 HasMany & HasSome Has One(4:59:23) Schema::create('car_production_dates', function (Blueprint $table) { $table->id('id'); $table->unsignedInteger('model_id'); date('created_at'); $table->foreign('model_id') ->references('id') ->on('car_models') ->onDelete('cascade'); }); public function engines() { return $this->hasManyThrough() { Engine::class, CarModel::class, 'car_id', //Foreign key on CarModel table 'model_id' //Foreign key on Engine table } } Public funtion productionDate() { return $this-hasOneThrough( CarProductionDate::class, CarModel::class, 'car_id', 'model_id' ) } <td> {{ date('d-m-Y', strtotime($car->productionDate->created_at)) }} </td> Many To Many(5:04:57) PIVOT TABLE(中間テーブル) Table: cars Pivot Table: car_product car_id : product_id Table: products php artisan make:model Product -m (5:06:49) Schema::create('products', function (Blueprint $table) { $table->increments('id'); $table->string('name'); $table->timestamps(); }); php artisan make:model CarProduct -m (5:07:43) Schema::create('car_products', function (Blueprint $table) { $table->integer('car_id')->unsigned(); $table->integer('product_id')->unsigned(); $table->foreign('car_id') ->references('id') ->on('cars') ->onDelete('cascade'); $table->foreign('product_id') ->references('id') ->on('products') ->onDelete('cascade'); }); php artisan migrate class Product extends Model { use HasFactory; public function cars() { return $this->belongsToMany(Car::class) ] } CarController.php public function show($id) { $car = Car::find($id) $product = Product::find($id); return view('cars.show')->with('car', $car); } ---- #35 Accessing the Request (5:15:04) CarController.php $request->validate([ 'name' => 'required|unique:cars', 'founded' => 'required|integer|min:0|max:2021', 'description' = 'required' ]) create.blade.php @if ($errors->any()) <div> @foreach ($errors->all() as $error) <li class="text-red-500 list-none"> {{ $error }} </li> @endforeach </div> @endif --- カスタムルール php artisan make:rule Uppercase public function passes($attribute, $value) { return strtoupper($value) === $value; } CarController.php use App\Rules\Uppercase; $request->validate([ 'name' => new Uppercase, 'founded' => 'required|integer|min:0|max:2021', 'description' = 'required' ]) $request->validate([ 'name' => ['required', 'unique:cars', new Uppercase], ←配列で指定? 'founded' => 'required|integer|min:0|max:2021', 'description' = 'required' ]) ----- #37 FORM REQUESTS (5:36:15) カスタムリクエスト php artisan make:request MyRequest App\Http\Requests\MyRequest; public function authorize(){ return true; } public function rules() { return [ 'name' => 'required|unique:cars', 'founded' => 'required|integer|min:0|max:2021', 'description' = 'required' ]; } CarController.php use App\Http\Requests\MyRequest; public function store(MyRequest $request) { $request->validated(); public function update(MyRequest $request) { $request->validated(); ------ #38 Image Upload (5:41:06) テーブルにフィールドを追加 php artisan make:migration add_image_to_cars_table up() $table->string('image_path'); down() $table->dropColumn('image_path'); dd($request->all()); イメージのバリデーション $request->validate([ 'image' => 'required|mimes:jpg,png,jpeg|max:5048' ]); $test = $request->file('image')->guessExtension(); dd($test); guessExtension() getMimeType() store() asStore() storePublicly() move() getClientOriginalName() getClientMimeType() guessClientExtension() getSize() getError() → エラーなし0 isValid() → 正常true $newImageName = time().'-'.request->name.'.'.$request->image->extension(); dd(newImageName); > 1611790072-Mercedes.jpg $test = $request->image->move(public_path('images'), $newImageName); <img src="{{ asset('images/'.$car->image_path) }}" > ------- #39 ARTISAN COMMANDS (6:00:15) php artisan list php artisan clear-compiled php artisan down php artisan up php artisan env php artisan help php artisan --version php artisan --env php artisan optimize php artisan cache:clear php artisan auth:clear-resets(リメンバートークンをクリア) php artisan key:generate(APP_KEYをリフレッシュ) php artisan session:table php artisan view:clear ----- #40 Auth composer require laravel-frontend-presets/tailwindcss --dev php artisan ui tailwindcss php artisan ui tailwindcss --auth npm install && npm run dev php artisan route:clear php artisan optimize php artisan route:list index.blade.php {{ dd(Auth:user()) }} @if (isset(Auth:user()->id) && Auth:user()->id == $car->user_id) <form>edit delete</form> @endif FOR non-logged in users public function __contruct() { $this->middleware('auth', ['except' => ['index', 'show']) }