Call to a member function create() on null - php

I know this is the same quetion title like others, but i cant find the right answer for me. Here is my problem.
I am trying to insert data to the other table after users data inserted. But what i got is Call to a member function create() on null.
Here is my code of AuthController.php
protected function create(array $data)
{
$user = User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
$user->usersbasics()->create([
'user_id' => $user->id,
]);
return $user;
}
Here is my User model
public function usersbasics()
{
$this->hasOne('App\UsersBasics');
}
Here is my UsersBasics model:
public function user()
{
$this->belongsTo('App\User');
}
I tried var_dumb($user->usersbasics()) and the result is NULL.
What is whrong with my code? because i use the same for my other work, and its fine. Please someone explain me and give me a solution. Please..
thank you,

This is a late answer, but I ran into the same problem.
You don't have the return keyword on both your relationships.
public function user()
{
return $this->belongsTo('App\User');
}
and
public function usersbasics()
{
return $this->hasOne('App\UsersBasics');
}
This fixxed it for me.

You need to set the parameters fillable in your User model.
class User extends Model
{
protected $fillable = ['name', 'email', 'password'];
}

Your controller method is protected instead of public.
If you look at the existing AuthController, we have function you mentioned:
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
}
This method is then called with postRegister (public, so it can be called from routes.php), where we pass only the input from Request as the parameter.
public function postRegister(Request $request)
{
$validator = $this->validator($request->all());
if ($validator->fails()) {
$this->throwValidationException(
$request, $validator
);
}
$user = $this->create($request->all());
return redirect($this->redirectPath());
}
I assume you tried to call the create() method directly from controller, which doesn't work because it's protected and can only be called from within the class itself. If you really want to make create() method work without postRegister, you would do something like this:
public function create(Request $request)
{
$user = User::create([
'name' => $request->input('name'),
'email' => $request->input('email'),
'password' => bcrypt($request->input('password')),
]);
$user->usersbasics()->create([
'user_id' => $user->id,
]);
return $user;
}
And then call this in your routes.php
Route::post('urlToPostMethod', 'Auth\AuthController#create');
The other, generally nicer way would be to call this instead
Route::post('urlToPostMethod', 'Auth\AuthController#postRegister');

Related

Laravel8 tdd: session is missing expected key errors

I just want to test an easy input field but I get this error!
/** #test */
public function email_must_be_a_valid_email()
{
$response = $this->post('/api/contacts', array_merge($this->data(), ['email' => 'NOT AN EMAIL']));
$response->assertSessionHasErrors('email');
}
private function data()
{
return [
'name' => 'Test Name',
'email' => 'test#hotmail.com',
'birthday' => '05/14/1988',
'company' => 'ABC String'
];
}
Thses are the Controller and the request rule.
I hope u can help me with it.
class StoreController extends Controller
{
public function store(ContactsRequest $request)
{
$data = $request->validated();
Contact::create($data);
}
}
public function rules()
{
return [
'name' => 'required',
'email' => 'required|email',
'birthday' => 'required',
'company' => 'required',
];
}
I hope u can help me with it.
If you are using an api route then you should use
$response->assertJsonValidationErrors(['email']);
or
$response->assertInvalid(['email']);
which works for both JSON and session errors.
https://laravel.com/docs/8.x/http-tests#assert-invalid
Thanks for your tips. I've solved the problem! But this kind of error message does not help at all to find the solution quickly.
The solution is that I need to be logged in to create contact and then validate form data. But the error message says something completely different!
protected $user;
protected function setUp(): void
{
parent::setUp();
$this->user = User::factory()->create();
$this->user->createToken(Str::random(30))->plainTextToken;
}
/** #test */
public function email_must_be_a_valid_email()
{
$this->actingAs($this->user);
$response = $this->post('/api/contacts', array_merge($this->data(), ['email' => 'NOT AN EMAIL']));
$response->assertSessionHasErrors('email');
}

Laravel: error "Undefined variable" when i validate form request with using custom Request class

