dimanche 26 juin 2016

Passing the form validator into controller's constructor is causing the controller to fail to execute properly

I'm still in the process of learning Laravel 5, and am following Laracasts. I've been following the lesson http://ift.tt/1mvRMh6, which I've found very helpful, however I've discovered some slight changes required to the codebase to accommodate the changes to Laravel since the video lesson was recorded. I wonder if my problem is due to some necessary feature or instruction or convention which has superseded the lesson.

When I click the "Profile" link, the page clearly refreshes, but I don't navigate to the Show Profile page.

This is my app/Http/routes.php

<?php

/*
|--------------------------------------------------------------------------
| Application Routes
|--------------------------------------------------------------------------
|
| Here is where you can register all of the routes for an application.
| It's a breeze. Simply tell Laravel the URIs it should respond to
| and give it the controller to call when that URI is requested.
|
*/

/**
 * All requests get passed as standard through 'web' middleware classes as definded in app/Http/Kernel.php
 */

/**
 * http://fidna.dev/public
 */
Route::get('/', function () {
    return view('welcome');
});

/**
 * http://ift.tt/290UyeD
 */
Route::get('/about', function () {
    $people = ['Taylor', 'Matt', 'Jeffrey'];
    return view('pages.about', array('people' => $people));
});

Route::get('/home' ,'IndexController@index');

Route::get('/cards', 'CardsController@index');
Route::get('/cards/{card}', 'CardsController@show');

Route::post('cards/{card}/notes', 'NotesController@store');

Route::get('/notes/{note}/edit', 'NotesController@edit');

/**
 * patch() is a synonym for save
 * The request type implies update
 */
Route::patch('notes/{note}', 'NotesController@update');

Route::auth();

Route::get('/home', 'HomeController@index');

/**
 * Profile
 * Watch out, because /{profile} could act as a catch-all
 * Therefore, leave this route at the bottom, allowing all the other routes to be processed first
 */
Route::resource('profile', 'ProfilesController', ['only' => ['show', 'edit', 'update']]);
Route::get('/{profile}', ['as' => 'profile', 'uses' => 'ProfilesController@show']);
/**
 * This is now implied by the routes command two lines above
 * 
Route::get('/{profile}/edit', ['as' => 'profile.edit', 'uses' => 'ProfilesController@edit']);
 * 
 */

My app/Custom/helpers.php (which is registered as autoloadable in composer.json) is as follows:

<?php
function link_to_profile($p_text = 'Profile')
{
    /**
     * The advantage with this first way is we are no longer hardcoding how we link to a profile
     * You'd only have to update the named route and update that if the path to it changed
     */
    return link_to_route('profile', $p_text, Auth::user()->name);
    return link_to('/' . Auth::user()->name, $p_text);
}

In order to navigate to the Show Profile page, I include link_to_profile() in the view.

The app/Http/Controllers/ProfilesController.php is as follows:

<?php
namespace App\Http\Controllers;

use App\User;
use Illuminate\Http\Request;
use \App\Http\Requests\ProfileForm;
use Input;

class ProfilesController extends Controller
{

    /**
     * Profile form requests validator class
     * 
     * @var Http\Requests\ProfileForm 
     */
    protected $_profileForm = null;

    public function __construct(ProfileForm $profileForm)
    {
        $this->_profileForm = $profileForm;
    }

    /**
     * Action to display the specified resource
     * 
     * @param string $username
     * 
     * @return Response
     */
    public function show($username)
    {
        try {
            $user = User::with('profile.country')->whereName($username)->firstOrFail();
            //dd($user->toArray());
        } catch (\Illuminate\Database\Eloquent\ModelNotFoundException $e) {
            return redirect('home');
        }

        return view('profiles.show')->withUser($user);
    }

    /**
     * Show the form for editing the specified resource
     * 
     * @param integer $id
     * 
     * @return Response
     */
    public function edit($username)
    {
        $user = User::with('profile.country')->whereName($username)->firstOrFail();
        return view('profiles.edit')->withUser($user);
    }

