Laravel Forms and Validation

Create 4 views under a new folder called “posts”

create.blade.php
edit.blade.php
index.blade.php
show.blade.php

To our create.blade.php:

@extends('layouts.app')

@section('content')
<h1>Create Post</h1>
<form method="post" action="/posts">
    @csrf <!-- {{ csrf_field() }} -->
    <input type="text" name="title" placeholder="Enter title" />
    <input type="submit" name="submit" />
</form>

@endsection
You need to match the name of the column in posts.. is it named title? If so then the input name is correct. To save this to the posts method you just need to use the action /posts. @csrf is needed to create a token so form will work.

Find the posts routes methods by typing this:

php artisan route:list

You’ll see that the name store deals with the method POST. So find the store method in your posts controller.. this will be the function that will deal with the data when the form is submitted.

Now to see your form find the create (GET) function and add to this function:

    public function create()
    {
        return view('posts.create');
    }

The dot notation gets converted to slash in the browser.. where you can view it at base.com/posts/create.

Now get the store function to show the data submitted from the form:

    public function store(Request $request)
    {
        //return $request->all();
        //return $request->get('title');
        return $request->title;
    }

Update this to save to the database in different ways and redirect to index page like this:

    public function store(Request $request)
    {
        Post::create($request->all());
        return redirect('/posts');
    }
    public function store(Request $request)
    {
        $input = $request->all();
        $input['title'] = 'yo';
        Post::create($input);
        return redirect('/posts');
    }
    public function store(Request $request)
    {
        $post = new Post;
        $post->title = $request->title;
        $post->save();
        return redirect('/posts');
    }

Index controller should now show the index view and pass the post info:

    public function index()
    {
        $posts = Post::all();
        return view('posts.index', compact('posts'));
    }

In your index view update to show all the posts information:

@extends('layouts.app')

@section('content')

<ul>
    @foreach($posts as $post)
        <li>{{$post->title}}</li>
    @endforeach
</ul>

@endsection

Now if you submit the form you’ll be redirected to the index view which will show all the posts in the database including the last one added.

To see just one post, let’s add this to our show function in PostController:

    public function show($id)
    {
        $post = Post::findOrFail($id);
        return view('posts.show',compact('post'));
    }

In your show view write this:

@extends('layouts.app')

@section('content')

<h1>{{$post->title}}</h1>

@endsection

Now if you visit url /posts/1, you’ll see the first post. Other numbers will show other posts. It will have to match the id in the database of course.

Update your index view to link to the show view like so:

@extends('layouts.app')

@section('content')

<ul>
    @foreach($posts as $post)
        <li><a href="{{route('posts.show',$post->id)}}">{{$post->title}}</a></li>
    @endforeach
</ul>

@endsection

Now let’s create our Edit controller and view.

The view:

@extends('layouts.app')

@section('content')
<h1>Edit Post</h1>
<form method="post" action="/posts/{{$post->id}}">
    <input type="hidden" name="_method" value="PUT" />
    @csrf <!-- {{ csrf_field() }} -->
    <input type="text" name="title" placeholder="Enter title" value="{{$post->title}}" />
    <input type="submit" name="submit" />
</form>

@endsection
The action needs to send the post ID and a hidden field is needed called PUT which sends it to the update function in the controller.

The controller:

    public function edit($id)
    {
        $post = Post::findOrFail($id);
        return view('posts.edit',compact('post'));
    }

Now edit the update function in the controller:

    public function update(Request $request, $id)
    {
        $post = Post::findOrFail($id);
        $post->update($request->all());
        return redirect('/posts');
    }

Now update the show view to have links to edit form:

@extends('layouts.app')

@section('content')

<h1><a href="{{route('posts.edit',$post->id)}}">{{$post->title}}</a></h1>

@endsection

Lastly we are going to use a form to delete some of this data.

Find the destroy function in PostContoller and add this:

    public function destroy($id)
    {
        $post = Post::whereId($id)->delete();
        return redirect('/posts');
    }

Since everything already links nicely.. just edit you edit view like this:

@extends('layouts.app')

@section('content')
<h1>Edit Post</h1>
<form method="post" action="/posts/{{$post->id}}">
    <input type="hidden" name="_method" value="PUT" />
    @csrf <!-- {{ csrf_field() }} -->
    <input type="text" name="title" placeholder="Enter title" value="{{$post->title}}" />
    <input type="submit" name="submit" value="UPDATE" />
</form>

<form method="post" action="/posts/{{$post->id}}">
    <input type="hidden" name="_method" value="DELETE" />
    @csrf <!-- {{ csrf_field() }} -->
    <input type="submit" name="submit" value="DELETE" />
