Uppgift: Lägg till och redigera innehåll med hjälp av formulär - osadi/yrgo GitHub Wiki

Vi behöver ha någon form av input för att lägga till innehåll till vår databas. Det gör vi med hjälp av formulär.

Lägg till

Steg 1 - Lägg till nya routes

Passa på att flytta ('/') till ('movies').

get('movies/create', 'MoviesController@create');
post('movies', 'MoviesController@store');

Se till så att movies/create hamnar ovanför movies/{slug}

Steg 2 - Lägg till paket för hjälp med formulärhantering

composer require illuminate/html

Redigera app.php och lägg till under providers:

'Illuminate\Html\HtmlServiceProvider',

och under alias:

'Form'      => 'Illuminate\Html\FormFacade',
'Html'      => 'Illuminate\Html\HtmlFacade',

Steg 3 - Skapa en ny vy för vår create

@extends('master')

@section('body')
    <h2>Lägg till film</h2>

    {!! Form::open(['url' => 'movies']) !!}
        <div class="form-group {{ $errors->has('title') ? 'has-error' : '' }}">
            {!! Form::label('title', 'Titel:') !!}
            {!! Form::text('title', null, ['class' => 'form-control']) !!}
        </div>

        <div class="form-group {{ $errors->has('slug') ? 'has-error' : '' }}">
            {!! Form::label('slug', 'Slug:') !!}
            {!! Form::text('slug', null, ['class' => 'form-control']) !!}
        </div>

        <div class="form-group">
            {!! Form::label('summary', 'Summary:') !!}
            {!! Form::textarea('summary', null, ['class' => 'form-control']) !!}
        </div>

        <div class="form-group">
            {!! Form::submit('Lägg till film', ['class' => 'btn btn-primary form-control'])  !!}
        </div>
    {!! Form::close() !!}

    @if($errors->any())
        <div class="alert alert-danger">
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </div>
    @endif
@stop

Steg 4 - skapa nya metoder på vår controller

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

public function store(Request $request)
{

    $this->validate($request,
        [
            'title' => 'required',
            'slug'  => 'required|unique:movies',
        ],
        [
            'title.required' => 'Titel får inte vara tom',
            'slug.required'  => 'Slug får inte vara tom',
            'slug.unique'    => 'Sluggen är redan tagen',
        ]
    );

    Movie::create($request->all());

    return redirect('movies');
}

Redigera

Nu är det dags att skapa ett formulär så att vi även kan redigera den data vi har lagt till.

Vi börjar igen med att definiera våra nya routes:

get('movies/{slug}/edit', 'MoviesController@edit');
patch('movies/{slug}', 'MoviesController@update');

Vi skapar sen upp vår nya vy för att visa datan vi vill redigera. Vi kallar den för edit.blade.php och lägger den i movies:

@extends('master')

@section('body')
    <h2>Redigera film: {{ $movie->title }}</h2>

    {!! Form::model($movie, ['method' => 'PATCH', 'action' => ['MoviesController@update', $movie->slug]]) !!}
    <div class="form-group {{ $errors->has('title') ? 'has-error' : '' }}">
        {!! Form::label('title', 'Titel:') !!}
        {!! Form::text('title', null, ['class' => 'form-control']) !!}
    </div>

    <div class="form-group {{ $errors->has('slug') ? 'has-error' : '' }}">
        {!! Form::label('slug', 'Slug:') !!}
        {!! Form::text('slug', null, ['class' => 'form-control']) !!}
    </div>

    <div class="form-group">
        {!! Form::label('summary', 'Summary:') !!}
        {!! Form::textarea('summary', null, ['class' => 'form-control']) !!}
    </div>

    <div class="form-group">
        {!! Form::submit('Uppdatera film', ['class' => 'btn btn-primary form-control'])  !!}
    </div>
    {!! Form::close() !!}

    @if($errors->any())
        <div class="alert alert-danger">
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </div>
    @endif
@stop

Och så lägger vi till en länk direkt under vår summary i index.blade.php

<p>{{ $movie->summary }}</p>
<a href="{{ action('MoviesController@edit', $movie->slug) }}" class="btn btn-success">Redigera</a>

Sist är det dags att lägga till metoderna på vår Controller. Vi behöver en för att visa formuläret för att redigera data, och en som är ansvarig för att spara förändringarna:

public function edit($slug)
{
    $movie = Movie::where('slug', '=', $slug)->firstOrFail();

    return view('movies.edit', ['movie' => $movie]);
}

