Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OctoberCMS repeater: How to store index/id inside the json array #4056

Closed
nolyboms opened this issue Jan 12, 2019 · 19 comments
Closed

OctoberCMS repeater: How to store index/id inside the json array #4056

nolyboms opened this issue Jan 12, 2019 · 19 comments

Comments

@nolyboms
Copy link

nolyboms commented Jan 12, 2019

Hello everyone,

after 3 days of researching for a way to accomplish my need i thought its best to ask and hope to get an answer.

In this post

#2772 (comment)

it is exactly described what i am trying to do.

I have a repeater in my backend form and the data gets saved in the database as a json like that:

"topics": [
{
    "topic_title": "timeslot 1",
    "topic_description": "timeslot 1 descr",
},
{
    "topic_title": "timeslot 2",
    "topic_description": "timeslot 2 descr",
},

],

What i would like to achieve is that the repeater items get indexed like that:

"topics": [
{	
	"topic_id": "1",
    "topic_title": "topic 1",
    "topic_description": "topic 1 descr",
},
{
	"topic_id": "2",
    "topic_title": "topic 2",
    "topic_description": "topic 2 descr",
},

],

In another github post #2451 (comment) it is stated that this could only be achieved by manipulating the array with

formBeforeSave()

But the information is already available in the code as

$indexCount:

input type="hidden" name="___index_topics[]" value="2"

Can you please tell me how to get index/id into a repeater field so it gets stored inside the json array?

@LukeTowers
Copy link
Contributor

@nolyboms could you please provide more information on why you need the index to be stored? It used to be stored (at least, that's what I remember) but it was removed because it made it overly complex to store that information in two ways.

@nolyboms
Copy link
Author

@LukeTowers thank you for responding.
I am generating an API out of the OctoberCMS Backend which provides all data to be used by an vuejs website.
The API contains all information about different topics.
Each topic in the array needs to be identified with a unique id because the logic of the website allows users to send questions or participate on a survey which are assigned to the topic by its ID.
Hope i explained it well.

@LukeTowers
Copy link
Contributor

@nolyboms hmm. If you have a need for a unique ID you should be using unique records with a RelationController, not a Repeater. The reason for this is that the "id" of a repeater is not unique, it's just an integer describing it's position within the array. If you really must have a unique ID then I recommend you look at adding to the data in formBeforeSave(), perhaps with a hidden guid field instead (and I would recommend a GUID for this if you went that route, not simply an integer).

@nolyboms
Copy link
Author

nolyboms commented Jan 13, 2019

@LukeTowers
If i could get the integer which describes the position to be stored with the array that would be absolutely perfect.

repeater id

Since that was possible in a previous OctoberCMS version - do you have an idea on how to get that info and store it in the array?

@LukeTowers
Copy link
Contributor

That number that you see is just straight CSS, it doesn't exist anywhere else. You'll notice that if you drag and reorder records the numbers stay in the same position even though the item contents are now different. That is why it is a bad idea to use the position of the element as an ID for other purposes.

@nolyboms
Copy link
Author

nolyboms commented Jan 13, 2019

@LukeTowers
I understand. Thank you! It was not clear to me that the number is based on CSS.

We are getting close. :-)

In my controller i am trying to append a value to the json array. But when i add this function to my controller it tries to append the value to a column:

public function formBeforeSave($model) { $model->topics= 'x1'; }

According to the docs i would have to define a accessor which i think is not necessary in my case.

So the question is now:
How to append an additional value to an existing json array in OctoberCMS?

@LukeTowers
Copy link
Contributor

@nolyboms same as you would with any array in general.

public function formBeforeSave($model)
{
    $model->topics = array_map($model->topics, function ($topic) {
         $topic['id'] = uniqid();
    });
}

@nolyboms
Copy link
Author

nolyboms commented Jan 13, 2019

@LukeTowers
I really REALLY appreciate your helping hand!!! THANK YOU!

Adding this to my controller


public function formBeforeSave($model)
    {

        $model->topics = array_map($model->topics, function ($topic) {
         $topic['id'] = uniqid();
        });

     }