</form>

@endsection

Notice that your method is now DELETE and we still pass the post ID through the form action tag.

Eloquent Polymorphic Many to Many Relationship CRUD

Create 4 models, Post, Video, Tag, and Taggable

php artisan make:model Post -m   
php artisan make:model Video -m
php artisan make:model Tag -m
php artisan make:model Taggable -m

In our migrations

create_posts_table, create_videos_table and create_tags_table.php:

            $table->string('name');

create_taggables_table:

            $table->integer('tag_id');
            $table->integer('taggable_id');
            $table->string('taggable_type');

Now you can migrate it:

php artisan migrate

Update Models

Tag:

    protected $fillable = [
        'name',
    ];

Taggable:

    protected $fillable = [
        'name',

    ];
    public function taggable(){
        return $this->morphTo();
    }

Post and Video:

    protected $fillable = [
        'name',
    ];
    public function tags(){
        $this->morphToMany('App\Models\Tag', 'taggable');
    }

Create a few staff members and products in the database.

Different CRUD statements to add to routes:

Route::get('/create', function () {
    $post = Post::create(['name'=>'My first post']);
    $tag1 = Tag::find(1);
    $post->tags()->save($tag1);
    $video = Video::create(['name'=>'video.mov']);
    $tag2 = Tag::find(2);
    $video->tags()->save($tag2);
});

Route::get('/read', function () {
    $post = Post::findOrFail(4);
    foreach($post->tags as $tag){
        echo $tag;
    }
});

Route::get('/update', function () {
    $post = Post::findOrFail(4);
    foreach($post->tags as $tag){
        return $tag->whereName('php')->update(['name'=>'updated php']);
    }
});

Route::get('/update2', function () {
    $post = Post::findOrFail(4);
    $tag = Tag::find(4);
    $post->tags()->save($tag);
});

Route::get('/attach', function () {
    $post = Post::findOrFail(4);
    $tag = Tag::find(2);
    $post->tags()->attach($tag);
});

Route::get('/sync', function () {
    $post = Post::findOrFail(4);
    $tag = Tag::find(2);
    $post->tags()->sync([1,2]);
});

Route::get('/delete', function () {
    $post = Post::findOrFail(4);
    foreach($post->tags as $tag){
        $tag->whereId(2)->delete();
    }
});

Install AIMEOS Laravel project

You’ll need to create an empty database with username and password. Create a password without special characters. You’ll be inputting this as part of the install. You’ll also create the first user.

Password fields show as empty.. so can be difficult to know if you've pasted in the password correctly. 

Create a new site called myshop:

php composer create-project aimeos/aimeos myshop

This will set up a demo site automatically for you.. so will finish off with the correct migrations.

Eloquent Polymorphic Relationship CRUD

Create 3 models, Staff, Product, and Photo

php artisan make:model Staff -m 
php artisan make:model Product -m 
php artisan make:model Photo -m
Here we are creating a pivot table which follows the some rules: alphabetical order of the two table names in singular case

In our migrations

create_staff_table:

            $table->string('name');

create_products_table:

            $table->string('name');

create_photos_table:

            $table->string('path');
            $table->integer('imageable_id');
            $table->string('imageable_type');

Now you can migrate it:

php artisan migrate

Update Models

Photo:

    protected $fillable = [
        'path',

    ];
    public function imageable(){
        return $this->morphTo();
    }

Product and Staff:

    protected $fillable = [
        'name',
    ];
    public function photos(){
        $this->morphMany('App\Models\Photo','imageable');
    }

Create a few staff members and products in the database.

Different CRUD statements to add to routes:

Route::get('/create', function () {
    $staff = Staff::findOrFail(1);
    $staff->photos()->create(['path'=>'example.jpg']);
});

Route::get('/read', function () {
    $staff = Staff::findOrFail(1);
    foreach($staff->photos as $photo){
        echo $photo->path;
    }
});

Route::get('/update', function () {
    $staff = Staff::findOrFail(1);
    $photo = $staff->photos()->whereId(1)->first();
    $photo->path = "new.jpg";
    $photo->save();
});

Route::get('/delete', function () {
    $staff = Staff::findOrFail(1);
    $staff->photos()->wherePath('new.jpg')->delete();
});

//Create photo without imageable_type, so no attachment
Route::get('/assign', function () {
    $staff = Staff::findOrFail(1);
    $photo = Photo::findOrFail(3);
    $staff->photos()->save($photo);
});

