As I've been implementing #2296431: Implement layout plugin type (or get it from somewhere), it's occurred to me that a lot of the code I've written there really belongs in a "renderer" so that it can be swapped out to implement the Panels IPE (or anything else you'd do with a renderer plugin in D7).

However, since we still need to flesh all that out, I don't think there's any problem with implementing that first (and even style plugins per #2296437: Implement style plugin type) and refactor the necessary code into a renderer plugin later.

Comments

dsnopek’s picture

Issue tags: +D8panels
mglaman’s picture

Status: Active » Needs work
StatusFileSize
new3.54 KB

Here's a WIP which defines the annotation plugin and some interfaces. I think the next best step would be to decorate the interface and move from there.

mglaman’s picture

Status: Needs work » Needs review
StatusFileSize
new7.65 KB
new4.55 KB

Here is actually an initial shot - this new patch defines the Standard, Simple, and Editor plugins. It includes an abstract base plugins can extend. The renderer just has a __construct and render() interface requirement. My take on it is that renderers will use internal methods to manipulate the layout plugin, which current handles building its regions and invoking the theme system.

dsnopek’s picture

Status: Needs review » Needs work

@mglaman: Thanks for picking this up! All the boilerplate looks good, this is a good start. :-)

However, I think architecturally the model is inverted. IMO, the Renderer's job is to prepare the content of the regions before they go to the Layout. So, DisplayVariant asks the Renderer to prepare the regions and then passes those regions to the Layout plugin. Whereas the current patch has the Renderer asking the DisplayVariant to render the page. So, we need to flip this around!

This way, the standard (and base) renderer would just apply region and block styles. But the IPE renderer would add the extra markup/Javascript necessary to do the in-place editing. And the editor renderer would add the extra buttons/drop-downs/etc to each region/pane that would be used in Page Manager (theoretically, I'm not sure how we'll actually do this in real life, but this is the general idea).

However, I'm not sure if "before the regions go to the Layout" should mean either (a) before we call $layout->build() or (b) before the layout theme function renders the whole thing. I could see an argument for either one...

Also, and this is a super minor thing:

+++ b/src/Plugin/DisplayRenderer/DisplayRendererBase.php
@@ -0,0 +1,67 @@
+  /**
+   * Render the Panels display.
+   *
+   * This is the outermost method in the Panels render pipeline. It calls the
+   * inner methods, which return a content array, which is in turn passed to the
+   * theme function specified in the layout plugin.
+   *
+   * @return string
+   *   Themed & rendered HTML output.
+   */
+  public function render() {
+    return $this->getDisplay()->build();
+  }

Let's call this function build(). There's a sort of convention in D8 that you call creating a render array building, because the actual rendering is done by later.

Feel free to ping me on IRC if you want to discuss this in a higher-bandwidth way!

saltednut’s picture

StatusFileSize
new10.28 KB
new6.12 KB

This patch addresses the concerns in #4 above, moving the logic around so that DisplayVariant is asking the DisplayRenderer to render the page.

We're now providing the DisplayRenderer the ability to process the regions before the layout, and one chooses renderer (e.g. Standard) when choosing the display variant's layout via the form.

saltednut’s picture

Status: Needs work » Needs review
dsnopek’s picture

Status: Needs review » Needs work

@brantwynn: Thanks, this is looking really good! All my review from #4 is addressed.

