pmusa

pmusa

Member Since 6 Months Ago

Experience Points
2,020
Total
Experience

2,980 experience to go until the next level!

In case you were wondering, you earn Laracasts experience when you:

  • Complete a lesson — 100pts
  • Create a forum thread — 50pts
  • Reply to a thread — 10pts
  • Leave a reply that is liked — 50pts
  • Receive a "Best Reply" award — 500pts
Lessons Completed
4
Lessons
Completed
Best Reply Awards
0
Best Reply
Awards
  • start-engines Created with Sketch.

    Start Your Engines

    Earned once you have completed your first Laracasts lesson.

  • first-thousand Created with Sketch.

    First Thousand

    Earned once you have earned your first 1000 experience points.

  • 1-year Created with Sketch.

    One Year Member

    Earned when you have been with Laracasts for 1 year.

  • 2-years Created with Sketch.

    Two Year Member

    Earned when you have been with Laracasts for 2 years.

  • 3-years Created with Sketch.

    Three Year Member

    Earned when you have been with Laracasts for 3 years.

  • 4-years Created with Sketch.

    Four Year Member

    Earned when you have been with Laracasts for 4 years.

  • 5-years Created with Sketch.

    Five Year Member

    Earned when you have been with Laracasts for 5 years.

  • school-session Created with Sketch.

    School In Session

    Earned when at least one Laracasts series has been fully completed.

  • welcome-newcomer Created with Sketch.

    Welcome To The Community

    Earned after your first post on the Laracasts forum.

  • full-time-student Created with Sketch.

    Full Time Learner

    Earned once 100 Laracasts lessons have been completed.

  • pay-it-forward Created with Sketch.

    Pay It Forward

    Earned once you receive your first "Best Reply" award on the Laracasts forum.

  • subscriber-token Created with Sketch.

    Subscriber

    Earned if you are a paying Laracasts subscriber.

  • lifer-token Created with Sketch.

    Lifer

    Earned if you have a lifetime subscription to Laracasts.

  • lara-evanghelist Created with Sketch.

    Laracasts Evangelist

    Earned if you share a link to Laracasts on social media. Please email [email protected] with your username and post URL to be awarded this badge.

  • chatty-cathy Created with Sketch.

    Chatty Cathy

    Earned once you have achieved 500 forum replies.

  • lara-veteran Created with Sketch.

    Laracasts Veteran

    Earned once your experience points passes 100,000.

  • 10k-strong Created with Sketch.

    Ten Thousand Strong

    Earned once your experience points hits 10,000.

  • lara-master Created with Sketch.

    Laracasts Master

    Earned once 1000 Laracasts lessons have been completed.

  • laracasts-tutor Created with Sketch.

    Laracasts Tutor

    Earned once your "Best Reply" award count is 100 or more.

  • laracasts-sensei Created with Sketch.

    Laracasts Sensei

    Earned once your experience points passes 1 million.

  • top-50 Created with Sketch.

    Top 50

    Earned once your experience points ranks in the top 50 of all Laracasts users.

Level 1
2,020 XP
Nov
13
5 days ago
Activity icon

Replied to Flip() Collection Between Model And Relations?

@piljac1 I did that too already. I was not satisfied with that because then you end up with a collection of Users (great so far) who each have their own Comment in the relations key (still great so far) , but each Comment still has a relations key to its User as well. Basically you built a 3 levels deep Collection instead of 2. setRelation() or unset() on the relation key won't work, because this will unset the whole reference.

@jaytee I have a PostController with index() method that returns 12 posts per page. I want to make it so that, for each of these 12 posts per page, each post also shows a list of the users that left a comment.

The requirement for that list of users (commentators) per posts is the following:

  1. distinct users (same user should not be printed twice),
  2. users must be listed so that the first commentator appears first (so I must check comments.created_at), then it is list by latest. So it means the second user that appears in the list is the user that left a comment the latest.
  3. I want to list only 5 users in that list.

Is that clear enough now that you have the big picture? and yes, the comments is polymorphic. morphMany / MorphTo