public function update($slug, Request $request)
{
    $movie = Movie::where('slug', '=', $slug)->firstOrFail();

    $movie->update($request->all());

    return redirect('movies');
}

Om vi tittar på vår update()-metod, så ser vi att vi inte har någon validering på den. Vi kan givetvis göra som med formuläret och bara kopiera koden. Men, vi vill inte upprepa oss, och vi vill inte ha samma kod på två ställen. Så, vi skapar en Request-class för att hjälpa oss med det. Och när vi ändå gör lite refaktorering så fixar vi till formuläret också.

php artisan make:request MovieRequest
Request created successfully.

Sen redigerar vi den under app/Http/Requests/MovieRequest.php

public function authorize()
{
    return true;
}
/**
 * Get the validation rules that apply to the request.
 *
 * @return array
 */
public function rules()
{
    $rules = [
        'title' => 'required',
        'slug'  => 'required|unique:movies',
    ];

    if(Request::isMethod('patch')) {
        // Behöver inte vara unik om vi uppdaterar.
        $rules['slug'] = 'required';
    }

    return $rules;
}

public function messages()
{
    return [
        'title.required' => 'Titel får inte vara tom',
        'slug.required'  => 'Slug får inte vara tom',
        'slug.unique'    => 'Vald slug är är redan tagen',
    ];
}

Sen tar vi bort $this->validate(...) ur vår store()-metod och ändrar Request till MovieRequest i parametern till vår store()-metod:

public function store(MovieRequest $request)
{
    Movie::create($request->all());

    return redirect('movies');
}

Glöm inte att lägga till use i toppen på vår Controller:

use App\Http\Requests\MovieRequest;

Sen använder vi oss av samma validering i vår update()-metod, så vi ändrar Request till MovieRequest även där. Nu valideras de med hjälp av samma klass.

Dags att få formuläret DRY.

Skapa en ny template i errors: form_error.blade.php

    @if($errors->any())
        <div class="alert alert-danger">
            @foreach ($errors->all() as $error)
                <li>{{ $error }}</li>
            @endforeach
        </div>
    @endif

Skapa en ny template i movies: _form.blade.php

<div class="form-group {{ $errors->has('title') ? 'has-error' : '' }}">
    {!! Form::label('title', 'Titel:') !!}
    {!! Form::text('title', null, ['class' => 'form-control']) !!}
</div>

<div class="form-group {{ $errors->has('slug') ? 'has-error' : '' }}">
    {!! Form::label('slug', 'Slug:') !!}
    {!! Form::text('slug', null, ['class' => 'form-control']) !!}
</div>

<div class="form-group">
    {!! Form::label('summary', 'Summary:') !!}
    {!! Form::textarea('summary', null, ['class' => 'form-control']) !!}
</div>

<div class="form-group">
    {!! Form::submit($submitButtonText, ['class' => 'btn btn-primary form-control'])  !!}
</div>

@include('errors.form_error')

Sen kan vi inkludera vår nya formulär-template i både create och edit:

@extends('master')

@section('body')
    <h2>Lägg till film</h2>
    {!! Form::open(['url' => 'movies']) !!}
        @include('movies._form', ['submitButtonText' => 'Spara ny film'])
    {!! Form::close() !!}
@stop
@extends('master')

@section('body')
    <h2>Redigera film: {{ $movie->title }}</h2>
    {!! Form::model($movie, ['method' => 'PATCH', 'action' => ['MoviesController@update', $movie->slug]]) !!}
        @include('movies._form', ['submitButtonText' => 'Uppdatera film'])
    {!! Form::close() !!}
@stop

Radera

Nu har vi bara kvar att kunna radera filmer. Vi börjar på samma sätt och lägger till våra routes för ändamålet.

delete('movies/{slug}', 'MoviesController@destroy');

Vi behöver ingen vy för detta utan vi går direkt på vår Controller.

public function destroy($slug)
{
    $movie = Movie::where('slug', '=', $slug)->firstOrFail();
    $movie->delete();

    return redirect('movies');
}

Och sist lägger vi till en länk så att vi faktiskt kan radera. index.blade.php

<p>{{ $movie->summary }}</p>
{!! Form::open(['method' => 'DELETE', 'action' => ['MoviesController@destroy', $movie->slug]]) !!}
    <div class="btn-group">
        {!! Form::submit('Radera', ['class' => 'btn btn-danger']) !!}
        <a href={{ action('MoviesController@edit', $movie->slug) }} class="btn btn-success">Redigera</a>
    </div>
{!! Form::close() !!}
⚠️ **GitHub.com Fallback** ⚠️