    /**
     * Edit the profile
     * 
     * @param string $username
     * 
     * @return Response
     */
    public function update($username)
    {
        $user = User::with('profile.country')->whereName($username)->firstOrFail();
        /**
         * Restricting input data to the values posted from the form
         */
        $input = Input::only('address1', 'address2', 'city', 'postcode');

        $this->_profileForm->validate($input);

        $user->profile->fill($input)->save();

        return view('profiles.show')->withUser($user);

    }

}

The app/Profile.php (model) is:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Profile extends Model
{

    /**
     * The only field that can be mass-assigned is the body
     * to avoid a Illuminate\Database\Eloquent\MassAssignmentException
     * 
     * @var array 
     */
    protected $fillable = ['address1', 'address2', 'city', 'postcode'];


    public function user()
    {
        return $this->belongsTo(User::class);
    }



    /**
     * Relating country to profile
     * 
     * @return type
     */
    public function country()
    {
        return $this->belongsTo('App\Country' ,'country_id', 'id');
    }

}

The config/app.php is:

<?php

return [

    /*
    |--------------------------------------------------------------------------
    | Application Environment
    |--------------------------------------------------------------------------
    |
    | This value determines the "environment" your application is currently
    | running in. This may determine how you prefer to configure various
    | services your application utilizes. Set this in your ".env" file.
    |
    */

    'env' => env('APP_ENV', 'production'),

    /*
    |--------------------------------------------------------------------------
    | Application Debug Mode
    |--------------------------------------------------------------------------
    |
    | When your application is in debug mode, detailed error messages with
    | stack traces will be shown on every error that occurs within your
    | application. If disabled, a simple generic error page is shown.
    |
    */

    'debug' => env('APP_DEBUG', false),

    /*
    |--------------------------------------------------------------------------
    | Application URL
    |--------------------------------------------------------------------------
    |
    | This URL is used by the console to properly generate URLs when using
    | the Artisan command line tool. You should set this to the root of
    | your application so that it is used when running Artisan tasks.
    |
    */

    'url' => env('APP_URL', 'http://localhost'),

    /*
    |--------------------------------------------------------------------------
    | Application Timezone
    |--------------------------------------------------------------------------
    |
    | Here you may specify the default timezone for your application, which
    | will be used by the PHP date and date-time functions. We have gone
    | ahead and set this to a sensible default for you out of the box.
    |
    */

    'timezone' => 'UTC',

    /*
    |--------------------------------------------------------------------------
    | Application Locale Configuration
    |--------------------------------------------------------------------------
    |
    | The application locale determines the default locale that will be used
    | by the translation service provider. You are free to set this value
    | to any of the locales which will be supported by the application.
    |
    */

    'locale' => 'en',

    /*
    |--------------------------------------------------------------------------
    | Application Fallback Locale
    |--------------------------------------------------------------------------
    |
    | The fallback locale determines the locale to use when the current one
    | is not available. You may change the value to correspond to any of
    | the language folders that are provided through your application.
    |
    */

    'fallback_locale' => 'en',

    /*
    |--------------------------------------------------------------------------
    | Encryption Key
    |--------------------------------------------------------------------------
    |
    | This key is used by the Illuminate encrypter service and should be set
    | to a random, 32 character string, otherwise these encrypted strings
    | will not be safe. Please do this before deploying an application!
    |
    */

    'key' => env('APP_KEY'),

    'cipher' => 'AES-256-CBC',

    /*
    |--------------------------------------------------------------------------
    | Logging Configuration
    |--------------------------------------------------------------------------
    |
    | Here you may configure the log settings for your application. Out of
    | the box, Laravel uses the Monolog PHP logging library. This gives
    | you a variety of powerful log handlers / formatters to utilize.
    |
    | Available Settings: "single", "daily", "syslog", "errorlog"
    |
    */

    'log' => env('APP_LOG', 'single'),

    /*
    |--------------------------------------------------------------------------
    | Autoloaded Service Providers
    |--------------------------------------------------------------------------
    |
    | The service providers listed here will be automatically loaded on the
    | request to your application. Feel free to add your own services to
    | this array to grant expanded functionality to your applications.
    |
    */

    'providers' => [

        /*
         * Laravel Framework Service Providers...
         */
        Illuminate\Auth\AuthServiceProvider::class,
        Illuminate\Broadcasting\BroadcastServiceProvider::class,
        Illuminate\Bus\BusServiceProvider::class,
        Illuminate\Cache\CacheServiceProvider::class,
        Illuminate\Foundation\Providers\ConsoleSupportServiceProvider::class,
        Illuminate\Cookie\CookieServiceProvider::class,
        Illuminate\Database\DatabaseServiceProvider::class,
        Illuminate\Encryption\EncryptionServiceProvider::class,
        Illuminate\Filesystem\FilesystemServiceProvider::class,
        Illuminate\Foundation\Providers\FoundationServiceProvider::class,
        Illuminate\Hashing\HashServiceProvider::class,
        Illuminate\Mail\MailServiceProvider::class,
        Illuminate\Pagination\PaginationServiceProvider::class,
        Illuminate\Pipeline\PipelineServiceProvider::class,
        Illuminate\Queue\QueueServiceProvider::class,
        Illuminate\Redis\RedisServiceProvider::class,
        Illuminate\Auth\Passwords\PasswordResetServiceProvider::class,
        Illuminate\Session\SessionServiceProvider::class,
        Illuminate\Translation\TranslationServiceProvider::class,
        Illuminate\Validation\ValidationServiceProvider::class,
        Illuminate\View\ViewServiceProvider::class,

        /*
         * Application Service Providers...
         */
        App\Providers\AppServiceProvider::class,
        App\Providers\AuthServiceProvider::class,
        App\Providers\EventServiceProvider::class,
        App\Providers\RouteServiceProvider::class,

        /**
         * After adding illuminate/html: ~5.0
         * @see http://ift.tt/28Ugd4m
         */
        Collective\Html\HtmlServiceProvider::class,

    ],

    /*
    |--------------------------------------------------------------------------
    | Class Aliases
    |--------------------------------------------------------------------------
    |
    | This array of class aliases will be registered when this application
    | is started. However, feel free to register as many as you wish as
    | the aliases are "lazy" loaded so they don't hinder performance.
    |
    */

    'aliases' => [

        'App' => Illuminate\Support\Facades\App::class,
        'Artisan' => Illuminate\Support\Facades\Artisan::class,
        'Auth' => Illuminate\Support\Facades\Auth::class,
        'Blade' => Illuminate\Support\Facades\Blade::class,
        'Cache' => Illuminate\Support\Facades\Cache::class,
        'Config' => Illuminate\Support\Facades\Config::class,
        'Cookie' => Illuminate\Support\Facades\Cookie::class,
        'Crypt' => Illuminate\Support\Facades\Crypt::class,
        'DB' => Illuminate\Support\Facades\DB::class,
        'Eloquent' => Illuminate\Database\Eloquent\Model::class,
        'Event' => Illuminate\Support\Facades\Event::class,
        'File' => Illuminate\Support\Facades\File::class,
        'Gate' => Illuminate\Support\Facades\Gate::class,
        'Hash' => Illuminate\Support\Facades\Hash::class,
        'Input' => Illuminate\Support\Facades\Input::class,
        'Lang' => Illuminate\Support\Facades\Lang::class,
        'Log' => Illuminate\Support\Facades\Log::class,
        'Mail' => Illuminate\Support\Facades\Mail::class,
        'Password' => Illuminate\Support\Facades\Password::class,
        'Queue' => Illuminate\Support\Facades\Queue::class,
        'Redirect' => Illuminate\Support\Facades\Redirect::class,
        'Redis' => Illuminate\Support\Facades\Redis::class,
        'Request' => Illuminate\Support\Facades\Request::class,
        'Response' => Illuminate\Support\Facades\Response::class,
        'Route' => Illuminate\Support\Facades\Route::class,
        'Schema' => Illuminate\Support\Facades\Schema::class,
        'Session' => Illuminate\Support\Facades\Session::class,
        'Storage' => Illuminate\Support\Facades\Storage::class,
        'URL' => Illuminate\Support\Facades\URL::class,
        'Validator' => Illuminate\Support\Facades\Validator::class,
        'View' => Illuminate\Support\Facades\View::class,

        /**
         * After adding illuminate/html: ~5.0
         * @see http://ift.tt/28Ugd4m
         */
        'Form' => 'Collective\Html\FormFacade',
        'Html' => 'Collective\Html\HtmlFacade',

    ],

];

