laravel mutator: access other attributes - laravel

I have a plain Laravel 8 install, and added a mutator that should access other attributes of that model.
As an example: would like to set the name to the name + email address.
I tried:
public function setNameAttribute($value) {
$this->attributes['name'] = $value .' - '. $this->attributes['email'];
}
And test:
>>> User::factory()->make()
[!] Aliasing 'User' to 'App\Models\User' for this Tinker session.
<warning>PHP Warning: Undefined array key "email" in .../app/Models/User.php on line 45</warning>
=> App\Models\User {#3399
name: "Mr. Johathan Becker - ",
email: "dsteuber#example.com",
email_verified_at: "2021-05-07 18:10:35",
#password: "$2y$10$92IXUNpkjO0rOQ5byMi.Ye4oKoEa3Ro9llC/.og/at2.uheWG/igi",
#remember_token: "bihwTV6T4E",
}
So: $this->attributes does not contain 'email'.
Can I access the other attributes of that model?
I can imagine that even if it is possible, the mutator can not guarantee that the related attribute is already set.
Update: matiaslauriti's comment solved the simplified example above. Thanks! The order in which the attributes are set matters. Afterwards I can use both $this->attributes['name'] or $this->name.
My more complex use case is: I want to create a Post for a User ($user->posts()->create([...])), and when setting a post attribute I want to access the 'user'. So in that case the user is already set and we can assume the 'user' is available. But in the Post mutator $this->user gives null. Suggestions?

You can try $this->email instead of $this->attributes['email']

Set email input before name input, and then you can access the email attribute with $attributes['email'].
I did it on the request file by
$this->request = collect(['email' => $this->email])->merge($this->request);

Related

Laravel Auth::user()->id returns 0 on custom id

I am trying to make a User object with a String as ID. Everything went fine, even authenticating. But whenever I am trying to get the currently logged in user his ID by either:
Auth::user()->id
or
Auth::id();
Both are returning '0'. Whenever I dump the Auth::user object I can actually see the id attribute correctly. Have I done something wrong?
Laravel tries to cast it to integer, simply put the following property in your User class.
class User {
public $incrementing = false;
}

Laravel - can't get model after deleting related model records

I have a function postShippingmethods in which I delete, update or create new shipping methods depending what the user specified in the form. It works like it should , except that if any methods are deleted, I get empty result when trying to retrieve the user model with the updated methods.
To delete methods, I first get the user:
$user = \App\User::where('id',$id)->with(['shipping_profiles' => function($query) {
$query->where('default', 1);
}, 'shipping_profiles.methods' ])->first();
I compare the stored methods to the ones in the request; if any are missing , they should be deleted.
This code does the deletion:
foreach($non_included_ids as $id){
$method = \App\ShippingMethod::find($id);
$method->suppliers()->detach();
$method->delete();
}
Then I get the user once again, to get the updated data:
$user = \App\User::where('id',$id)->with(['shipping_profiles' => function($query) {
$query->where('default', 1);
}, 'shipping_profiles.methods' ])->first();
^^ this works well if nothing was deleted, but for some reason if something was deleted, the above code will return nothing. And when I try to use the $user to retrieve data I of course get "Trying to get property of non object".
So can anyone explain why this happen and what I should do to get the user with the updated data?
Use a different variable name in the loop:
foreach($non_included_ids as $non_included_id){
Otherwise, the loop changes the value of $id and \App\User::where('id',$id) fetches the wrong user.

Password verify always returns fail in Laravel (Hash::check)

I've got an issue when I try to validate the post password via Hash::check in Laravel 5.5
I made a posts table (in this case sales table) with password column. When I try to create the post, it's working perfectly and the password is hashed and also belongs to logged in User. Then on the current post page is a button with an input (password) to delete that specific post, but the condition is always false.
My Controller public function destroy(Request $request, $id)
$input_pass = request('input_password');
$sale = Sale::find($id);
$hashed = $sale->password;
// Check if sale password is correct
if (Hash::check($input_pass, $sale->password)) {
$sale->delete();
} else {
// something else to do
}
For the post store, I used bcrypt method to hash the password. I've been also trying to dd('sale->password') which refers to column in sales table (correct) and dd('$input_pass') which refers to typed in password in DELETE form (also correct) - so I'm a little bit confused, why the pass don't match.
From your comment I find that you have a logical error where you initially hash your password and persist it in DB.
You are passing the string password to bcrypt where it should actually be something like request('password')
Change
'password' => bcrypt('password'),
to
'password' => bcrypt(request('password')),

how to hash a password laravel 5.2 model create

I'm creating admin user via model and it saving record successfully but password is not being hashed as follows:
$request->password = bcrypt($request->input('password'));
Admin::create($request->except('_token'));
you can not modify $request properties like that.
Give it a try:
$input = $request->except('_token');
$input['password'] = bcrypt($input['password']);
Admin::create($input);
OR, handle it in your Admin Model
public function setPasswordAttribute($value)
{
$this->attributes['password'] = bcrypt($value);
}
Then you can
Admin::create($request->except('_token'));
Take a look at Laravel's Hashing documentation. It shows that you should be hashing any strings like so:
Hash::make($request->newPassword)
However looking at your code, i'd say this issue is actually the fact you're trying to modify the request $request->password, this is not going to work how you expect. Look at your Admin model class and see what the code is expecting, perhaps this is already in built if you pass the correct arguments.

show name instead of id in a url using laravel routing

I have defined a route in laravel 4 that looks like so :
Route::get('/books/{id}', 'HomeController#showBook');
in the url It shows /books/1 for example , now i'm asking is there a way to show the name of the book instead but to keep also the id as a parameter in the route for SEO purposes
thanks in advance
You could also do something like this:
Route::get('books/{name}', function($name){
$url = explode("-", $name);
$id = $url[0];
return "Book #$id";
});
So you can get book by id if you pass an url like: http://website.url/books/1-book-name
if your using laravel 8, this may be helpfull.
In your Controller add this
public function show(Blog $blog)
{
return view('dashboard.Blog.show',compact('blog'));
}
In your web.php add this
Route::get('blog/{blog}', [\App\Http\Controllers\BlogController::class,'show'])->name('show');
Then add this to your model (am using Blog as my Model)
public function getRouteKeyName()
{
return 'title'; // db column name you would like to appear in the url.
}
Note: Please let your column name be unique(good practice).
Result: http://127.0.0.1:8000/blog/HelloWorld .....url for a single blog
So no more http://127.0.0.1:8000/blog/1
You are welcome.
You can add as many parameters to the url as you like, like this:
Route::get('/books/{id}/{name}', 'HomeController#showBook');
Now when you want to create an url to this page you can do the following:
URL::action('HomeController#showBook', ['id' => 1, 'name' => 'My awesome book']);
Update:
If you are certain that there will never be two books with the same title, you can just use the name of the book in the url. You just need to do this:
Route::get('/books/{name}', 'HomeControllers#showBook');
In your showBook function you need to get the book from the database using the name instead of the id. I do strongly encourage to use both the id and the name though because otherwise you can get in trouble because I don't think the book name will always be unique.
You can also use model binding check more on laravel docs
For example
Route::get('book/{book:name}',[BookController::class,'getBook'])->name('book');
The name attribute in "book/{book:name}" should be unique.

Resources