juu073's avatar

How do I do polymorphic creates "the right way"?

Hello,

I currently have a polymorphic relationship between, for my first step, two tables -- content and blogs.

Content will be anything that a user can submit to the community I'm building -- blogs, links, file uploads, etc.

First, my tables have the following structure:

  • contents: id, title, summary, user_id, object_type, object_id, created_at, updated_at
  • blogs: id, content, created_at, updated_at

I will note that I have the following under the boot() function of the AppServiceProvider:

    public function boot()
    {
        Relation::morphMap([
           'blog' => \App\Blog::class
        ]);
    }

I have the following relationship defined in my Content model:

    public function object()
    {
        return $this->morphTo();
    }

And I have the following defined in my Blog model:

    public function activity()
    {
        return $this->morphOne(Content::class, 'object');
    }

So, when I create a blog, I need to create both a record in contents and a record in blogs, and I have it working in the store() function of my Blog controller, but I know I’m doing it an absolutely round-about way, and I’m sure I can reduce it to likely one line of code:

    public function store(Request $request)
    {
        $validData = $this->validateBlog();
        $validData['user_id'] = Auth::id();

        $blog = Blog::create($validData);
        $validData['object_type'] = 'blog';
        $validData['object_id'] = $blog->id;

        $content = Content::create($validData);

        return redirect('/blog');
    }

I have seen tutorials that show I should be able to do something like one of the following:

$content->object()->save($blog)
$blog->activity()->save($content)

...but I had no luck.

Can anyone tell me the most efficient way of doing this?

If there is any other information you need, please let me know! As I said, the relationship itself works — I’m able to retrieve the data using $blog->activity and $blog->object calls, but I just can’t get the insert down.

Thanks!

0 likes
4 replies
Snapey's avatar

You should follow the documentation for this and create columns for activity type and activity id

Your name is a little tricky in that these columns are likely to be activityable_type and activityable_id

If you don't use these names then you will need to specify them where you create the morphTo and morphMany relationships.

You can then store them like $blog->activity()->create() and not need to try and manipulate the fields yourself.

juu073's avatar

I know the naming conventions aren't necessarily what the documentation recommends; however, how I'm using it does align with the documentation, as that is why the optional arguments are provided -- to do what I'm doing.

I'm not having an issue with the way things are named, as I'm able to retrieve records, and use, for example, $blog->activity->user_id to get the user_id attached to the content when querying for a blog, and even $blog->activity->user->name for my relationship I've made in the content object to the users table. My issue is strictly with the saving/creating records.

Snapey's avatar

how does this

public function object()
{
    return $this->morphTo();
}

Tell eloquent what columns contain the related model?

juu073's avatar

My understanding is because that method name is object() that is calling morphTo, that morphTo knows to look at object_type and object_id. If that’s incorrect, then I’m looking for guidance on what to provide to it.

I’m able to call $content->object with no issue to get attributes in the corresponding record in blog.

Please or to participate in this conversation.