Problem/Motivation
When I create an EVA display for a view, and add exposed filters, and then try to view a node with the EVA on it, I get the following errors:
Warning: Illegal string offset 'options' in modules/contrib/eva/src/Plugin/views/display/Eva.php on line 278
Error: Cannot use string offset as an array in Drupal\eva\Plugin\views\display\Eva->getPath() (line 278 of modules/contrib/eva/src/Plugin/views/display/Eva.php).
The full stack trace is:
Drupal\eva\Plugin\views\display\Eva->getPath() (Line: 2020)
Drupal\views\ViewExecutable->getPath() (Line: 1943)
Drupal\views\ViewExecutable->getUrl() (Line: 114)
Drupal\views\Form\ViewsExposedForm->buildForm(Array, Object)
call_user_func_array(Array, Array) (Line: 514)
Drupal\Core\Form\FormBuilder->retrieveForm('views_exposed_form', Object) (Line: 271)
Drupal\Core\Form\FormBuilder->buildForm('views_exposed_form', Object) (Line: 135)
Drupal\views\Plugin\views\exposed_form\ExposedFormPluginBase->renderExposedForm(1) (Line: 115)
eva_entity_view(Array, Object, Object, 'full')
call_user_func_array('eva_entity_view', Array) (Line: 402)
Drupal\Core\Extension\ModuleHandler->invokeAll('entity_view', Array) (Line: 270)
Drupal\Core\Entity\EntityViewBuilder->buildMultiple(Array) (Line: 220)
Drupal\Core\Entity\EntityViewBuilder->build(Array)
call_user_func(Array, Array) (Line: 376)
Drupal\Core\Render\Renderer->doRender(Array, ) (Line: 195)
Drupal\Core\Render\Renderer->render(Array, ) (Line: 226)
Drupal\Core\Render\MainContent\HtmlRenderer->Drupal\Core\Render\MainContent\{closure}() (Line: 574)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 227)
Drupal\Core\Render\MainContent\HtmlRenderer->prepare(Array, Object, Object) (Line: 117)
Drupal\Core\Render\MainContent\HtmlRenderer->renderResponse(Array, Object, Object) (Line: 90)
Drupal\Core\EventSubscriber\MainContentViewSubscriber->onViewRenderArray(Object, 'kernel.view', Object) (Line: 111)
Drupal\Component\EventDispatcher\ContainerAwareEventDispatcher->dispatch('kernel.view', Object) (Line: 149)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 64)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 99)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 78)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 50)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 656)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)
The code in getPath()
reads as follows:
public function getPath() {
if (isset($this->view->current_entity)) {
$uri = $this->view->current_entity->url();
if ($uri) {
$uri['options']['absolute'] = TRUE;
return url($uri['path'], $uri['options']);
}
}
return parent::getPath();
}
The issue is that $this->view->current_entity->url()
returns a string (in my case, the string "/node/2"), but other statements in that function ($uri['options']['absolute']
, $uri['path']
, $uri['options']
) assume it is some kind of array structure. I think this code might not have been ported from D7 properly (potentially relevant change entries: Many methods for generating URLs and links deprecated; EntityInterface::toUrl() and EntityInterface::toLink() added).
Also worth noting: the url() function no longer exists.
Steps to reproduce
Environment:
- Apache/2.2.31 (Unix) mod_wsgi/3.5 Python/2.7.13 PHP/7.0.15 mod_ssl/2.2.31 OpenSSL/1.0.2j DAV/2 mod_fastcgi/2.4.6 mod_perl/2.0.9 Perl/v5.24.0
- PHP: 7.0.15, Memory limit: -1 (Unlimited)
- MySQL 5.6.35
Instructions:
- Clone Drupal core on branch 8.3.x. I am on commit
5d6ea2c5ec
from 2017-05-01. - Clone EVA on branch 8.x-1.x. I am on commit
66a6412
from 2017-03-16. - Install Drupal using the Standard install profile.
- Log in as
/user/1
. - Go to
/admin/structure/views/add
. Enter the following data:- View basic information:
- View name:
Test
- Machine name:
test
- Leave Description unchecked.
- View name:
- View settings:
- Show
Content
of typeArticle
tagged with: (leave blank) sorted by:Newest first
- Show
- Page settings
- Leave Create a page unchecked.
- Block settings
- Leave Create a block unchecked.
- Click Save and edit
- View basic information:
- You are taken to a view edit page. Under Displays, next to Master, click Add, and click EVA.
- Under Entity content settings set:
- Entity type:
Content
. - Bundles:
Basic page
. - Arguments:
Use the ID of the entity the view is attached to
.
- Entity type:
- Next to Filter criteria, click Add. From the Content category, check Title, then click Add and configure filter criteria. Set:
- Check Expose this filter to visitors, to allow them to change it.
- Filter type to expose:
Single filter
- Ensure Required is unchecked.
- Label:
Title
. - Description: (leave empty).
- Operator:
Is equal to
. - Ensure Expose operator is unchecked.
- Value: (leave empty).
- Ensure Remember the last selection is unchecked.
- Administrative title: (leave empty)
- Click Apply.
- Under Displays, next to EVA, click Add, and click Page.
- Under Page settings, set Path =
test
. - Under Displays, click EVA to go back to that display.
- Under Pager, click More link and set:
- Set For =
This entity_view (override)
. - Check Create more link.
- Leave Always display the more link checked.
- Leave More link text =
more
. - Click Apply (this display).
- Set For =
- Click Save on the main view.
- Go to
/admin/structure/types/manage/page/display
. Ensure the EVA is displayed on the Default and/or Full content display modes. - Go to
/node/add/article
. Create an Article. Lorem ipsum text is fine. - Go to
/node/add/page
. Create a Basic page. Lorem ipsum text is fine. - You should end up on the basic page node view page (if you do not, go to
/admin/content
and click the basic page's title to view it). You see the fatal errors mentioned in this issue.
Proposed resolution
To be determined.
Remaining tasks
- Add steps to reproduce on on
8.x-1.x
HEAD - Propose a resolution
- Write a patch
- Review and feedback
- RTBC and feedback
- Commit
User interface changes
Likely none.
API changes
Likely none.
Data model changes
Likely none.
Comment | File | Size | Author |
---|---|---|---|
#7 | 2874662-7-cannot-use-string-offset-as-array.patch | 1.27 KB | mparker17 |
Comments
Comment #2
mparker17Whoops, this is a bug report.
Comment #3
ahebrank CreditAttribution: ahebrank commentedThe deprecated functions aren't really relevant since this is all in the Views namespace, but it's possible that the ViewExecutable::$current_entity (or whatever type of object $this->view is) and its url() method have changed without us noticing. Which D8 is this?
Comment #4
mparker17@ahebrank this is on Drupal 8.3.1.
Comment #5
ahebrank CreditAttribution: ahebrank commentedSorry, my mistake; you're absolutely right that this function didn't get touched after 8.0. Something like this might work? I'm not sure exactly what form the URL out of getPath is supposed to take.
Comment #6
mparker17Added steps to reproduce to the issue summary.
Comment #7
mparker17Oops, forgot to update version to
8.x-1.x-dev
after adding steps to reproduce it on that version.@ahebrank,
getPath()
is defined by\Drupal\views\Plugin\views\display\DisplayPluginInterface::getPath()
, which doesn't specify the return value. However all the implementations I can see in Drupal core return strings, so let's go with that :)Attaching a patch which fixes it both in my test environment (8.3.x / eva-8.x-1.x-dev) and my project environment (8.3.1 / eva-8.x-1.1, where I initially discovered the error).
Feedback welcome!
Comment #8
ahebrank CreditAttribution: ahebrank commentedThanks for this. I haven't yet been able to reproduce the original issue but as soon as I can do that I'll merge and then release a new 1.2 as a hotfix since this is clearly buggy code.
This probably qualifies as a different issue, but when reading through the display code I was wondering whether this approach is still a good way to get the base View path, especially given that entities-within-entities is now a common approach for sitebuilding modularity. For instance, if I attached an Eva to a Paragraph, which was then referenced within a node, I think the Eva would attempt get the (non-existent) canonical Paragraph path when it should be (?) using the parent node path. Would it be better for the hook_entity_view to inject the current path from the routing system (or is that info already in the View executable)?
Comment #9
mparker17@ahebrank if the steps to reproduce in the issue summary aren't working, I could provide either the whole test site configuration, or just the configuration for the view (I prefer steps to reproduce, as they unequivocally prove that there isn't a site-specific configuration issue, but a CMI export can be useful in a pinch).
I think this problem does qualify as a different issue; but I think you're right: the code in the
Eva::getPath()
function looks as if it would return the path to the Paragraph in that case. It might be better to get the path from the routing system.Comment #12
ahebrank CreditAttribution: ahebrank commentedReplicated with instructions above and merged to dev; see PR diff at https://github.com/ahebrank/eva/pull/15/files.
Comment #13
mparker17Awesome! Thanks! :D