The whole problem i'm facing here is that I want to eagerload as much as possible because of the pagination. Obviously, things would be way easier if I just looped through each post to build that list of users (commentators) for each. But that would mean at least +12 more SQL requests per page (now imagine having a pagination of 100 posts per page...)

Nov
12
6 days ago
Activity icon

Replied to Flip() Collection Between Model And Relations?

I appreciate your anticipation effort but you definitely don't need to know what my ultimate goal is. My first post is clear enough. I removed the little bits of unnecessary code that confused you. I'll even rephrase my question : Starting from a Collection, how do I flip each Comment item with its User relation?

I don't need workarounds. You are suggesting me stuff that I tried for hours without any success already. So i made my question as simpler as it can get so nobody wastes time. Your suggestion are even already in the post I linked (withcount and query builder), and here for the distinct part : https://laracasts.com/discuss/channels/eloquent/sortby-not-compatible-with-distinct

Basically I'm asking how to dig a hole with a spoon and I don't need to know about shovels. Unless you feel like reading the 2 others topics above...

Thank you for trying though @jaytee .

Activity icon

Replied to Flip() Collection Between Model And Relations?

I'm trying to show how many DIFFERENT users commented on a post (eventhough there are 100 comments, that could be just 2 different users replying to each other).

So I need to access those users starting from the $post (eagerloading), not with $user->comments.

I understand what you mean but I have sql optimization in mind. I want to minimize database roundtrips as much as possible.

See here if you feel like reading the whole story behind this mishmash : https://laracasts.com/discuss/channels/eloquent/eloquent-withcount-and-collection-count-do-not-return-same-count

Activity icon

Started a new Conversation Flip() Collection Between Model And Relations?

I have a Collection of Comment models.

Each Comment has a relation with a User model.

How do I flip the entire Collection, so that I end up having the following? :

a Collection of User models, where each User has a relation with its Comment model.

https://i.imgur.com/BoUSGPt.png

Nov
10
1 week ago
Activity icon

Replied to Eloquent WithCount() And Collection Count() Do Not Return Same Count

did that already (debugbar). I can't figure the magic behind the eagerloading, all I can tell is it does not seem to run my commentators() method query, which is:

    public function commentators(): hasManyThrough
    {
        /** @noinspection PhpUndefinedMethodInspection */
        return $this->hasManyThrough(
            'App\User',
            'App\Comment',
            'commentable_id',
            'id',
            'id',
            'user_id'
        )
        ->where('commentable_type', array_search(static::class, Relation::morphMap()) ? : static::class)
        ->groupBy('users.id', 'comments.commentable_id')
        ->orderByRaw('MIN(comments.created_at) ASC, users.created_at ASC, users.id ASC');
    }

and here is what the $posts, which is supposed to eager load commentators and count it, actually runs in sql :

select `posts`.*, 
(select count(*) from `users` inner join `comments` on `comments`.`user_id` = `users`.`id` where `comments`.`deleted_at` is null and `posts`.`id` = `comments`.`commentable_id` and `comments`.`deleted_at` is null and `commentable_type` = ? and `users`.`deleted_at` is null) as `total_commentators_count`, 
(select count(*) from `comments` where `posts`.`id` = `comments`.`commentable_id` and `comments`.`commentable_type` = ? and `comments`.`deleted_at` is null) as `total_comments_count`, 
(select count(*) from `comments` where `posts`.`id` = `comments`.`commentable_id` and `comments`.`commentable_type` = ? and `user_id` = ? and `comments`.`deleted_at` is null) as `user_comments_count` 
from `posts` 
where `posts`.`deleted_at` is null order by `created_at` desc"

it's missing all the groupby and orderby parts???

Activity icon

Started a new Conversation Eloquent WithCount() And Collection Count() Do Not Return Same Count

I eager load a relation so that it can return count of DISTINCT commentators of a blog post. Such as this: ->withCount('commentators as total_commentators_count')

Now in my blade partial view, the following will return the CORRECT count: $post->commentators->count()

but the following will NOT return the correct count: $post->total_commentators_count

even though they do exactly the same. How come?

Here are some screenshots (I blurred the unnecessary code for convenience) :

https://i.imgur.com/bNcrVid.png

https://i.imgur.com/WlzVqAs.png

