How to validate in model in Laravel 5? - php

I am new to Laravel. Now I am starting to develop a project using Laravel 5. I have been using CodeIgniter before. I am having problem with validation class that is not compatible with what I want to do.
Normally we validate in Controller like this.
public function postCreate(Request $request)
{
$this->validate($request, [
'name' => 'required|max:30',
'mm_name' => 'required|max:50',
]);
echo "passed";
}
That is working find. But what I want to do is I want to move that validation logic to model. So I created a new folder called Models under app folder. Under the Models folder I created a class called ValidationHelper that extends the Model class.
This is my Validation helper class
<?php namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use DB;
class ValidationHelper extends Model{
function CreateCategory($request)
{
$this->validate($request, [
'name' => 'required|max:30',
'mm_name' => 'required|max:50',
]);
}
}
So now I am trying to import that class to my controller using constructor dependency injection. So now my controller is like this.
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use App\Models\ValidationHelper;
class CategoryController extends Controller
{
protected $validationHelper;
function __construct(ValidationHelper $v_helper)
{
$this->validationHelper = $v_helper;
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function categoryList()
{
//
return View('admin.Category.list');
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
//
return View('admin.Category.create');
}
}
So when I run my app and do validation, it is giving me this error. How can I do this in Laravel? How to separate my validation logic to model?

You can move the code in your model by registering model event(s) as given below:
// For example, User.php model
public static function boot()
{
parent::boot();
static::creating(function($user)
{
if (!$user->isValid()) return false;
}
}
If you put this boot method in your User.php model then whenever you'll create a new user, the validation will take place at first. For this, you have to create the isValid method in your model where you'll check the validation by yourself and return true/false depending on the validation result. If you return false, creation will be inturupted. This is just an idea but you may read more here about model events.

Related

My Laravel Controller function is not executed when adding custom request

I am new to Laravel. I decide to apply my understanding on Laravel to create a simple registration API.
This API will receive three data which are name, email, and password. These input data will be validated inside the Request file. But I found that, if I use the RegisterUserRequest $request inside my Controller file, the method inside controller file is not executed.
Here is my AuthController file:
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\Http\Requests\Auth\RegisterUserRequest;
use App\Models\User;
use Illuminate\Support\Facades\Validator;
use Illuminate\Http\Request;
class AuthController extends Controller
{
public function register(RegisterUserRequest $request)
{
return response()->json([
'message' => 'Here',
]);
}
}
Here is my RegisterUserRequest file
<?php
namespace App\Http\Requests\Auth;
use Illuminate\Foundation\Http\FormRequest;
class RegisterUserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return false;
}
/**
* Get the validation rules that apply to the request.
*
* #return array<string, mixed>
*/
public function rules()
{
return [
'name' => 'required',
'email' => 'required|email',
'password' => 'required',
];
}
}
Here is my route
Route::group(['namespace' => 'App\Http\Controllers\Api'], function () {
Route::post('register', [AuthController::class, 'register']);
});
Here is the output show on Postman:
Because suppose the output show on Postman would be:
{
"message": "Here"
}
But it don't. So i think that the register method inside the AuthController is not executed.
Is anyone know the problem? Really Appreciated!!!
Thank you.
As you defined, the user is not authorized to make this request:
public function authorize()
{
return false;
}
Set it to true.

How to mock Eloquent Model in Laravel 8 when calling a route in PHPUnit

