String value found, but an array or an object is required

Created on 4 January 2024, 12 months ago
Updated 22 February 2024, 10 months ago

Problem/Motivation

Components that require a nested schema are currently not supported. The storybook server encodes these as escaped JSON strings, which means that json_decode'ing them once is not enough. The error shown looks something like this:

I believe the responsible line in Storybook server is this one.

Steps to reproduce

  1. Create a component that takes a property of type array or object, e.g.
    '$schema': 'https://git.drupalcode.org/project/drupal/-/raw/10.1.x/core/modules/sdc/src/metadata.schema.json'
    name: Landing Page Hero
    status: stable
    props:
      type: object
      properties:
        title:
          type: string
          title: Title
        ctas:
          type: array
          title: CTAs
          items:
            type: object
            items:
              text:
                type: string
                title: Text
              link:
                type: string
                title: Link
    
  2. Create a story for it, populating the nested structure:
    title: Organisms/Landing Page Hero
    argTypes:
      title: 
        name: Title
        type: string
    stories:
      - name: Landing Page Hero
        args:
          title: My Demo Component
          ctas:
            -
              text: "More about us"
              link: '#'
            -
              text: "Buy tickets"
              link: '#'
    
  3. Load the story in Storybook
  4. Notice an error like in the above screenshot

Proposed resolution

json_decode() arguments in case they are not simple strings.

Remaining tasks

  • Create MR
  • Review
  • Merge

User interface changes

None.

API changes

None.

Data model changes

None.

πŸ› Bug report
Status

Needs review

Version

2.0

Component

Code

Created by

πŸ‡³πŸ‡±Netherlands eelkeblok Netherlands πŸ‡³πŸ‡±

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @eelkeblok
  • πŸ‡³πŸ‡±Netherlands eelkeblok Netherlands πŸ‡³πŸ‡±
  • Status changed to Needs review 12 months ago
  • πŸ‡³πŸ‡±Netherlands eelkeblok Netherlands πŸ‡³πŸ‡±
  • πŸ‡―πŸ‡΄Jordan Rajab Natshah Jordan

    Thanks, Eelke, for reporitng and the MR

    Empty arrays, and empty Objects too like empty attrubutes
    Maybe your fix will make sure not to have issues in call cases
    after changes in twig/twig

    Faced issues only with Sotrybook after updates for :

    • Drupal 10.2.0
    • cl_server 2.0.0-beta5
    • @lullabot/storybook-drupal-addon 2.0.6
    Response body: The website encountered an unexpected error. Try again later.<br><br><em class="placeholder">Twig\Error\RuntimeError</em>: The merge filter only works with arrays or &quot;Traversable&quot;, got &quot;string&quot; for argument 2. in <em class="placeholder">twig_array_merge()</em> 
    
    the use of array_merge in Drupal is changing!!

    Drupal 10 is using "twig/twig": "^3.5.0",
    twig/twig 3.8.0 is out and in use for now
    But 3.9.0 will be out and it will have deprecations.

    https://github.com/twigphp/Twig/blob/v3.5.1/src/Extension/CoreExtension....

    /**
     * Merges an array with another one.
     *
     *  {% set items = { 'apple': 'fruit', 'orange': 'fruit' } %}
     *
     *  {% set items = items|merge({ 'peugeot': 'car' }) %}
     *
     *  {# items now contains { 'apple': 'fruit', 'orange': 'fruit', 'peugeot': 'car' } #}
     *
     * @param array|\Traversable $arr1 An array
     * @param array|\Traversable $arr2 An array
     *
     * @return array The merged array
     */
    function twig_array_merge($arr1, $arr2)
    {
        if (!twig_test_iterable($arr1)) {
            throw new RuntimeError(sprintf('The merge filter only works with arrays or "Traversable", got "%s" as first argument.', \gettype($arr1)));
        }
    
        if (!twig_test_iterable($arr2)) {
            throw new RuntimeError(sprintf('The merge filter only works with arrays or "Traversable", got "%s" as second argument.', \gettype($arr2)));
        }
    
        return array_merge(twig_to_array($arr1), twig_to_array($arr2));
    }
    

    Storybook + CL Server having issues passing values and doing twig merge array
    Move functions for CoreExtension

    fabpot committed 3 weeks ago

    https://github.com/twigphp/Twig/blob/v3.8.0/src/Extension/CoreExtension....

    function twig_array_merge(...$arrays)
    {
        $result = [];
    
        foreach ($arrays as $argNumber => $array) {
            if (!is_iterable($array)) {
                throw new RuntimeError(sprintf('The merge filter only works with arrays or "Traversable", got "%s" for argument %d.', \gettype($array), $argNumber + 1));
            }
    
            $result = array_merge($result, twig_to_array($array));
        }
    
        return $result;
    }
    

    πŸ› Fix Storybook issues with Drupal 10.2.0 after cl_server 2.0.0-beta5 and @lullabot/storybook-drupal-addon 2.0.6 Fixed
    Testing changes with empty arrays, or empty objects

  • πŸ‡³πŸ‡±Netherlands eelkeblok Netherlands πŸ‡³πŸ‡±

    My fix for complex values breaks true values for booleans, it appears. Will update to check for that specifically.

  • πŸ‡³πŸ‡±Netherlands eelkeblok Netherlands πŸ‡³πŸ‡±

    Changed.

  • πŸ‡³πŸ‡±Netherlands basvredeling Amsterdam

    I took a similar approach and added this to the end of the ServerEndpointController::getArguments() method:

      private function getArguments(Request $request): array {
        # ...
        # ...
        # ...
        if ($request->getMethod() === 'POST') {      
          $params = $request->getContent();
    
          $params = Json::decode($params);
    
           // Also decode any json encoded parameters.
          foreach ($params as $key => $value) {
            if (is_string($value) && $this->isJson($value)) {
              $params[$key] = Json::decode($value);
            }
          }
          return $params;
        }
    
        return [];
      }
    
      /**
       * Determine if given string is json.
       *
       * @param string $string
       *
       * @return bool
       *
       * @deprecated
       *   Replace with json_validate() after PHP 8.3.
       */
      private function isJson(string $string): bool {
         json_decode($string);
         return json_last_error() === JSON_ERROR_NONE;
      }
    
  • Status changed to RTBC 10 months ago
  • πŸ‡΅πŸ‡ͺPeru marvil07

    @eelkeblok, thanks for reporting this problem, and also providing a solution for it! πŸ‘

    I got into the same problem, and the changes on the MR solved it!

    BTW, both phpstan and phpcs reports that are not passing, are the same as the status on current 2.x branch; in other words no new warnings around those checks has been introduced in this patch.

    Marking as RTBC.

  • heddn Nicaragua

    +1 on landing this.

  • First commit to issue fork.
  • Status changed to Needs review 10 months ago
  • πŸ‡ΊπŸ‡ΈUnited States agentrickard Georgia (US)

    Pushed up code style changes after running phpstan / phpcbf etc.

  • Status changed to RTBC 10 months ago
  • Status changed to Needs review 10 months ago
  • πŸ‡ΊπŸ‡ΈUnited States agentrickard Georgia (US)

    Turns out that you cannot inject the extension list without throwing "Typed property Drupal\cl_server\Theme\ClServerThemeNegotiator::$extensionList must not be accessed before initialization"

  • πŸ‡ΊπŸ‡ΈUnited States agentrickard Georgia (US)

    Sorry. I am bouncing between two docroots to test this. I simply forgot to assign the propery value.

    Fixed again, and required `drush cr`

Production build 0.71.5 2024