Tschallacka
Tschallacka

This took me a while to piece together how it works and all, so here's the guide how to easily put a management form for your relationships within your current form.

For this example i'm going to assume the following:

  • You know how to make a backend form
  • You know how to make a controller
  • You know how to make a model
  • You know how to make the database/schema structure

In this example we are trying to set up a hotel, and a hotel has a lot of facilities.

The facilities have the relationship: belongsTo hotel

public $belongsTo = [
                    'hotel' => [
                         'ExitControl\HotelManager\Models\HotelManagerModel',
                      ],
                 ];

The hotels have the relationship: hasMany facilities

public $hasMany = ['facilities' => [
                       'Tschallacka\HotelManager\Models\HotelFacilityModel',
                            'key' => 'hotel_id'
                        ],
                ];

They are linked togeter by hotel_id in the facilities(foreign key in my setup but that's not required for this to work)

Important to know

When you edit via the form we are going to make it will default save the hotel_id in the facilities table. So there is no need to have a hotel selection form in that form. Even if you include it, any selections you make in there will be blatantly ignored.

Setting fillables

You need to define which fields are fillable in your model. If you do not define these you'll get an error saying something along the line of Mass assignment failed for field 'something youforgot'. If you get this error when trying to save, copy and paste that field name into the fillables.

You need to set the fillable array in the model the "subform" belongs to. In this case HotelFacilityModel needs to have the fields it can save/update fillable.

It's important that you use the "model" field names here. So if you defined a relationship, you need to use the relationship name instead of the database name.

    protected $fillable = ['active','facility'];

In my facilities I have two fields I need to set, if it's active(yes/no) and which facility it is. The hotel entry is missing here because as I stated before, that will be filled automatically.

Making the controller behave

In the HotelController.php we need to add the behaviour RelationController to it. So in the top we add Backend.Behaviors.RelationController to the $implement array.

public $implement = [
        'Backend.Behaviors.FormController',
        'Backend.Behaviors.ListController',
        'Backend.Behaviors.RelationController' // <----
        ];

And we define where we can find our relationship configuration file in the HotelController

   public $relationConfig = 'config_relation.yaml';

Now to create this config_relation.yaml file you go to your \controllers\hotelcontroller directory where also your config_form.yaml resides and all the views for the forms and create there a new file called config_relation.yaml

In it post

facilities:
    label: Facilities
    manage:
        form: $/tschallacka/hotelmanager/models/hotelfacilitymodel/relation_fields.yaml
        list: $/tschallacka/hotelmanager/models/hotelfacilitymodel/relation_columns.yaml
    view:
        list: $/tschallacka/hotelmanager/models/hotelfacilitymodel/relation_columns.yaml
        toolbarButtons: create|delete

For other types of relations read: http://octobercms.com/docs/backend/relations#relationship-types

As you might notice I have defined here relation_fields.yaml and relation_columns.yaml and you might be wondering what these fields are.

These are the exact same fields in your model for building up your form minus the hotel choosing element. So basically copy over fields.yaml and columns.yaml and remove the hotel field and rename them to what you defined here in the config_relation.yaml

Adding the form to your hotel management form

Now go to your PluginName\hotelmanager\hotelmanagermodel folder and open up fields.yaml

facilities:
    label: facilities
    span: left
    type: partial
    tab: tschallacka.hotelmanager::lang.hotelmanagermodel.hotelfacilities
    path: ~/plugins/tschallacka/hotelmanager/controllers/hotelcontroller/_facilities.htm

You might notice we are using a partial here instead of just adding it to the form. This is because we need to call a special piece of php code to actually render the relationship editor we just defined.

Creating the "renderer"

Go back to your hotelcontroller directory where also your config_relation.yaml resides and create a new file _facilities.htm In it put the following code:

 <?= $this->relationRender('facilities'); ?>

Make sure you use here the relationship name you defined in the relation_config.yaml. In this case 'facilities'

And that's it. Now you have a subform in a form.

Important nice details

If you use a seperate database connection than than default OctoberCMS install database you need to copy over the OctoberCMS.deferred_bindings table to your other database for things to work properly.

Last updated

jonathandey
jonathandey

Thanks for this, very helpful indeed!

Whybhagi
Whybhagi

Hello,

How can you pass some data/variable to the subform?

Im trying to pass the form id so as to dynamically set the values of a dropdown in the subform.

wilirius15434
wilirius15434

This is a great tutorial Tschallacka - something that's very relevant to a lot of people I'm sure.

One thing I'm confused about is where it's forcing the hotel entry in the example. It is not forcing anything in the situation where I am using a relationship form and I'm not sure if it's because I'm missing something that is not explicitly stated in the tutorial.

Last updated

Crazymodder
Crazymodder

Thanks for that tutorial:)

zindigo
zindigo

Tschallacka, thanks for the tutorial. When I try to create a model with a hasMany relation, the hasMany relation is created in the database but it does not display in the list view until after I save the parent model. Have you had this problem?

All other relations (besides hasMany) appear in the view upon creating the parent model. It's just the hasMany relations that don't show.

In update of the parent model, all of the hasMany relations are listed as expected. This is quite a problem when you need to enter various data and you don't remember what was already entered.

I am using a separate database so I wonder if this may cause this problem.

Could you or someone please point me in the right direction for how to solve this?

LukeTowers
LukeTowers

@indigo try making a detailed issue report on the Github repository for this and we'll take a look. More detail you can provide the better equipped we are to help you out.

zindigo
zindigo

Thanks, LukeTowers. I'll do that.

hpanic32253
hpanic32253

But what if I have a one-to-one relationship and just want to add a set of fields (subform for the related item) inside the form instead of having a list with add/update buttons on the top?

Whybhagi
Whybhagi

You can use a Dropdown field and set its options dynamically.

goldnetonline
goldnetonline

Bro.

I don't know who you are. I don't know what you do. But what I do have are a very particular set of skills; skills I have acquired over a very long career. I will look for you, I will find you, and I will buy you anything you want.

Thanks

1-11 of 11