Home
NexoPOS

Define Models Dependency

The model dependency ensures a model cannot be deleted if it's still used as a reference on another model. For example, a customer cannot be deleted if he's still attached to an order, and a product cannot be deleted if it's still attached to an order product.

This feature tends to protect the integrity of your data by enforcing the proper deletion of entries to avoid orphan and hidden entries.

Declaring Dependency

The dependency is made by default on each model. You'll use the property "setDependencies" where you'll provide an array with the related class as a key and another array to configure the configuration. Here is an example.

<?php
namespace Modules\YourModules\Models;

use App\Models\NsModel;
use App\Classes\Model;

class Book extends NsModel
{
    public function setDepedencies() {
        return [
            BookChapter::class => Model::dependant(
                local_index: 'id', // the index on Book that will be used as reference
                local_name: 'name', // the attribute that will be used to display the error. e.g "a Storm of Sword cannot be deleted..."
                foreign_index: 'id', // is the relation attribute on the BookChapter class
                foreign_name: 'name', // as for the book, this attribute will be used on the error. e.g "a Storm of Sword cannot be deleted as it's used by Chapter 1"
            )
        ];
    }
}

Using Related Table As Reference

Sometimes, you want to link your dependency to another related table. Let's consider the following scenario. You have a recipe that uses products as ingredients. We have here a middleman table that links the products to the recipe ingredient tables. Typically, that middleman table doesn't have any "name" attribute; therefore, we'll use the name of the related table.

Here is a detailed structure for this example.

Products
-> name: "Tomato"
-> id: 2

Recipe
->name "Hot Tomato"
->id 1

Ingredient
-> product_id: 2
-> recipe_id: 1

Here, we need to create a way to prevent Products from being deleted if it's used as Ingredients, and we need to use the Recipe name to show an error like: "Tomato cannot be deleted as it's a dependency for Hot Tomato".

<?php
namespace Modules\YourModule\Models;

use App\Models\NsModel;
use App\Classes\Model;

class Product extends NsMoels
{
    public function setDependencies()
    {
        return [
            Ingredient::class => Model::dependant(
                local_name: 'name', // local attribute to be used for the error on the Product table
                foreign_index: 'product_id', // the attribute on the Ingredient table, which is the middleman table
                related: Model::related( // we define the attribute here
                    model: Recipe::class, // we link the related model Recipe
                    local_name: 'name', // the attribute to be used for the error.
                    local_index: 'id', // the foreign attribute on Recipe. The value is by default "id"
                    foreign_index: 'recipe_id', // the local attribute on Ingredient                
                )
            );
        ];
    }
}

Prefix For Dependency Name

The error thrown so far pulls the name of the items and displays it as being dependent. However, you might want to give a context to that name. In our previous example, wouldn't it be nice if instead of "Hot Tomato" we could use "Recipe: Hot Tomato"? That's where the "prefix" on the related method is used.

You'll define a named argument "prefix" for a callback function that uses the name of the dependent model as a parameter. From there, you can return any other localized string using that name.

Extending Other Model Dependency

You're not forced to only provide a dependency for your model, but you can provide a custom dependency to other models. For example, a user cannot be deleted if he still has a book that they entered into the system.

For that, in our module, we'll register that dependency as follows:

<?php
namespace Modules\YourModule\Providers;

use Illuminate\Support\Provider as CoreProvider;
use App\Classes\Hook;
use App\Classes\Model;
use App\Models\User;
use Modules\YourModule\Models\Book;

class ServiceProvider extends CoreProvider
{
    public function register()
    {
        Hook::filter( User::method( 'setDependencies' ), function( $dependants ) {
            $dependants[ Book::class ]  =   Model::dependant(
                local_index: 'id',
                local_name: 'name',
                foreign_index: 'user_id',
                foreign_name: 'name'
            );
            
            return $dependants;
        });
    }
}