In Laravel (5.8) controller, i try to make update() function for my User model.
I validate data with using my own class UpdateRequest. When i put variable $user in this class, i have error Undefined variable: user.
<?php
namespace App\Http\Requests\Users;
use Illuminate\Foundation\Http\FormRequest;
use Illuminate\Validation\Rule;
class UpdateRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'name' => 'required|string|alpha_dash|max:255|min:6',
'email' => ['required',
'string',
'email',
'max:255',
Rule::unique('users')->ignore($user->id)],
];
}
}
public function update(User $user, UpdateRequest $request)
{
$user->update($request->only(['name', 'email']));
return redirect()->route('users.index');
}
But if I use validate function in controller update() method, all works fine.
public function update(User $user, Request $request)
{
$this->validate($request, [
'name' => 'required|string|alpha_dash|max:255|min:6',
'email' => 'required|string|email|max:255|unique:users,id,' . $user->id,
]);
$user->update($request->only(['name', 'email']));
return redirect()->route('users.index');
}
In your custom request class, you don't have the $user initialized and you try to use it, while in the controller method the $user is passed as a parameter.
Note $this->user in the Request returns the currently authenticated user, so make sure that you always want to use his ID, instead of an ID of the passed in user, hence the reason I am using request('user') to get the user id from the URL.
So try this instead:
public function rules()
{
return [
'name' => 'required|string|alpha_dash|max:255|min:6',
'email' => ['required',
'string',
'email',
'max:255',
Rule::unique('users')->ignore(request('user'))],
];
}
You need to change $user->id to $this->user->id and it should work properly. Check below:
return [
'name' => 'required|string|alpha_dash|max:255|min:6',
'email' => ['required',
'string',
'email',
'max:255',
Rule::unique('users')->ignore($this->user->id)],
];
Hope it helps you!!
User class instance is missing in UpdateRequest class constructor or you can try with $this->user->id. It may help you.

How to use laravel RegisterController without standard auth (php artisan make:Auth)

I thought that if($this->validator($request->all())) this would return true or false, but it returns a object every time returns true
use RegistersUsers;
protected $redirectTo = '/home';
public function __construct()
{
$this->middleware('guest');
}
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|string|max:255',
'surname' => 'required|string|max:255',
'age' => 'required|integer|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6|confirmed',
]);
}
protected function create(array $data)
{
return User::create([
'name' => $data['name'],
'surname' => $data['surname'],
'age' => $data['age'],
'email' => $data['email'],
'password' => bcrypt($data['password']),
]);
}
public function register(Request $request){
if($this->validator($request->all())){
//create user
// function after registration
var_dump('success');
}else{
//redirect to ...
var_dump('fail');
}
}
You have a couple of options here:
Use validate()
public function register(Request $request)
{
$this->validator($request->all())->validate();
dd('success'); //This won't get called if validation doesn't pass
}
Using the above method, Laravel will handle the response for you.
or if you want to have more control over the how you handle the validation then you can use the passes() method instead:
public function register(Request $request)
{
if ($this->validator($request->all())->passes()) {
dd('success');
} else {
dd('fail');
}
}
Manually creating validators

Check an user is exist or not in RegisterController Laravel and redirect back to registration page