Nov
08
1 week ago
Activity icon

Replied to You Can Delete() Over And Over Something Already Deleted...

@snapey the part that annoys me the most is the fact that it fires the events any case ...

I had to update all my model events in order to care of that behavior (which should never happen I got you, but if it can happen then it can happen...)

<?php

declare(strict_types=1);

namespace App\Observers;

use App\Tag;

class TaggableObserver
{
    private static $deleted_at = null;

    public function deleting($taggable)
    {
        /** @var \App\Traits\Taggable $taggable */
        $tagsToUpdate = $taggable->tags()->pluck('id');

        if (! method_exists($taggable, 'runSoftDelete')) {
            Tag::whereIn('id', $tagsToUpdate)->decrement('count', 1);
        } else {
            /** @var \Illuminate\Database\Eloquent\SoftDeletes $taggable */
            if ($taggable->isForceDeleting()) {
                if ($taggable->trashed()) {
                    Tag::whereIn('id', $tagsToUpdate)->decrement('trashed_count', 1);
                } else {
                    Tag::whereIn('id', $tagsToUpdate)->decrement('count', 1);
                }
            } else {
                if (! $taggable->trashed()) {
                    Tag::whereIn('id', $tagsToUpdate)->decrement('count', 1);
                    Tag::whereIn('id', $tagsToUpdate)->increment('trashed_count', 1);
                }
            }
        }

        Tag::removeOrphanedTags();
    }

    /*public function deleted($taggable){}*/

    /*public function forceDeleted($taggable){}*/

    public function restoring($taggable)
    {
        static::$deleted_at = $taggable->deleted_at;
    }

    public function restored($taggable)
    {
        if (null !== static::$deleted_at) {
            /** @var \App\Traits\Taggable $taggable */
            $tagsToUpdate = $taggable->tags()->pluck('id');
            Tag::whereIn('id', $tagsToUpdate)->increment('count', 1);
            Tag::whereIn('id', $tagsToUpdate)->decrement('trashed_count', 1);
        }
    }
}
Activity icon

Replied to You Can Delete() Over And Over Something Already Deleted...

@jaytee correct, but it still fires the deleting() and deleted() model events regardless !

@snapey maybe. maybe not. this forces to do controls/checks at this app level, while the delete() method should be able to handle it itselft imo.

Nov
07
1 week ago
Activity icon

Replied to You Can Delete() Over And Over Something Already Deleted...

I want to make sure I did not miss something before messing with the big boys on GH.

Look at what I have to code to avoid that :

https://i.imgur.com/k9CsdST.png

I have to check if ->trashed()...