I'm trying to mock a method in the Model so that I am able to test the controller api endpoint with different scenarios.
I am currently using Laravel 8 with PhpUnit and Mockery package.
In the route I am using Route model binding.
api.php
Route::get('/api/{project}', [ProjectController::class, 'show']);
ProjectController.php
class ProjectController extends Controller
{
public function show(Project $project)
{
$state = $project->getState();
return response()->json($state);
}
}
ProjectControllerTest.php
class ProjectControllerTest extends TestCase
{
/**
* #test
* #group ProjectController
*/
public function shouldReturn200ForValidProjectGuid()
{
$project = Project::factory()->create();
$mock = Mockery::mock(Project::class);
// I have also tried this, see error below
// $mock = Mockery::mock(Project::class)->makePartial();
$this->app->instance(Project::class, $mock);
$mock->shouldReceive('getState')->andReturn('New South Wales');
$response = $this->getJson("/api/{$project->guid}");
$response->assertStatus(200)
->assertJson([
'data' => 'New South Wales'
]);
}
}
I am currently getting this error
Received Mockery_0_App_Models_Project::resolveRouteBinding(), but no expectations were specified Exception caught at [/usr/src/app/vendor/mockery/mockery/library/Mockery/Loader/EvalLoader.php(34) : eval()'d code#924
I have tried other options like makePartial() instead, however it results in the following error as well
Received Mockery_0_App_Models_Project::__construct(), but no expectations were specified Exception caught at [/usr/src/app/vendor/mockery/mockery/library/Mockery/Loader/EvalLoader.php(34) : eval()'d code#924
Any help would be much appreciated, thank you
You can try the following. I have changed the controller response slightly to make it work with assertJson().
web.php
Route::get('/projects/{project}', [ProjectController::class, 'show']);
ProjectController
<?php
namespace App\Http\Controllers;
use App\Models\Project;
class ProjectController extends Controller
{
/**
* Display the specified resource.
*
* #param int $id
* #return \Illuminate\Http\Response
*/
public function show(Project $project)
{
return response()->json([
'state' => $project->getState()
]);
}
}
ProjectControllerTest
<?php
namespace Tests\Feature;
use App\Models\Project;
use Mockery;
use Tests\TestCase;
class ProjectControllerTest extends TestCase
{
/**
* A basic test example.
*
* #return void
*/
public function test_example()
{
$mock = Mockery::mock(Project::class)->makePartial();
$mock->shouldReceive('resolveRouteBinding')->andReturnSelf();
$mock->shouldReceive('getState')->andReturn('NSW');
$this->app->instance(Project::class, $mock);
$response = $this->get('/projects/1');
$response->assertStatus(200)
->assertJson([
'state' => 'NSW'
]);
}
}
You don't mock models, you are already using a Factory so you still use that to create "mock" data on your model.
$project = Project::factory()->create(['state' => 'New South Wales']);
Read more about factories and unit testing in Laravel. See the official documentation.

Laravel Virgin: Inject a Model In Controller as Dependency

In my inherited code in the Models there's some serious logic and I want to use the Laravel's Dependency Injection in order to load the models as Dependencies into the controller instead of Using the Laravel's provided Facades.
So here's a sample Controller:
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
class UserController extends Controller
{
/**
* Show the profile for the given user.
*
* #param int $id
* #return View
*/
public function show($id)
{
return view('user.profile', ['user' => User::findOrFail($id)]);
}
}
But Instead of using the Facade User I want to be able to load it as dependency into the controller:
namespace App\Http\Controllers;
use App\User;
use App\Http\Controllers\Controller;
user App\Models\User
class UserController extends Controller
{
/**
* #var User
*/
private $user=null;
public function __construct(User $user)
{
$this->user=$user;
}
/**
* Show the profile for the given user.
*
* #param int $id
* #return View
*/
public function show($id)
{
return view('user.profile', ['user' => $this->user->findOrFail($id)]);
}
}
The reason why I want to do that is because I come from Symfony Background where the Dependency Injection Pattern Is heavily Erdosed. Also Dependency Injection is the Unit Test's best buddy, so I want to be able to unitilize the Dependency Injection that I am familiar with.
So I wanted to know whether I can inject the models where the logic exists in the Controllers Instead of using the Facade Pattern provided by laravel.
When you register your route, you can use the model binding:
// routes/web.php
Route::get('users/{user}', 'UserController#show');
Then in your controller, you can change your method to:
public function show(User $user)
{
//
}
Where the $user will be the instance of App\User with the right id. For example, if the url is /users/1, the $user will contain the App\User with id 1.
For more information: https://laravel.com/docs/5.8/routing#route-model-binding

Get model instance in custom request Laravel

I have a models with custom rules of validation, In every model I have variable $rules:
public static $rules = [...];
https://medium.com/#konafets/a-better-place-for-your-validation-rules-in-laravel-f5e3f5b7cc
I want use these rules in custom request:
<?php
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Support\Facades\Auth;
class ModelRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return Auth::check() ? true : false;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return static::$rules;
}
}
I get error:
Access to undeclared static property: App\Http\Requests\ModelRequest::$rules
In controller:
public function store(ModelRequest $request)
{
...
}
This is globally. I need get instance of model, but how?
If you've put the $rules variable in your model you can't access it like this, because static refers to the class you are currently in.
Try this out:
Notice: I assume that your models are under the App name space
// In your model class
class YourModel extends Model{
const RULES=[];
}
//Then in your request class
class ModelRequest extends FormRequest
{
public function rules()
{
return App\YourModel::RULES;
}
}

php Laravel ~ Attribute [controller] does not exist

I am trying to set up an Route Controller in my Laravel project and I have set up the controller and also the route.
However, when I load the route in the web.php then it produces an error when I try to navigate to that page in the browser of Attribute [controller] does not exist
Here is the code..
<?php
namespace CMS\Http\Controllers\Auth;
use CMS\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
use AuthenticatesUsers {
logout as performLogout;
}
/**
* Where to redirect users after login.
*
*/
protected $redirectTo;
/**
* Create a new controller instance.
*
*/
public function __construct()
{
$this->redirectTo = route('backend.dashboard');
$this->middleware('guest')->except('logout');
}
public function logout(Request $request)
{
$this->performLogout($request);
return redirect()->route('auth.login');
}
}
And then in the web.php I have this...
Route::controller('auth', 'Auth\LoginController', [
'getLogin' => 'auth.login'
]);
The controller method is deprecated since Laravel 5.3. But now, you can use the resource method, which is meant for the same purpose as the controller method.
Like This:
Route::resource('auth', 'LoginController');
or
Route::get('/auth','LoginController');
Route::post('/auth','LoginController');

Categories