How to redirect back in laravel default authentication system.For example in Auth\RegisterController
protected function validator(array $data)
{
return Validator::make($data, [
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'contact_no' => 'required|unique:users',
'password' => 'required|string|min:6|confirmed',
]);
}
protected function create(array $data)
{
$email = $data['email'];
$token = $data['token'];
$checkUser = Invitation::where('email', $email)
->where('token', $token)
->first();
if (!$checkUser) {
return redirect()->back()->with('error', 'Credentials not matched !');
}
return User::create([
'name' => $data['name'],
'email' => $data['email'],
'contact_no' => $data['contact_no'],
'password' => bcrypt($data['password']),
]);
before creating an user i want to check the user is exist or not with a token came from another table.I checkuser with a query and if i use this before the create method ,
if (!$checkUser) {
return redirect()->back()->with('error', 'Credentials not matched !');
}
it throws an error
Type error: Argument 1 passed to Illuminate\Auth\SessionGuard::login() must be an instance of Illuminate\Contracts\Auth\Authenticatable, instance of Illuminate\Http\RedirectResponse given,
problem occurred with the redirect inside the if condition.If i dd('error') inside if it shows error when check user return null
Use isset to check if a user exists.
if (!isset($checkUser)) {
return redirect()->back()->with('error', 'Credentials not matched !');
}
And lastly, I recommend using Laracasts/Flash for a more fluent flash messaging. So your code would be something like this.
flash()->error('Credentials not matched.');
return redirect()->back();
To sum up my suggestion:
if (!isset($checkUser)) {
flash()->error('Credentials not matched.');
return redirect()->back();
}
You can add your logic in the validator method of the RegisterController like this :
protected function validator(array $data)
{
\Validator::extend('has_invitation', function($attribute, $value, $parameters) use($data){
$checkUser = Invitation::where('email', $data['email'])
->where('token', $value)
->first();
return !$checkUser;
}, "Credentials not matched !");
return Validator::make($data, [
'name' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6|confirmed',
'token' => 'required|has_invitation'
]);
}
If there is an error in validation laravel will automaticly redirect to the registration page.
Make a change in if condition in protected function create(array $data) in RegisterController
if (!$checkUser) {
return null;
}
and overwrite the register method from trait RegistersUsers in RegisterController
public function register(Request $request)
{
$this->validator($request->all())->validate();
$user = $this->create($request->all());
if(!$user) return redirect()->back()->with('error','Credentials Not Matched! ');
event(new Registered($user));
$this->guard()->login($user);
return $this->registered($request, $user)
?: redirect($this->redirectPath());
}

Reuse laravel validation rules from another controller

Q: How can i reuse Auth's ResigsterController validation rules from another controller without having to grab the whole RegisterController class?
Here are the rules:
...
protected function validator(array $data)
{
return Validator::make($data, [
'fname' => 'required|string|max:255',
'lname' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6|confirmed',
'tos' => 'boolean|accepted',
]);
}
...
The other controller in:
app\Http\Controllers\UserController.php
public function update(Request $request, User $user)
{
//I need to validate $request with the rules from
//ControllersAuth\RegisterController.php
}
To reuse same validation rules you can use Form Request Validation
I suggest to use trait. Create a trait like:
trait ValidationTrait {
public $errors;
public function validate($data) {
$Reflection = new \ReflectionClass(__CLASS__);
$ReflectionClass = $Reflection->newInstance();
if(empty($ReflectionClass->rules)) return TRUE;
$v = Validator::make($data, $ReflectionClass->rules);
if($v->fails()) {
$this->errors = $v->failed();
return FALSE;
}
return TRUE;
}
public function validationErrors() {
return $this->errors;
}
}
In model:
class myModel extends Eloquent {
use ValidationTrait;
public $rules = array(
'fname' => 'required|string|max:255',
'lname' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6|confirmed',
'tos' => 'boolean|accepted',
);
}
Call it like:
$myModel = new myModel();
if($myModel->validate(Input::all()) {
//validate success....
}else{
return $Customer->validationErrors()
}
You should try using creating a Helper class so you can have some of your code's reusable in any class.
If you don't know how to make a Helper class there are guides here
you can make a file request add the validation rule there, next time u need it, you can call the file name,ex:
public function update(UserRequest $request,User $user){
}
//1. Php artisan make:request UserRequest
//2. add rule to UserRequest file
public function rules()
{
return [
'fname' => 'required|string|max:255',
'lname' => 'required|string|max:255',
'email' => 'required|string|email|max:255|unique:users',
'password' => 'required|string|min:6|confirmed',
'tos' => 'boolean|accepted',
];
}
https://laravel.com/docs/5.4/validation#form-request-validation

Categories