similar ugly stuff within my restored() event observer. which I actually had to get rid off! guess why? because I had to fallback to the restoring() event in order to be able to check on ``->trashed()```

but I want restored(), not restoring() all because the Eloquent Model is absolutely fine with this:

$post->delete();
$post->delete();
$post->delete();
$post->delete();
$post->delete();
$post->delete();
$post->delete();
Activity icon

Replied to You Can Delete() Over And Over Something Already Deleted...

this is important in my mind because this means you have to be extremely carefull and make sure your users do not try to softdelete something already softdeleted. so you need to perform strong checks on "top" level (Controllers) because the low level (Eloquent Model) just does not care and runs the deletion over and over.... which actually should be the opposite?

There is like a lack of consistency. When you need to retrieve a softdeleted model, this wont work: \App\Post::find('id'); bceause you need to do this: \App\Post::withTrashed()->find('id'); which is fine. I'm ok with that concept. So why is not there the same behavior/consistency with the delete() and restore() methods? shouldn't it be:

$post->withTrashed()->delete();

which is absurd of course, but would make it so that you cannot just straight softdelete something already softdeleted.

Not sure if I'm clear...

Activity icon

Started a new Conversation You Can Delete() Over And Over Something Already Deleted...

This following bothers me: Consider a Post model which uses SoftDeletes trait. You can actually do the following as many times as you want:

// some code 
$post->delete();
$post->delete();
$post->delete();
// some code

why does not this throw an error by default? how to avoid this?

In fact, you can do the same with the restore() method!

The reason why this bothers me is because this will run through a model Observer perfectly fine for the following events: deleted and restored which will trigger unwanted stuff, since you should not be able to softdelete something that is already softdeleted (and not be able to restore something that is already restored).

Quick fix : I guess I would need to wrap my whoooole code and delete() operations the following way now :

if (! $post->trashed()) {
    $post->delete();
}

which is absurd.

I figured this out while writting tests.

Is this normal and why? Thanks

Oct
08
1 month ago
Activity icon

Replied to Restoring() And Restored() Model Events

Got it. I'll sure write some tests for that particular scenario, just in case. Thank you very much @nakov , you have been of great help! all tests green, i can have a sleep now.

Activity icon

Replied to Restoring() And Restored() Model Events

"Having static variable must be because the boot method is static, and you cannot call a reference variable from within a static method." Right, but I'm using an observer. Like this :

private static $deleted_at = null;

public function deleting(Post $post)
{
    $post->comments
        ->each->delete();
}

public function restoring(Post $post)
{
    static::$deleted_at = $post->deleted_at;
}

public function restored(Post $post)
{
    $post->comments()
        ->onlyTrashed()->where('deleted_at', '>=', static::$deleted_at)
        ->get()
        ->each->restore();
}

Let's say I run a foreach() loop that is supposed to restore 2 posts. Isn't there any risk, since the timing is very close (milliseconds) that the deleted_at static var of first post is swapped with deleted_at static var of the second post? which would result in restoring comments with inaccurate time in here : ->where('deleted_at', '>=', static::$deleted_at)

so far that seems to work (all tests green!) but i need to make sure before i go forward.

Activity icon

Replied to Restoring() And Restored() Model Events

calling a static variable did the trick indeed, plus your explanation was on point about restoring() and restored() being obviously called on 2 separate instances, which explained the empty var. I don't feel very comfortable calling a static var though. Is there any downside to this? Will it cause me headaches later on? Most importantly: What if I happen to restore 2 posts at the same time?

Activity icon

Replied to Restoring() And Restored() Model Events

Your query returns an error because $this->deletedAt is null.

Here are some tests :

    public function restoring(Post $post)
    {
        $this->deletedAt = $post->deleted_at;
        dd($this->deletedAt);

    }

This will return an instance of Carbon with a good date (not null). Great so far!

And then :

public function restored(Post $post)
{
    dd($this->deletedAt);
    /*dd($post->comments()
        ->onlyTrashed()//->where('deleted_at', '>=', $this->deletedAt)
        ->get());*/
}

this will return null. Why though? Also, if I run dd($post); I can see all the references to the column deleted_at are null. Since $this->deletedAt references object of $post I believe it also becomes null at some point.

Here is my test btw :

    public function test_it_can_restore_its_comments_when_restored_post()
    {
        $post = app(PostFactory::class)
            ->withComments(3)
            ->create();
        $this->assertEquals(1, Post::count());
        $this->assertEquals(3, Comment::count());

        $post->delete();
        $this->assertEquals(0, Post::count());
        $this->assertEquals(1, Post::onlyTrashed()->count());
        $this->assertEquals(0, Comment::count());
        $this->assertEquals(3, Comment::onlyTrashed()->count());

        $post->restore();
        $this->assertEquals(1, Post::count());
        $this->assertEquals(3, Comment::count());

        $this->assertEquals(0, Post::onlyTrashed()->count());
        $this->assertEquals(0, Comment::onlyTrashed()->count());
    }

it fails near the end at this line : $this->assertEquals(3, Comment::count()); with InvalidArgumentException: Illegal operator and value combination because you can't perform >= on a nullhere : ->where('deleted_at', '>=', $this->deletedAt)

Activity icon

Replied to Restoring() And Restored() Model Events

hehe, I tried that already. Without any success. It worked for you because you only restore a single row. Try with a collection of 3 comments to restore and you will see it fails. You will notice only your first row will be restored. 2 others will remain. And it will throw an error, because once the method finishes restoring your first row (first comment), your $this->deletedAt now equals null, so all other models (the 2 other comments) in your collection won't be restored.

Activity icon

Started a new Conversation Restoring() And Restored() Model Events

I want to restore comments (model is Comment) attached to a post (model is Post) after the post is restored.

This fails :

public function restored(Post $post)
{
    $post->comments()
        ->onlyTrashed()->where('deleted_at', '>=', $post->deleted_at)
        ->get()
        ->each(function ($comment) {
            $comment->restore();
        });
}

This works:

public function restoring(Post $post)
{
    $post->comments()
        ->onlyTrashed()->where('deleted_at', '>=', $post->deleted_at)
        ->get()
        ->each(function ($comment) {
            $comment->restore();
        });
}

Difference is: restoring() instead of restored().

The following condition : where('deleted_at', '>=', $post->deleted_at) is here because I do not want to restore comments that were soft-deleted before the post was deleted. In other words, it's because I do not want to restore comments that were soft-deleted by moderators. I want to restore the comments that were soft-deleted the very moment I soft-deleted the post.

Reason why it fails: I believe it fails with restored() because $post->deleted_at becomes null so I cannot use it in my where() condition anymore.

Question: how do I hold the previous value of $post->deleted_at, right before it was restored? I tried playing with getDirty() and getChanges() but these did not help, they hold no track of previous value in the observer.

Thank you for your help.

Oct
06
1 month ago
Activity icon

Replied to Traits With Same Method Name

Right. I found about aliases on StackOverflow already. However there is no magic obviously. I still need to tell php how to "know" i want the comments left BY the user model, OR i want the comments left ON the user model. So keeping commentableComments() and commentatorComments() is the way to go for me I guess. exemple:

$user->commentableComments()->get(); // will return comments left ON the user's profile
$user->commentatorComments()->get(); // will return comments left BY the user.

how would you guys rename these two methods? I really don't like it.

Activity icon

Replied to Traits With Same Method Name

I do have a Post model. However, not just Post is a commentable. User profiles are also commentable. However, User is BOTH commentable and commentator. So I need to import BOTH traits for User, hence the conflict with the traits method name.

Let me ask my question an other way: Let's suppose your Post model has 50 traits (why not). Now chances are accross those traits, some have the same method names. How do you deal with that?

Oct
05
1 month ago
Activity icon

Started a new Conversation Traits With Same Method Name

my model User has 2 traits:

    use Commentable;
    use Commentator;

both traits currently have a ******comments() method like this:

$comments_of_a_post = $post->commentableComments()->get();
$comments_of_a_user = $user->commentatorComments()->get();

I'd like to rename these 2 methods into comments() instead, simply, but those then conflict, since User model calls 2 traits with same method names.

Any way to work around this? That actually works fine this way but I do not like the ugly "commentable****" and "commentator***" prefixes. I want to get rid of those...

thanks

Oct
01
1 month ago
Activity icon

Replied to Php Artisan Config:cache Did TRUNCATE My Whole Database

Solved it. Nevermind. See here: https://github.com/laravel/framework/issues/13374

I see I wasn't the only one surprised by such a behavior.

Activity icon

Started a new Conversation Php Artisan Config:cache Did TRUNCATE My Whole Database

When I run this: php artisan config:clear it's all great and my phpunit tests run super fast (~500ms).

But once I run this: php artisan config:cache

then this vendor/bin/phpunit tests/Feature/ApiCommentsTest.php (note that this test file has trait use RefreshDatabase) it will take ~20sec for the test to complete but most importantly it will just erase my whole database. Glad I'm not in a production environment. This was so frightening.

Why such a behavior between the clear and cache. How do I solve this issue?

my phpunit.xml has this :

    <php>
        <env name="APP_ENV" value="testing"/>
        <env name="DB_CONNECTION" value="testing"/>
        <env name="CACHE_DRIVER" value="array"/>
        <env name="SESSION_DRIVER" value="array"/>
        <env name="QUEUE_DRIVER" value="sync"/>
        <env name="MAIL_DRIVER" value="array"/>
        <ini name="display_errors" value="On" />
        <ini name="display_startup_errors" value="On" />
    </php>

and my database.php has this:

        'testing' => [
            'driver' => 'sqlite',
            'database' => ':memory:',
            'prefix' => '',
        ],

So how come running a phpunit test destroyed my whole mysql database, while it's supposed to run into :memory: ?

Please note that it does indeed seem to run tests into :memory: when i execute php artisan config:clear prior to vendor/bin/phpunit tests/Feature/SomeTest.php, but thing go really bad as soon as I execute php artisan config:cache then run any test.

isn't this config command just something that is supposed to cache the env file and that's pretty much all about it?

I'm worried. Please explain.

edit: laravel 6, php7.3, debian

Sep
29
1 month ago
Activity icon

Replied to FormRequest With Variables

Do you have documentation about this trick? I could not find any. My IDE is complaining about the FormRequest constructor requiring a call to parent constructor...

knowing the parent has many parameters:

public function __construct(array $query = array(), array $request = array(), array $attributes = array(), array $cookies = array(), array $files = array(), array $server = array(), $content = null)
{
    $this->initialize($query, $request, $attributes, $cookies, $files, $server, $content);
}
Activity icon

Replied to FormRequest With Variables

I don't understand. Is it the FormRequest that retrieves the $commentable ? How do I typehint my store() method? Like:

public function store(Test $request)

In my mind, the user's request hits the FormRequest first, which validates the datas, then goes down to the controller. But since it's the controller that retrieves the $commentable, how is this supposed to work?

Activity icon

Started a new Conversation FormRequest With Variables

How do I put my validation logic within a FormRequest, knowing that my validation rules need variables set by the controller?

Here is my actual code: https://i.imgur.com/3bb8rgI.png

I want to tidy up my controller's store() method, moving the validate() in a FormRequest. However, as you can see, it needs the $commentable variable, which is retrieved by the controller.

I guess I could make it so that the FormRequest could retrieve that variable itself as well, but that would be an ugly duplicate (since it would also probe the database twice...). So that is not a good solution at all.

Any idea? Cheers.

Sep
20
1 month ago
Activity icon

Replied to OrderBy() Not Compatible With Distinct()

Fixed it with a GROUP BY instead of using DISTINCT

This answer from Tim Biegeleisen helped me understand the issue: https://stackoverflow.com/a/46466349/7977859 so no need for ugly tinkerings about ONLY_FULL_GROUP_BY in my.cnf

https://i.imgur.com/XUaB91d.png

Sep
19
1 month ago
Activity icon

Replied to OrderBy() Not Compatible With Distinct()

That's right, I'm looking to retrieve the usernames that left 1 (or more) comment on the Post model.

A Post has many Comments (polymorphic relationship, since not only Posts can be commented but some other models as well), and a Comment belongs to a User.

I need to go through the comments table for this (inner join?), to get the list of users (without duplicates). The list of users (who commented on a post), must be ordered by comments.created_at asc.

I cannot return a Collection. I need it as an Instance of Eloquent\Relations.

I cannot avoid using a distinct here, since that is exactly what I want: a distinct list of users, without duplicates, below every post (the view shows the participants).

Activity icon

Replied to OrderBy() Not Compatible With Distinct()

wut?

also, I figured distinct() does not accept any parameter. this is what i am left with so far:

    public function commentableCommentators(): belongsToMany
    {
        return $this->belongsToMany($this->retrieveUserModel(), 'comments', 'commentable_id', 'user_id')
            ->where('commentable_type', array_search(static::class, Relation::morphMap()) ? : static::class)
            ->withPivot('created_at')->orderBy('pivot_created_at')
            ->distinct();
    }

which orders results well. but does not eliminate duplicates anymore. like if it was ignoring the distinct(); at the very end...

select distinct `users`.*, `comments`.`commentable_id` as `pivot_commentable_id`, `comments`.`user_id` as `pivot_user_id`, `comments`.`created_at` as `pivot_created_at` from `users` inner join `comments` on `users`.`id` = `comments`.`user_id` where `commentable_type` = 'App\Post' and `comments`.`commentable_id` in ('aaa', 'bbb', 'ccc', 'ddd') and `users`.`deleted_at` is null order by `pivot_created_at` asc
Sep
12
2 months ago
Activity icon

Replied to OrderBy() Not Compatible With Distinct()

I meant orderBy() instead of sortBy() of cours.

I can't sort later in the view, since that sql request does not return any comment but the users only. I just need the distinct users, but orderer by the time they left their comments on that post.

Plus I do not want to do that in a view anyway.

Sep
11
2 months ago
Activity icon

Started a new Conversation OrderBy() Not Compatible With Distinct()

I have 3 models: User Post Comment

Users can leave comments on a post.

I have a method within my Post model that allows me to list all users who left a comment on a post :

    /**
     * Get distinct commentators on a commentable model.
     *
     * @usage  $distinctCommentators = Post::find('post_UUID')->commentableCommentators()->get();
     *
     * @return \Illuminate\Database\Eloquent\Relations\belongsToMany
     */
    public function commentableCommentators(): belongsToMany
    {
        return $this->belongsToMany($this->retrieveUserModel(), 'comments', 'commentable_id', 'user_id')
            ->where('commentable_type', array_search(static::class, Relation::morphMap()) ? : static::class)
            ->distinct('user_id');
    }

I'd like to sort that users list so that the user that commented first appears first. So i appended this :

->orderBy('comments.created_at')

Which won't work since it collides with the distinct().

Thank you for your help.

Activity icon

Replied to User Specific Alerts With Many Filters

you mean I would check against a specific table that would list every possible combinations of criterias/filters?

Activity icon

Started a new Conversation User Specific Alerts With Many Filters

Imagine an app where people would be able to submit best online deals. i.e : User posts a deal where Product is -50% off at online Shop.

Now let's say User2 wants to receive alerts everytime a new deal is submitted, but where price of Product is between $50 and $100, plus where Product is of family "electronics" only, plus where Product is at Shop named "Amzn" only.

How would this look like in Eloquent/Laravel? Do you have to run an SQL request for every single user of your DB, everytime a new deal is posted, to check if the deals fits in each user's criterias/filters, then send the alert?

This is a complete random example. Basically my question is, broader picture: how do you handle user specific alerts with very user specific filters?

Thank you

Sep
10
2 months ago
Activity icon

Replied to Factory And Events / Call A Custom Method Instead Of Create()

Yes I do. Thank you for your link to that article. That's what I needed.

Activity icon

Started a new Conversation Factory And Events / Call A Custom Method Instead Of Create()

User can leave a Comment on a Post. Those are 3 models. When user comments a post, I store the comment through a custom method commentatorStoreComment(), which also triggers an event :

$user->commentatorStoreComment($post, 'here goes my interesting comment body blablabla');

https://i.imgur.com/ab1Juam.png

In order to test it, here is how I am forced to code my tests :

https://i.imgur.com/YMHg9hg.png

As you can see, I cannot use my Comment Factory since this would bypass my custom method that fires the event.

This passes the tests fine, but I am looking for a more elegant/maintainable/scalable way to write my tests involving Comment. Right now I have to duplicate that line everywhere for each test cases...

Thank you.

Sep
08
2 months ago
Activity icon

Replied to Eager Load A Relation

Sure, but I was looking for something more elegant.

                ->when(auth()->id(), function ($query) {
                    return $query->withCount('userComments');
                })

All good!

Activity icon

Replied to Eager Load A Relation

That works very well indeed. Thanks Muhammed!

Bonus question : is there a way to skip that additional "request" if the user is not logged in? I'd like to get rid of the highlighted request if there is no auth()->id() since there would be no point running that relationship :

https://i.imgur.com/cLeEcmJ.png

Activity icon

Replied to Eager Load A Relation

Correct. You got it. I just want to show an info next to each post if the user has left a comment there.

I'm thinking about something like this :

->withCount('userComments')

which would then also allow me to display the number of comments left by the user on each post. With something such as this, on the Post model :

    public function userComments(): MorphMany
    {
        return $this->comments()->where('user_id', auth()->user()->id);
    }

Thoughts? Is there a better way to achieve this?

Activity icon

Replied to Eager Load A Relation

Sorry. Let me explain it a different way.

This is what my partial view looks like:

{{ $post->title }}<br />
{{ $post->bodyTruncated }}<br />
<a href="{{ route('posts.show', $post->id) }}">Click here to read more about this post</a><br />             
@if(auth()->user() && $post->isCommentedByUser(auth()->user()))
    You left comments on this post.
@endif

Problem: the isCommentedByUser method fires an SQL request for every single $post (I have 12 per page). I'd like to find away that would grab the info whether the user commented (or not) any of the shown posts, with eager load.

Activity icon

Started a new Conversation Eager Load A Relation

my PostController.php :

    public function index()
    {
        $posts = Post::latest()
                ->with('user')
                ->withCount('comments')
                ->paginate(12);

        return view('posts.index', compact('posts'));
    }

my Post model :

    public function comments(): MorphMany
    {
        return $this->morphMany(Comment::class, 'commentable');
    }

my User model :

    public function comments(): HasMany
    {
        return $this->hasMany(Comment::class, 'user_id', 'id');
    }

How do I eager load a boolean within my controller's $post so that my view can display the fact that auth()->user()->id left or not (true/false) a comment on each displayed post (12 per page)? I want to avoid the N+1 problem I currently encounter.

Sep
05
2 months ago
Activity icon

Replied to [security] Creating Instance From POST Data

I wish I could.

https://i.imgur.com/q1npNpG.png

As you can see, I perform the validation using vars that are defined/assigned just above the validate() method. Those vars are $commentableTable and $commentableKeyName I haven't figured yet how to elegantly send those to the FormRequest. My controller needs that $commentable var, and I do not want to retrieve that var both in the controller and the FormRequest (since it would poll the DB twice)

Sep
04
2 months ago
Activity icon

Replied to [security] Creating Instance From POST Data

I ended using the native ReflectionClass, which seems bulletproof to me.

My getCommentable() news up an instance only if it's ok to do so.

Only then it hits the validate() method, which at that point it almost just a second pass, but why not. Never paranoïd enough.

https://i.imgur.com/u4vLNGw.png

I'll move on from here.

I did not like the idea of maintaining an array of whitelisted values. The interface works great.

Thank you again for your lights ustam

Sep
03
2 months ago
Activity icon

Replied to [security] Creating Instance From POST Data

I sure do, as you can see. I was wondering if it was ever possible for a malicious visitor to forge it in a way that it would run methods though, somehow.

teşekkürler kardeşim

Activity icon

Started a new Conversation [security] Creating Instance From POST Data

I'm creating an instance from user submitted data :

https://i.imgur.com/jrMUfYj.png

$instance = new $commentableType(); // App\Post

which comes from:

https://i.imgur.com/lRrD30N.png

$commentableType = 'App\\' . request('commentable_type'); // App\Post

Is such a thing safe? Thank you.

Aug
29
2 months ago
Activity icon

Replied to Eager Loading

Users can comment articles (and files, and images, and whatever). A user can also comment comments. The "answerTo()" allows me to know which comment a certain comment replies to, through the "reply_to_id". In fact, I also do have a "parent_id" column in that same table, which fullfills about the same purpose. but since I do not want an infinite depth of "children", at some level of depth all comments have the same "parent_id" but a different "reply_to_id" (which still allows me to know who replies to who, without having a super deep multidimmensionnal array with that "parent/children" relationship). Not sure if clear enough.

Aug
28
2 months ago
Activity icon

Started a new Conversation Eager Loading

How to avoid this? https://i.imgur.com/JrB4bvw.png

This is redundant.

I have a HasComments.php trait with the following :

    public function comments(): MorphMany
    {
        return $this->morphMany(Comment::class, 'commentable');
    }

And a Comment.php model with the following:

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

    public function answerTo()
    {
        return $this->belongsTo(self::class,'reply_to_id','id');
    }

And here is the faulty line that fires the two redundant SQL queries :

$comments = $this->comments()->with(['user', 'answerTo.user'])->get()->keyBy('id');

How do I make it so that Eloquent merges these 2 (highlighted in the screenshot above) and does not query unnecessarily? Thanks

Aug
24
2 months ago
Aug
21
2 months ago
Aug
18
3 months ago
Activity icon

Replied to SetRelation To Collection

I could also chain strtoupper() onto the collection somehow. That will make it all full caps.