The form request validation app/Http/Requests/ProfileForm.php is

<?php

namespace App\Http\Requests;

use App\Http\Requests\Request;

class ProfileForm extends Request
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'address1' => 'required|max:255',
            'address2' => 'max:255',
            'city' => 'required|max:255|string',
            'postcode' => 'required'
        ];
    }
}

The resources/views/profiles/show.blade.php is:

@extends('layouts/app')

@section('content')
<h1> | <small></small></h1>

    <div class="address">

        <p>
             <br>
             <br>
             <br>
             <br>
            

        </p>

    </div>

    @if ( Auth::user()->id == $user->id )
        
    @endif


@stop

and the resources/views/profiles/edit.blade.php is:

@extends('layouts/app')

@section('content')
    <h1>Edit Profile</h1>

    

        <!-- Update request -->
        
        <!-- Update request -->

        <!-- Necessary to circumvent TokenMismatchException which arises from recent improvements to Laravel-->
        <!-- This supplies a posted token value -->
        {!! csrf_field() !!}
        <!-- Necessary to circumvent TokenMismatchException -->

        <!-- Address Line 1 field -->
        <div class="form-group">
            
            
        </div>

        <!-- Address Line 2 field -->
        <div class="form-group">
            
            
        </div>

        <!-- City field -->
        <div class="form-group">
            
            
        </div>

        <!-- Postcode field -->
        <div class="form-group">
            
            
        </div>


        <!-- Submit button -->        
        <div class="form-group">
            
        </div>

            


    

