tuncdogu55's avatar

tuncdogu55 liked a comment+100 XP

5mos ago

While I understand the power of Polymorphism, I also understand the basic design principles for Database Design. Polymorphism violates something I consider to be crucial to Database Design: Foreign Key Relationships.

When using Polymorphism, the two columns <morphable>_type and <morphable>_id are used. The <morphable>_type column references the name of a Table in the Database, and the <morphable>_id references an ID within that Table. Nothing new here.

However, I see it as bad practice to mix Meta-Data and Data, i.e. <morphable>_type. If a table is dropped or renamed, the Database can't naturally enforce anything. I understand that Migrations can resolve this, but it doesn't fix the fact that the Database itself can't enforce this relationship.

Furthermore, Foreign Key relationships can only reference one Parent Table. Polymorphism violates this with the <morphable>_id column. Sure, there's no Foreign Key assigned to this column, but now you essentially have a number that has no meaning to the Database. If that key is updated, or the entry is removed, how will the Database know to remove that row? I understand that this too can be resolved, by using the Boot Method in each respective Model, but it doesn't fix the fact that the Database itself can't enforce a Foreign Key that isn't defined.

Honestly, this leaves me stuck. I know that there are other alternatives to Polymorphism that are RDBMS friendly, but all require general maintenance, or make the MVC flow feel unnatural. I'm a Database guy, so violating basic principals is hard for me to do. However, I'm also a Design guy, so I don't want to build a system that's hard to code or unnatural. Polymorphism is where these two clash, as it's an elegant solution, but it violates Database Design.

I know the pros for sticking with proper Database Design, but is Polymorphism really worth breaking principles?

Furthermore, is there a nice, general way to automatically handle all of the nasty maintenance issues that come with Polymorphism? Since Laravel is Database Agnostic, I'm willing to bend the rules a bit, as I can say that the Database Layer of my Application (which would extend into Models and Migrations) is able to successfully enforce Polymorphic relationships.

tuncdogu55's avatar

tuncdogu55 liked a comment+100 XP

5mos ago

Ok - for anybody who is wondering, there are a few hurtles here in the database.

The Upsert Method used an Insert query, which actually get's error-checked before executing the query.

The hiccup that I ran into was this.

$team_id = auth()->user()->currentTeam->id; //using jetstream w/ teams

Item::upsert(collect($new_order)->map(function($item) use($team_id) {
  return [
    'id'=>$item['order'],
    'team_id'=>$team_id,
    'sort_order'=>$item['order'],
  ];
})->toArray(), ['id','team_id'], ['sort_order']);

This is the first query I tried, and it failed because it kept saying something along the lines of

The column 'name' has no default value and isn't nullable.

This is because when you create an Item in the application it requires a name (by design).

The way that Upsert works behind the scenes is

INSERT into items (id, team_id, sort_order, created_at, updated_at) VALUES 
    ('id_for_item_1', 1, '2020-12-10 13:30:00', '2020-12-10 13:30:00'), 
    ('id_for_item_2', 2, '2020-12-10 13:30:00', '2020-12-10 13:30:00'), 
    ('id_for_item_3', 3, '2020-12-10 13:30:00', '2020-12-10 13:30:00') 
on duplicate key
update sort_order = values(sort_order), updated_at = values(updated_at)

When it does this - it actually checks to make sure the insert statement is valid before executing, so all your non-nullables are going to break the insert statement.

So, one reasonable solution, if you are positive that the items will not be deleted from the database between being displayed and updated, you can set blank values for all your non-nullable columns.

$team_id = auth()->user()->currentTeam->id; //using jetstream w/ teams

Item::upsert(collect($new_order)->map(function($item) use($team_id) {
  return [
    'id'=>$item['order'],
    'name'=>'',
    'due_date'=>now(),
    'team_id'=>$team_id,
    'sort_order'=>$item['order'],
  ];
})->toArray(), ['id','team_id'], ['sort_order']);

This should be safe because when it does the insert using the id field (assuming it's the primary key) it should always flag as a duplicate, and therefore always update.

tuncdogu55's avatar

tuncdogu55 was awarded Best Answer+1000 XP

6mos ago

foreach($images as $image){
                $course->addMedia($image)
                    ->preservingOriginal() // blocking the deleting original file. 
                     ->toMediaCollection('images');

                $product->addMedia($image)
                     ->toMediaCollection('images');
                     
}

preservingOriginal Middle Method worked. Thanks.

tuncdogu55's avatar

tuncdogu55 wrote a reply+100 XP

6mos ago

foreach($images as $image){
                $course->addMedia($image)
                    ->preservingOriginal() // blocking the deleting original file. 
                     ->toMediaCollection('images');

                $product->addMedia($image)
                     ->toMediaCollection('images');
                     
}

preservingOriginal Middle Method worked. Thanks.

tuncdogu55's avatar

tuncdogu55 started a new conversation+100 XP

6mos ago

Hello,

I’ve been working with the Spatie Laravel Media Library package and ran into a common problem when trying to attach the same uploaded file to multiple models (for example, both a Course and a Product model).

When I do something like this:

foreach ($images as $image) {
    $course->addMedia($image)->toMediaCollection('images');
    $product->addMedia($image)->toMediaCollection('images');
}

I quickly get the following error:

File ... does not exist in FileDoesNotExist.php

As far as I understand, when you call addMedia($image) with an UploadedFile, Spatie moves the file from PHP’s temporary upload directory to the media library path — meaning the file is no longer available for the second model.

What is your suggestions about that ?