octobercms / october

Self-hosted CMS platform based on the Laravel PHP Framework.
https://octobercms.com/
Other
11.01k stars 2.21k forks source link

Repeater with hasMany relation - Backend #2451

Closed leoquijano closed 7 years ago

leoquijano commented 7 years ago

Hi,

I'm building a backend form with a repeater component. This is the $hasMany entry in the parent model (Plan):

Plugin\Models\Plan class:

public $hasMany       = [
  'trustees' => 'Plugin\Models\PlanTrustee',
];

And this is my YAML field configuration:

    ...
    trustees:
        label: Trustees
        type: repeater
        span: left
        prompt: Add New Trustee
        form:
            fields:
                first_name:
                    label: First Name
                    type: text
                last_name:
                    label: Last Name
                    type: text

However, when I try to open an existing plan, I get N repeater items (as many as there are trustees), but they're all empty. And when a try to create a new plan (in this case with a Foo Bar trustee), I get this error:

SQLSTATE[HY093]: Invalid parameter number: parameter was not defined (SQL: select * from "plan_trustees" where "id" in (Foo, Bar))" on line 662 of /vendor/laravel/framework/src/Illuminate/Database/Connection.php

The database tables are the usual:

Schema::create('plans', function (Blueprint $table) {
  $table->increments('id');
  // ...
});

Schema::create('plan_trustees', function (Blueprint $table) {
  $table->increments('id');
  $table->unsignedInteger('plan_id');
  $table->string("first_name", 50);
  $table->string("last_name", 50);
  $table->timestamps();
  $table->foreign("plan_id")->references("id")->on("plans")->onDelete("cascade");
});

I'm using the following versions of October CMS:

Is this feature working with relations?

Patroklo commented 7 years ago

But... repeaters only affect the form's model and those fields should be jsonable (because the data is saved in that way in your database), in this case what you have to use are relations, I think that's exactly what you need.

About why it's loading the fields but empty, let's say that repeater accepts an array as data, so it loads without error, try to use another type of field instead of repeater in your example and will throw a non array exception.

edit: gonna try a lil trick for using 2 models in 1 form, it may work here!

Patroklo commented 7 years ago

It works!!!! Really it doesn't have much sense, but you can use a SINGLE field from another model in a repeater. It will store all data as JSON (still thinking what you need in this case is a relation, though).

Moar data here, only change the text field for a repeater and will work just fine

leoquijano commented 7 years ago

I had checked relations, but found them to be a bit too complex for that form. I thought repeaters were a simple way to do it. I guess I'll check again.

Patroklo commented 7 years ago

Exactly what do you want to acomplish? Maybe a json field could do the trick.

leoquijano commented 7 years ago

I have a Plan class, that has PlanTrustees (hasMany). So one plan can have N trustees.

Since we only require first & last names from trustees, a simple repeater would just add 2 text fields per trustee, and allow the customer to easily edit them without leaving that form or without using popups or other more complex UI.

Patroklo commented 7 years ago

Yeah, if you are not going to use those names and last names for another purpose it's the most simple way

daftspunk commented 7 years ago

Repeater only supports returning the result as an array at this point. It is possible for you to manipulate that array in something like formBeforeSave() method override in your controller, so it will then populate and associate a related record.

frthjf commented 7 years ago

Hi, I seek to implement a repeater like relation editor as well. Any code examples so far? @draftspunk Are there any plans to support something like this in future versions?

idpsycho commented 6 years ago

Hello, I have built a custom Model Trait HasManyJsonable that fetches hasMany relations into jsonable, and is able to sync the submitted form back into relations. It has a built in validation for repeater models.

It was quite a challenge, but in the end I had to implement those usecases in it:

  1. simple checklist with checklist_item's with hasMany relation, editable as jsonable with repeater
  2. "note" model containing title and description, that can be attached to any model and multiple times, as it is extended with type information, fetched relation becomes jsonable for repeater and then is processed back to relation
  3. multiple models merged together into one huge jsonable, the model type is maintained as _group which is supported by repeater to render multiple form types in one repeater, and it again supports validation and then syncing the data, each _group type to its own relation table

It was quite a challenge, I would like to share this code but as I'm beginner in OctoberCMS the code isn't cleanest. But if anyone is interesting in making it into a shareable plugin, I'd love to share my code and help with refactoring. You can find me at github/idpsycho.