It's more like an errormessage dismiss request .. for this notice

Notice: Array to string conversion in Drupal\bootstrap\Bootstrap::cssClassFromString() (line 292 of themes/bootstrap/src/Bootstrap.php).

This is caused by Element.php's

if ($value = $this->getProperty('value', $this->getProperty('title'))) {
      $class = "$prefix-" . Bootstrap::cssClassFromString($value, $this->getProperty('button_type', 'default'));
      $this->addClass($class);
      if ($button && $this->getProperty('split')) {
        $this->addClass($class, $this::SPLIT_BUTTON);
      }
    }

As a button can contain a markup array this should be altered to something like

if ($value = $this->getProperty('value', $this->getProperty('title'))) {
      if (is_array($value)) {
           if (array_key_exists('#markup', $value)) {
                $value = $value['#markup'];
           }
           else {
                 $value = implode(" ", $value);
           }
      }
      $class = "$prefix-" . Bootstrap::cssClassFromString($value, $this->getProperty('button_type', 'default'));
      $this->addClass($class);
      if ($button && $this->getProperty('split')) {
        $this->addClass($class, $this::SPLIT_BUTTON);
      }
    }

The same issue with ::glyphiconFromString

Support from Acquia helps fund testing for Drupal Acquia logo

Comments

ytsurk created an issue. See original summary.

ytsurk’s picture

ytsurk’s picture

Version: 7.x-3.x-dev » 8.x-3.x-dev
markhalliwell’s picture

Status: Active » Needs work

I think it makes more sense to check this in the methods that are consuming the passed value instead.

Furthermore, I also think it would be far easier to do something like the following so it encompasses everything (not just #markup):

// Check if provided value is a render array and
// prematurely render to extract string value.
$value = Element::isRenderArray($value) ? Element::create($value)->renderPlain() : $value;
markhalliwell’s picture

Title: get rid of Notice: Array to string conversion - ::cssClassFromString should be called with string argument » Bootstrap::cssClassFromString and Bootstrap::glyphiconFromString cannot handle render arrays

Better title

ytsurk’s picture

Thx for your thoughts.

I also thought of changing it in the consuming methods, but there is an explicit str()-conversion - actually causing the notice.
This somehow made me do it outside ...

The isRenderArray check is awesome !

ytsurk’s picture

OK - here's a complete rewrite of my first patch.

I extended Drupal\bootstrap\Utility\Element with one method called renderOrFlattenValue().
This method is meant to be reusable in all similar places .., so far I found no other.

ytsurk’s picture

somehow missed the file ...

ytsurk’s picture

Status: Needs work » Needs review
ytsurk’s picture

FileSize
2.15 KB

improved: return faster, do not cast strings to string ...

ytsurk’s picture

FileSize
2.13 KB

and another tested one ....

markhalliwell’s picture

Status: Needs review » Needs work

My solution in #4 is all that is needed. A new "flatten" method is unnecessarily verbose. It implements type checking and "optimizations" that are not needed.

ytsurk’s picture

FileSize
1.31 KB

Sorry - my bad .. i was using 8.x-3.0-rc2 and did not find you mentioned methods ..,

here's the patch like I understand your intensions, against the 8.x-3.x-dev branch.

BTW - thank you for all your efforts for this great, alive and real object-oriented theme.

ytsurk’s picture

Status: Needs work » Needs review
markhalliwell’s picture

Status: Needs review » Needs work

I just remembered that renderPlain actually returns an instance of \Drupal\Component\Render\MarkupInterface. So both values will need to be typecast to a string, which we can do like the following:

$string = '' + (Element::isRenderArray($string) ? Element::create($string)->renderPlain() : $string);
markhalliwell’s picture

BTW - thank you for all your efforts for this great, alive and real object-oriented theme.

My pleasure :D

markhalliwell’s picture

We should also change the method signature so it passes the string by reference, e.g. (&$string). That way, if it is a render array, it can set the necessary #printed property when it gets rendered (and doesn't render twice) later.

ytsurk’s picture

Status: Needs work » Needs review
FileSize
2.86 KB

Okey - passing as reference is a great performance enhancement, yes.
I also added the typecasting to string, but I had to use (string), with ''+ I tries to cast it to a int and we have another Notice ?! (wierd..)

markhalliwell’s picture

Status: Needs review » Fixed
FileSize
3.69 KB

Awesome! Thanks @ytsurk, this is definitely on the right track.

I went ahead and made a few tweaks to the patch, mostly around documentation and introducing a new Bootstrap::toString() helper method (since this isn't likely the only place this will need it).

  • markcarver committed 56efe16 on 8.x-3.x authored by ytsurk
    Issue #2820849 by ytsurk, markcarver: Bootstrap::cssClassFromString and...

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.