h5pmod: how to add new objects to semantics.json in multichoice?

Forums: 

Hi there

 

while experimenting with the h5pmod on moodle (currently writing my thesis about the h5p developer modes) I've been trying to change some of the properties in semantics.json of h5p.multichoice and to add new objects to that file. 

More precisely, I want to create an overall feedback template, which provides like two score ranges and feedback text lines each. So far, I used the pathfinder and the property adaption like this:

$newoverallFeedback= find_semantics_path('overallFeedback/overallFeedback/overallFeedback', $semantics);

            if (isset($newoverallFeedback)) {           

              $newoverallFeedback->fields = '[

                      {

                        "name": "from",

                        "type": "number",

                        "label": "Score Range",

                        "min": 0,

                        "max": 100,

                        "default": 0,

                        "unit": "%"

                      },

                      {

                        "name": "to",

                        "type": "number",

                        "min": 0,

                        "max": 100,

                        "default": 50,

                        "unit": "%"

                      },

                      {

                        "name": "feedback",

                        "type": "text",

                        "label": "Feedback for defined score range",

                        "importance": "low",

                        "default": "Good start.",

                        "optional": false

                      },

                      {

                        "name": "from2",

                        "type": "number",

                        "min": 0,

                        "max": 100,

                        "default": 51,

                        "unit": "%"

                      },

                      {

                        "name": "to2",

                        "type": "number",

                        "min": 0,

                        "max": 100,

                        "default": 100,

                        "unit": "%"

                      },

                      {

                        "name": "feedback2",

                        "type": "text",

                        "importance": "low",

                        "default": "Good score!",

                        "optional": false

                      }

                   } 

]

            }

          }

       ]

 },';

This example gave me some token errors. 

 

And as a second option I used the array_splice function to replace the entire "overallFeedback"-section with pretty much the same one but double the from, to and feedback-sections within the inner field:

array_splice($semantics, 3, 1, $addField);

In here, I used the entire overall Feedback section as variable addField and the same changes as above. This would simply remove everything below the last section before the feedback semantic. Probably I'm only missing a small point?

 

I hope that my explanations aren't too messy and that someone can give me a hint on how to add new fields/ objects to the json file. Thanks!

 

otacke's picture

Hi Selina!

Are you potentially mixing PHP and JavaScript? The alter semantics hook is part of the PHP based set of hooks and you're not passing an of objects to $newoverallFeedback->fields, but a string that contains JSON notation as you'd use it in JavaScript. Also, the token error rather sounds like you're linter is checking a JavaScript file :-)

You'd want to have something like

    $newoverallFeedback = find_semantics_path('overallFeedback/overallFeedback/overallFeedback', $semantics);
    if (isset($newoverallFeedback)) {
      $newoverallFeedback->fields = [
        (object) [
          'name' => 'from',
          'type' => 'number',
          // and so on
        ],
        (object) [
          'name' => 'to',
          'type' => 'number',
          // and do on
        ],
        // and more ...
      ];
    }

If you do it that way, you will not need array_splice at all, however, because you're first getting the field by find_semantics_path and then writing to it directly. I suppose you wanted to assign the new fields to $addField instead and appent those afterwards. Aaaand finally by using

array_splice($semantics, 3, 1, $addField);

you are assuming that some fields have fixed positions. This will work, but if, for instance, the H5P core team introduced a new block of options before the overall feedback, you'd replace the wrong fields.

Also, looking at your code I assume you are trying to pre-populate the overall feedback with a couple of entries. This will not work.You can change the logical structure of semantics.json using the hooks, but you cannot create parameter instances for lists with it. Good idea though! But in order to achieve this (and make it customizable via overrides), the H5PEditor.TableList widget would need to be improved (accepting an array of values to pre-populate the fields with)

Cheers,
Oliver

Hi Oliver!

Thank you for your very detailed reply. It's helped me a lot because I had in fact mixed up the notations of php and js. Having fixed that I got a result but it still wasn't quite what I was expecting. I meant to add something like a new line to the feedback ranges but so far got all extra objects in the same line. So I'm still struggling to figure out the correct syntax to seperate two feedback range lines from each other but I'll make it work somehow.

However, about the array_splice function, I am aware that it applies to fixed positions. It was only a second attempt to overwrite the structures, since for example the h5pmod template uses an array_shift function to show a first example, therefore my idea was to follow that idea. But actually overwriting by inserting new objects directly to the semantic structure has proven better results. 

Lastly it's really unfortunate that adding some default-values to the text inputs won't work. Have to look into the table-list library then to possibly understand the structure and the accepted attributes.

Thanks again for your explanations!

Regards, Selina   

otacke's picture

Hi Selina!

I meant to add something like a new line to the feedback ranges but so far got all extra objects in the same line.

That's what I figured, and that's what you cannot do by overriding semantics. Please see the last paragraph of my previous answer.

However, about the array_splice function, I am aware that it applies to fixed positions

My comment didn't refer to the use of array_splice, but to using it with fixed numbers as arguments. If you use

array_splice($semantics, 3, 1, $addField);

then you'll replace the 4th field no matter what's at that position. That will work if we have something like

{
  media: ...,
  question: ...,
  answers: ...,
  overallFeedback: ...
}

But what if the H5P core team changed the structure and added some other field on top? Then it could be ...

{
  someOtherField: ...,
  media: ...,
  question: ...,
  answers: ...,
  overallFeedback: ...
}

and you'd be replacing 'answers'. Your override would break until you change that index in your code. It would be better to determine the index of the overallFeedback field and use that index as argument:

array_splice($semantics, $indexOfOverallFeedback, 1, $addField);

if you want to use array_splice and you wouldn't have to worry. Well, unless the structure changes even more and the overallFeedback fields moves somewhere else completely ...

Cheers,
Oliver