I have a model like the following:
User extends Authenticatable
{
protected $appends = array('role');
public function getRoleAttribute()
{
$role = DB::table('acl_user_has_roles')->where('user_id', $this->id)
->value('role');
return $role;
}
}
When I try to reference this foo attribute like the following:
$user = User::find(1);
unset($user->id); // This line causes the problem.
echo $user->role;
I always get "null" instead of expected "Owner".
What did I miss here?
I am running this in laravel 5.5.43.
In the following post, getKey() function was mentioned, that didn't work.
The problem is actually caused by something else, as described in the following medium post.
Just in case anyone else runs into the same issue. The problem is caused by another line in the code. I unset $user->id before echo.
The issue is described in detail in the following medium post:
Be Careful to Use Laravel Eloquent’s Accessors, Mutators And Events
Related
I'm using soft delete in model Article, but in model Comment not use soft delete. I'm also customize the key using slug column in model Article. If the article is deleted, I want still show the comment. But when article is deleted, show method always return 404.
public function show(Article $article, Comment $comment)
{
if ($article->id != $comment->article_id)
throw new NotFoundHttpException('Record Not Found.');
return $this->success(['comment => $comment']);
}
How to fix this?
Your question statement is not defining the problem you should ask how to bind soft deleted route and model.
Laravel provide ->withTrashed() method for this so it also bind soft deleted models in route.
web.php
user App/Http/Controller/ArticleController;
Route::get('article/{article}', [ArticleController::class, 'show'])->name('article.show')->withTrashed();
But this method added in Laravel 8.55 If you have older version so you can simply find model in controller without route model binding.
ArticleController.php
public function show($article, App/Comment $comment)
{
$article = App/Article::withTrashed()->findOrFail($article);
if ($article->id != $comment->article_id) {
throw new NotFoundHttpException('Record Not Found.');
}
return $this->success(['comment => $comment']);
}
Or you can also use Explicit Binding for specific model in RouteServiceProvider.
public function boot()
{
parent::boot();
Route::bind('article', function ($id) {
return App\Article::withTrashed()->find($id) ?? abort(404);
});
}
And you can also use onlyTrashed() method in explicit binding in case you use separate route for trashed models.
If you want to get deleted records as well, use the method withTrashed
Your code should look something like this:
Article::withTrashed()->find($id);
Hope it help u and happy coding !
I want to add additional data to $user collection so can get the profile fields in the view
I have tried using $user['profileFields'] = $this->getProfileFields() and pass $user to the view using compatct or with and this is working fine.
DD
However, I have found some reference over the net saying I can extend using map but when I tried it is giving the following error
BadMethodCallException
Call to undefined method App\User::map()
So here is what I am trying to understand
Question:
Is the below code is wrong and won't work for what I am looking for and the first approach is the solution? Is there any
recommended method to add additional data to the $user collection?
public function show(User $user)
{
$user->map(function ($user){
$user['profileFields'] = $this->getProfileFields();
return $user;
});
return view('admin.user.show', compact('user'));
}
collection methods are works on the collection, here you're getting the object of user.
$user->profileFields = $user->getProfileFields();
return view('admin.user.show', compact('user'));
If the profileFields is in another table and having a foreign key with model ProfileField, then try to add a one to one relation to the User model.
Inside the User model, add a function
public function profileFields()
{
return $this->belongsTo('App\ProfileField', 'foreign_key','other_key');
}
This will give you the profileFields in every user when calling using eloquent.
I'm new in Laravel and I'm curious about one thing. I have 3 database tables: posts, comments, replies. I want to make a simple delete from each. But obviously post has many comments and comments has many replies. Whole thing is about these replies. Seems like I can't reach them.
I have properly working relations between tables.
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Post;
use App\Comment;
use App\Reply;
use App\Traffic;
use Image;
use Illuminate\Support\Facades\Storage;
class PostsController extends Controller
{
//few others things here...
public function destroy($id) //$id is an id of post
{
// Select Post and comments of post
$post = Post::find($id);
$comments = Comment::where('post_id', $id);
//remove image (working fine)
Storage::delete('public/img/' . $post->image);
// delete all replies of post comments <<< Here is the issue. Can I even do like this?
foreach ($comments as $comment) {
$post_comment_reply = Reply::where('comment_id', $comment->id);
$post_comment_reply->delete();
}
// delete post record (working fine)
$post->delete();
//delete comments of post (working fine)
$comments->delete();
// return to user profile (working fine)
return redirect('/home')->with('success', 'Post has been deleted');
}
There is an even easier way to do so.. if you just add a database constraint to the foreign key in the replies table to the comment..
$table->unsignedInteger('comment_id');
$table->foreign('comment_id')->references('id')->on('comments')
->onDelete('cascade');
The last part: onDelete('cascade') ensures that all the replies will be deleted once a comment has been deleted :) so you don't have to manually do that in the application layer.
Let me know if it makes sense :)
Instead of deleting the replies in a loop, you can delete them all at once:
$comments = Comment::where('post_id', $id);
$comment_ids = $comments->pluck('id');
Reply::whereIn('comment_id', $comment_ids)->delete();
What's wrong in your code is that you create a db query but does not execute it:
// You forgot the ->get() following the where statement
foreach ($comments as $comment)
$post_comment_reply = Reply::where('comment_id', $comment->id)->get();
$post_comment_reply->delete();
}
However the code altogether is not quite optimal, you could make it directly on database level with onDelete('cascade'), or simply create a request to delete the replies without retrieving them and reducing the number of query to the db, like such:
foreach ($comments as $comment)
Reply::where('comment_id', $comment->id)->delete();
}
One step further reducing db queries like suggested above:
Reply::whereIn('comment_id', $comments->pluck('id'))->delete();
If you want to delete the relations via Laravel, you have to override the boot function.
Override the boot() on your Comment model like
protected static function boot()
{
static::deleting(function (Comment $model) {
$model->replies()->delete();
});
parent::boot();
}
This will delete all the replies associated to a comment when that comment is deleted via eloquent.
I have a one-to-one relationship between my User model and an additional UserInformation model in which I store additional needed information which would bloat the "normal" user table.
I set up my models like this:
# User.php
public function information()
{
return $this->hasOne(UserInformation::class);
}
# UserInformation.php
public function user()
{
$this->belongsTo(User::class);
}
I have a profile page where the User can update information from both tables.
The view has inputs like this:
<input name="email"> // is a field in the users-table
<input name="information[size]"> // is a field in the users-information table
I read in different locations that I should be able to save both my User model and its relation in with:
$user->fill($request->all())->save();
But this throws the following error:
preg_replace(): Parameter mismatch, pattern is a string while replacement is an array
So my current solution looks like this:
auth()->user()
->fill($request->except('information'))
->save();
auth()->user()
->information
->fill($request->input('information'))
->save();
That works very good but doesn't look good in my opinion. So my question is: how can I clean that code up and save both in one go?
Have you tried including this
protected $guarded = array('information');
in your User.php model file
and then
auth()->user()
->fill($request->all())
->information->fill($request->input('information'))
->save();
I think your current solution looks fine, but if you want, you could always extract it out to your own custom method in your User model.
public function saveWithInformation($attributes)
{
$this->fill($attributes)->save();
$this->information->fill($attributes['information'])->save();
}
Then you can just call:
auth()->user()->saveWithInformation($request->all());
Since I was looking for a pretty flexible solution I came up with this function which I implemented into my User model (but it could also be included in a BaseModel)
public function fillWithRelation(array $request)
{
foreach ($request as $key => $value)
{
if (is_array($value) && method_exists($this, $key))
// check if the value is an array and if a method with the name of
// the key exists (which would be the relationship
{
$this->{$key}->fill($value);
unset($request[$key]);
}
}
return $this->fill($request);
}
This is definitely working if you include the information for a hasOne relationship like posted in my question.
I am trying to get row from the table with "->find(X)" or "->where" but i get error in return. i guess i am missing something but i can't tell what.
<?php
class SnippetsController extends BaseController {
public $restful = true;
public function index($id)
{
$snippet = SnippetsController::where('id', '=', 11)->get();
i tried it with find but noting helps.
$snippet = SnippetsController::find(11);
with "->get" and without. but noting works. i do have the "11" id in the table itself and the error seems to have noting to do with it.
maybe i need to extend the class to Eloquent? if so, how do i keep the BaseController on top of it?
Thanks!
error:
BadMethodCallException Method [find] does not exist.
You must have a Model called Snippet, right? So this is how you use it:
$snippet = Snippet::find(11);
Your SnippetsController is not tied to a database (Eloquent ORM), so you must create (if you don't have already) a model:
class Snippet extends Eloquent {
}
Just edit the code $snippet = SnippetsController::where('id', '=', 11)->get(); with $snippet = Snippets::where('id', '=', 11)->get();. May be your model name is Snippets it may solve your problem.