@stop

The migration files are the vanilla out-of-the box Laravel 5 create_users_table.php and create_password_resets_table.php and a create_profiles_table.php which I created myself and is as follows:

<?php

use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;

/**
 * Migration for profiles table
 * 
 * <pre>
 * Created with artisan command:
 * 
 * php artisan make:migration:schema create_profiles_table --schema="address1:string, address2:string:nullable, <br>
 * city:string, postcode:string, country:integer, location:string:nullable"
 * </pre>
 */
class CreateProfilesTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('profiles', function (Blueprint $table) {
            $table->increments('id');
            $table->integer('user_id');
            $table->string('address1');
            $table->string('address2')->nullable();
            $table->string('city');
            $table->string('postcode');
            $table->integer('country');
            $table->string('location')->nullable();
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::drop('profiles');
    }
}

The MySql create code for the profiles table is:

CREATE TABLE `profiles` (
    `id` INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
    `user_id` INT(11) NOT NULL,
    `address1` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
    `address2` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
    `city` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
    `postcode` VARCHAR(255) NOT NULL COLLATE 'utf8_unicode_ci',
    `country_id` INT(11) NOT NULL,
    `location` VARCHAR(255) NULL DEFAULT NULL COLLATE 'utf8_unicode_ci',
    `created_at` TIMESTAMP NULL DEFAULT NULL,
    `updated_at` TIMESTAMP NULL DEFAULT NULL,
    PRIMARY KEY (`id`)
)
COLLATE='utf8_unicode_ci'
ENGINE=InnoDB
AUTO_INCREMENT=2
;

I can login and logout without problem. Everything happens with the profile management and I've isolated the problem as being ProfilesController::__construct(ProfileForm $profileForm). When I remove the argument from the constructor, the ProfilesController executes, however I have no form-request-based validation available any more.

I removed the argument to get me into the Show Profile page, then re-instated it once inside the page to see how it would affect clicking the "Edit Profile" link in the show.blade.php above. The site responds by failing with a "redirected you too many times" error.

I'm running WAMPServer with PHP version 5.5.12 and Apache version 2.4.9

Can anybody help?



via Chebli Mohamed

Aucun commentaire:

Enregistrer un commentaire