Here's some new review! The first several items are quick fix, nit-picky stuff which should be easy to take care of right away. Then the last few items are deeper architectural things that we might need to hammer on for a bit.

  1. +++ b/src/Annotation/DisplayRenderer.php
    @@ -0,0 +1,33 @@
    + * @file
    + * Contains \Drupal\panels\Annotation\DisplayRenderer.php.
    

    Shouldn't have .php

  2. +++ b/src/Annotation/DisplayRenderer.php
    @@ -0,0 +1,33 @@
    +  /**
    +   * The human readable title.
    +   *
    +   * @var string
    +   */
    +  public $title = '';
    

    Let's renamed this to 'label' to match layout plugins

  3. +++ b/src/Plugin/DisplayRenderer/DisplayRendererBase.php
    @@ -0,0 +1,31 @@
    +  /**
    +   * Render the Panels display.
    +   *
    +   * This is the outermost method in the Panels render pipeline. It calls the
    +   * inner methods, which return a content array, which is in turn passed to the
    +   * theme function specified in the layout plugin.
    +   *
    +   * @return string
    +   *   Themed & rendered HTML output.
    +   */
    

    This should just be {@inheritdoc}

  4. +++ b/src/Plugin/DisplayRenderer/DisplayRendererInterface.php
    @@ -0,0 +1,31 @@
    + * @file
    + * Contains \Drupal\panels\Plugin\Renderer\RendererInterface.
    

    Incorrect class name and namespace

  5. +++ b/src/Plugin/DisplayRenderer/DisplayRendererInterface.php
    @@ -0,0 +1,31 @@
    +  /**
    +   * Render the Panels display.
    +   *
    +   * This is the outermost method in the Panels render pipeline. It calls the
    +   * inner methods, which return a content array, which is in turn passed to the
    +   * theme function specified in the layout plugin.
    

    This isn't exactly true for Drupal 8, and needs to be updated, however...

  6. I just took a look at the Drupal 7 renderer plugins, and I think most of the code from PanelsDisplayVariant::buildRegions() needs to get moved into either the standard renderer or the DisplayRendererBase because in Drupal 7 it's actually the renderer that's responsible for constructing the render array out of the list of configured blocks AND for applying the layout In general, I think we need a pass at making sure we're using renders the same way in D8 as we are in D7.
  7. Since we no longer actually "render" anything in the DisplayRenderer, but we just build render arrays, we should actually call this "DisplayBuilder"? That would be similar to "EntityViewBuilder" from core which take an entity and builds a render array.
  8. Now that we have the "editor" renderer, we should use it to render the admin form! This doesn't necessarily need to use a UI like in Drupal 7 (yet) but could just put a table like we using currently inside each region. This would then show the block in the actual layout that will be used!
saltednut’s picture

Status: Needs work » Needs review
StatusFileSize
new12.1 KB
new16.12 KB

This patch addresses points 1 through 6 of comment #7.

Re 7.7: We may need to do some more refactoring, so I didn't rename anything yet.

Re 7.8: I would recommend we file a followup because working on the "editor" is going to be a bigger task that might actually be best served as a meta issue with multiple sub-issues around using it to render the admin form, making it functional, etc.

In this patch, I am also removing the 'simple' renderer until we can figure out why it existed in D7 and whether or not we actually need it in D8.

saltednut’s picture

There were some docblock issues with either missing phpdoc or the wrong declaration for @param looking for ContextAwarePluginInterface instead of the correct ContextHandlerInterface

dsnopek’s picture

StatusFileSize
new20.41 KB
new12.66 KB

@brantwynn: Awesome, thanks! This is looking really great, and I think we're super close. :-)

At the sprint yesterday, @Crell taught me how to inject services into plugins (it is possisble!) so here is a new version of the patch which does that and performs a little clean-up.

The patch is working great in my manual testing!

dsnopek’s picture

Status: Needs review » Needs work

A little more review:

  1. Let's go ahead rename DisplayRenderer to DisplayBuilder! This also means renaming all the docblocks, $render variables to $builder, and so on to make things consistent.
  2. +++ b/src/Plugin/DisplayRenderer/Editor.php
    @@ -0,0 +1,20 @@
    +class Editor extends DisplayRendererBase {
    

    Let's rename this to EditorDisplayBuilder. All the other plugin types repeat the name of the of the plugin in the class name.

  3. +++ b/src/Plugin/DisplayRenderer/Standard.php
    @@ -0,0 +1,134 @@
    +class Standard extends DisplayRendererBase implements ContainerFactoryPluginInterface {
    

    And this to StandardDisplayBuilder

  4. +++ b/src/Plugin/DisplayVariant/PanelsDisplayVariant.php
    @@ -226,6 +198,20 @@ class PanelsDisplayVariant extends VariantBase implements ContextAwareVariantInt
    +      $manager = \Drupal::service('plugin.manager.panels.display_renderer');
    +      $plugins = $manager->getDefinitions();
    

    Oops! This was something I forgot got to do in the last patch. This should use the injected $this->rendererManager (or, actually, $this->builderManager after the rename) rather than calling \Drupal::service() directly.

  5. Can you open a follow-up issue about using the 'editor' builder to build the adminstration form?

Thanks!

dsnopek’s picture

  1. +++ b/src/Plugin/DisplayRenderer/DisplayRendererBase.php
    @@ -0,0 +1,28 @@
    +  public function build(array $regions, array $context, LayoutInterface $layout = null) {
    

    Oh, and it's Drupal coding standards (I think?) to capitalize NULL

  2. +++ b/src/Plugin/DisplayRenderer/DisplayRendererInterface.php
    @@ -0,0 +1,37 @@
    +  public function build(array $regions, array $context, LayoutInterface $layout = null);
    

    Here too!

dsnopek’s picture

Hiding super old patch...

dsnopek’s picture

Title: Implement render plugin type » Implement "display renderer" plugin type (now called "display builder")
Status: Needs work » Needs review
Related issues: +#2553507: Use the 'editor' display builder for admin form
StatusFileSize
new20.37 KB

Here is a new patch that makes all the changes I requested in #11 and #12. No interdiff because this renames all the files.

And here is a new issue to use the 'editor' display builder in the admin interface: #2553507: Use the 'editor' display builder for admin form

saltednut’s picture

This is looking really good from my manual testing. @dsnopek thanks for pushing this through and showing me what was up along the way. Hopefully we can get a maintainer in here to review soon.

tim.plunkett’s picture

+++ b/src/Plugin/DisplayVariant/PanelsDisplayVariant.php
@@ -47,32 +44,39 @@ class PanelsDisplayVariant extends VariantBase implements ContextAwareVariantInt
-  protected $contextHandler;

@@ -97,20 +101,20 @@ class PanelsDisplayVariant extends VariantBase implements ContextAwareVariantInt
-    $this->contextHandler = $context_handler;

This is broken without contextHandler.

saltednut’s picture

In an attempt to return the context handler I am seeing:

Symfony\Component\DependencyInjection\Exception\ServiceNotFoundException: You have requested a non-existent service "plugin.manager.panels.display_builder". in Symfony\Component\DependencyInjection\Container->get() (line 318 of core/vendor/symfony/dependency-injection/Container.php).
Drupal\panels\Plugin\DisplayVariant\PanelsDisplayVariant::create(Object, Array, 'panels_variant', Array)
Drupal\Core\Plugin\Factory\ContainerFactory->createInstance('panels_variant', Array)
Drupal\Component\Plugin\PluginManagerBase->createInstance('panels_variant', Array)
Drupal\Core\Plugin\DefaultLazyPluginCollection->initializePlugin('03abc060-1c7e-4e69-9800-0d783c883753')
Drupal\Component\Plugin\LazyPluginCollection->get('03abc060-1c7e-4e69-9800-0d783c883753')
Drupal\page_manager\Plugin\VariantCollection->get('03abc060-1c7e-4e69-9800-0d783c883753')
Drupal\page_manager\Plugin\VariantCollection->sortHelper('03abc060-1c7e-4e69-9800-0d783c883753', '39bea8b6-0638-4a80-8508-08a7d207a299')
uasort(Array, Array)
Drupal\page_manager\Plugin\VariantCollection->sort()
Drupal\page_manager\Entity\Page->getVariants()
Drupal\page_manager\PageExecutable->selectDisplayVariant()
Drupal\page_manager\Entity\PageViewBuilder->view(Object, 'full', NULL)
Drupal\Core\Entity\Controller\EntityViewController->view(Object, 'full', NULL)
call_user_func_array(Array, Array)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}()
call_user_func_array(Object, Array)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1)
Stack\StackedHttpKernel->handle(Object, 1, 1)
Drupal\Core\DrupalKernel->handle(Object)
saltednut’s picture

I maybe missed some code that was not supposed to be deleted.

tim.plunkett’s picture

Issue tags: +Needs tests

This needs tests, because that was seriously broken

dsnopek’s picture

Thanks @tim.plunkett for tracking this down and @brantwynn for the new patch!

We definitely need tests in Panels in general, and I think it totally makes sense to write some tests for the new display builder code.

I'd be reluctant to write tests for the PanelsDisplayVariant at this point, though, since it still contains copy-pasted code from Page Manager which will be eliminated after we finish moving the necessary code to CTools (per #2511554: [meta] Move some parts of Page Manager into CTools) and then do #2511582: Extend BlockDisplayVariant rather than copying code from Page Manager.

Eventually PanelsDisplayVariant will descend from a variant base class which is basically the same as Page Manager's BlockDisplayVariant (except living in CTools) and we can rely on its tests for all that functionality, and then in Panels we only have to test the bits that we overrode. If we wrote tests for it now, we'd probably just throw them all away once the refactor is finished (or end up copy-pasting tests from Page Manage too - but let's just not do that).

However, this mistake was in PanelsDisplayVariant. :-)

saltednut’s picture

Oh yeah, sorry @tim.plunkett I meant to mention that it was totally broken. I posted #18 because I was stuck. Tests would definitely help.

saltednut’s picture

Status: Needs review » Needs work
mpotter’s picture

StatusFileSize
new18.45 KB

Here is a re-rolled patch against the latest dev. I tested creating a Panels page variant and added a block and it seemed to work, but more testing and eyes are needed. And as mentioned in #19 this definitely needs some tests to be written. Maybe a separate issue for the tests so we can commit this soon since it blocks other work?

phenaproxima’s picture

Status: Needs work » Needs review

Status: Needs review » Needs work

The last submitted patch, 23: panels-renderer-2340999-23.patch, failed testing.

phenaproxima’s picture

StatusFileSize
new17.66 KB

Made some minor style/wording changes...

phenaproxima’s picture

StatusFileSize
new8.35 KB

Er...forgot the interdiff.

phenaproxima’s picture

Status: Needs work » Needs review
Issue tags: -Needs tests
StatusFileSize
new23.97 KB
new8.17 KB

@mpotter's patch was awesome and made it possible to write a simple unit test of StandardDisplayBuilder. Nice.

phenaproxima’s picture

+++ b/src/Plugin/DisplayVariant/PanelsDisplayVariant.php
@@ -30,24 +29,63 @@ use Symfony\Component\DependencyInjection\ContainerInterface;
+   * Constructs a new BlockDisplayVariant.

Just noticed...this should be PanelsDisplayVariant. Can be fixed on commit, though...

phenaproxima’s picture

StatusFileSize
new23.98 KB

Renamed AdminDisplayBuilder back to EditorDisplayBuilder and fixed #29.

dsnopek’s picture

Status: Needs review » Reviewed & tested by the community

Looks good to me! And it worked for me with manual testing. RTBC!

The last submitted patch, 23: panels-renderer-2340999-23.patch, failed testing.

The last submitted patch, 26: 2340999-26.patch, failed testing.

  • japerry committed 5992f57 on 8.x-3.x authored by phenaproxima
    Issue #2340999 by brantwynn, phenaproxima, dsnopek, mglaman, mpotter:...
japerry’s picture

Status: Reviewed & tested by the community » Fixed

Also worked good for me!

Status: Fixed » Closed (fixed)

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