Route::get('/unassign', function () {
    $staff = Staff::findOrFail(1);
    $staff->photos()->whereId(3)->update(['imageable_id'=>0,'imageable_type'=>'']);
});

Eloquent Many to Many Relationship CRUD

We will need a new model and migrations for role and role_user

php artisan make:model Role -m
php artisan make:migration create_user_role_table --create=role_user
Here we are creating a pivot table which follows the some rules: alphabetical order of the two table names in singular case

In our migrations add this to role_user:

            $table->integer('user_id')->unsigned()->nullable()->index();
            $table->integer('role_id')->unsigned()->nullable()->index();

And this to role:

            $table->string('name');

Now you can migrate it:

php artisan migrate

Update Models with fillable content for Role and a roles method for User.

Role:

    protected $fillable = [
        'name',
    ];

User:

    public function roles(){
        return $this->belongsToMany('App\Models\Role');
    }

Different CRUD statements to add to routes:

Route::get('/create', function () {
    $user = User::findOrFail(1);
    $role = new Role(['name'=>'Administrator']);
    $user->roles()->save($role);
});

Route::get('/read', function () {
    $user = User::findOrFail(1);
    foreach($user->roles as $role){
        echo $role->name;
    }
});

Route::get('/update', function () {
    $user = User::findOrFail(1);
    if($user->has('roles')){
        foreach($user->roles as $role){
            if($role->name=="Administrator"){
                $role->name="subscriber";
                $role->save();
            }
        }
    }
});

Route::get('/delete', function () {
    $user = User::findOrFail(1);
    foreach($user->roles as $role){
        $role->whereId(3)->delete();
    }
});

Route::get('/attach', function () {
    $user = User::findOrFail(1);
    $user->roles()->attach(4);
});

Route::get('/detach', function () {
    $user = User::findOrFail(1);
    $user->roles()->detach(4);
});

Route::get('/sync', function () {
    $user = User::findOrFail(1);
    $user->roles()->sync([4,5,6]);
});
Attach won't check the database to see if it's already been attached.. so with this method you'll need to check your database.

Sync is a bit better because it won't add duplicates. If you don't add previous roles in the database to the sync method, then it will delete those old roles.

Eloquent One to Many Relationship CRUD

Update Models with fillable content for Post and a posts method for User.

Post:

    protected $fillable = [
        'title',
        'body',
    ];

User:

    public function posts(){
        return $this->hasMany('App\Models\Post');
    }

Different CRUD statements to add to routes:

Route::get('/create', function () {
    $user = User::findOrFail(1);
    $user->posts()->save($post = new Post(['title'=>'My first post','body'=>'Love Laravel']));
});

Route::get('/read', function () {
    $user = User::findOrFail(1);
    $user->posts()->save($post = new Post(['title'=>'My first post','body'=>'Love Laravel']));
    foreach($user->posts as $post){
        echo $post->title;
    }
});

Route::get('/update', function () {
    $user = User::findOrFail(1);
    $user->posts()->whereId(1)->update(['title'=>'Update to title', 'body'=>'Loving Laravel']);
});

Route::get('/update2', function () {
    $user = User::findOrFail(1);
    $user->posts()->where('id','=',2)->update(['title'=>'Update to title 2', 'body'=>'Loving Laravel']);
});

Route::get('/delete', function () {
    $user = User::findOrFail(1);
    $user->posts()->whereId(1)->delete();
});

//Deletes all with user 1
Route::get('/delete2', function () {
    $user = User::findOrFail(1);
    $user->posts()->delete();
});

Eloquent One to One Relationship CRUD

Different CRUD statements to add to routes:

Route::get('/insert', function () {
    $user = User::findOrFail(1);
    $address = new Address(['name'=>'1234 Houston Ave NY NY 11218']);
    $user->address()->save($address);
});

Route::get('/update', function () {
    $address = Address::whereUserId(1)->first();
    $address->name = '1234 Update Ave Alaska';
    $address->save();
});

Route::get('/read', function () {
    $user = User::findOrFail(1);
    echo $user->address->name;
});

Route::get('/delete', function () {
    $user = User::findOrFail(1);
    $user->address()->delete();
});

Laravel Tinker Updating and deleting

We’ll go into the command line:

php artisan tinker

Now find a record:

$post = App\Models\Post::find(3);

Update like this:

$post->title = "hi"
$post->content = "hi"

In order to save to database write:

$post->save();

To soft delete you just need one line like so:

$post->delete()

To permanently delete this:

$post = App\Models\Post::onlyTrashed()

This will give you an Eloquent Builder response. If you write $post you’ll see it again

Now permanently delete:

$post->forceDelete()