throws the error:


 "array_map() expects parameter 1 to be a valid callback, array must have exactly two members"

And when i adjust the function according to a solution provided on stackoverflow to look like this...


public function formBeforeSave($model)
    {

        $model->topics = array_map(array($model, 'topics'), function ($topic) {
         $topic['id'] = uniqid();
        });

     }

I get the error:


 "array_map(): Argument #2 should be an array

Any idea how to make OctoberCMS happy and not throwing errors anymore? :)

@LukeTowers
Copy link
Contributor

Whoops, order of arguments was backwards. array_map(callbackFunction, $inputArray)
do it array_map(function () {}, $model->topics);

@nolyboms
Copy link
Author

My function looks now like this:


 public function formBeforeSave($model)
    {


        $model->timeslots = array_map(function ($timeslot) {
             $timeslot['id'] = uniqid();
             return $timeslot;
        }, $model->timeslots);

        var_dump($model->timeslots); 
    }

The output of var_dump states that the id is been appended but checking the db column and generated API, it seems that the value is not being stored. Very strange. -_-

@LukeTowers
Copy link
Contributor

@nolyboms try attaching to the model's beforeSave event.

@nolyboms
Copy link
Author

Nope. Didn't work. but...

So here is the strange thing which i can not understand:

Repeater Field Name: topics
DB Column: topics

Controller function:

    
$model->topics = array_map(function ($topic) {
    $topic['topic_id'] = uniqid();
	return $topic;
}, $model->topics);

NO TOPIC_ID IS STORED!

Now watch this...

Repeater Field Name: no change
DB: Created another column and called it: themes
Changed function to:

     
$model->themes = array_map(function ($topic) {
    $topic['topic_id'] = uniqid();
	return $topic;
}, $model->themes);

TOPIC_ID is appended to the column themes!

??????

@LukeTowers
Copy link
Contributor

@nolyboms post your model class.

@nolyboms
Copy link
Author

nolyboms commented Jan 14, 2019

sidenote: i have changed the column name and all corresponding assets now from "topics" to "timeslots"

model class:


use Model;

class Events extends Model
{
    use \October\Rain\Database\Traits\Validation;
    
    public $timestamps = false;

    protected $jsonable = [
        'event_manager',
        'event_news',
        'timeslots',
        'apptheme'
    ];

    public $table = 'xxx_xxx_events';

    public $rules = [
    ];

	public $belongsTo = [
        'speaker_id' => [
            'Xxx\Xxx\Models\Speakers',
            'table' => 'acme_xxx_speakers',
        ],
    ];

}

controller:


use Backend\Classes\Controller;
use BackendMenu;

class Events extends Controller
{
    public $implement = [
        'Backend\Behaviors\ListController',
        'Backend\Behaviors\FormController',
        ];
    
    public $listConfig = 'config_list.yaml';
    public $formConfig = 'config_form.yaml';

    public function __construct()
    {
        parent::__construct();
        BackendMenu::setContext('Xxx.Xxx', 'main-menu-item', 'side-menu-item');
    }

    public function formBeforeSave($model)
    {
        $model->timeslots = array_map(function ($meooow) {
             
                $meooow['id'] = uniqid();
                return $meooow;

        }, $model->timeslots);
    }

}    

@LukeTowers
Copy link
Contributor

is it working now?

@nolyboms
Copy link
Author

No. :(

@LukeTowers
Copy link
Contributor

@nolyboms did you try putting the logic in the beforeSave() method on the model? Changing $model to $this instead of course

@nolyboms
Copy link
Author

nolyboms commented Jan 15, 2019

clap

THANK YOU

@nolyboms
Copy link
Author

nolyboms commented Jan 15, 2019

And for anyone in the same situation, here is the solution:

public function beforeSave()
{
    $this->_FieldName_ = array_map(function ($miau) {

        $miau['id'] = uniqid();
        return $miau;

    }, $this->_FieldName_);
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

No branches or pull requests

3 participants