Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: Introduce a new package to decouple View from MVC #123

Closed
gsteel opened this issue Aug 8, 2022 · 6 comments
Closed

RFC: Introduce a new package to decouple View from MVC #123

gsteel opened this issue Aug 8, 2022 · 6 comments
Labels
Component Proposal Proposal for a new component to be added to Laminas Project, including Mezzio subproject RFC

Comments

@gsteel
Copy link
Member

gsteel commented Aug 8, 2022

laminas-view is currently coupled to laminas-mvc.

As part of the effort to evolve and improve laminas-view, it would be useful to extract the code and features that are only relevant to laminas-mvc into a separate package named something like laminas-mvc-view in a similar vein to mezzio-laminasviewrenderer with the namespace Laminas\Mvc\View.

I have made a start on the package at gsteel/laminas-mvc-view.

Currently, this package contains ServerUrl and Url view helpers that provide BC with their counterparts in laminas-view. The goal would be to eventually move/replace all of the MVC-specific functionality in this package:

  • Any other view helpers specific to MVC
  • The ViewEvent and the main View class/entrypoint
  • The RenderingStrategy framework

Once the package has a stable release, the plan would be to deprecate all the relevant classes in laminas-view in a minor release of the 2.x series, removing them in 3.0.

A minor release of laminas-mvc itself might be of benefit as there is opportunity to move code in the Laminas\Mvc\View namespace to the proposed package.

Whilst this RFC is only relevant to the MVC related code, there are further opportunities to de-couple laminas-view from laminas-navigation and laminas-feed.

I believe that as navigation in inherently "view related", it would be best to move all of the navigation related helpers to the navigation component making view a dependency of navigation.

The Feed renderer and rendering strategy might be co-located with the proposed package, moved to a standalone package or to laminas-feed.

References:

@gsteel gsteel added RFC Component Proposal Proposal for a new component to be added to Laminas Project, including Mezzio subproject labels Aug 8, 2022
@weierophinney
Copy link
Member

I'd focus this on just the bits of laminas-view that you feel are specific to the MVC:

  • clearly the view helpers that have insight into MVC-related things like routing (ServerUrl, Url).
  • any other view helpers that use things like routing, access controllers, etc. I'd like to see a full catalog here, if possible.

The next few pieces are related, and ostensibly MVC-specific:

  • the View class
  • the ViewEvent class
  • rendering strategies

The reason I say ostensibly is because they deal with nested view models and how to render them, and how to select a rendering strategy. The feature exists to allow cobbling together content from a variety of different services, but then rendering it under a single view. It does a depth-first rendering, with each child capturing to a named variable in the parent model; this allows the parent then to use and/or manipulate that content when being rendered.

Because each child can use a different rendering strategy, it also means that you could have, for instance, one child that uses, say, a Twig-based renderer, another that uses a Blad-based renderer, another using a Mustache-based renderer... but then use a laminas-view template to put all that content together. I could potentially even render to JSON in several children, and then consume the JSON in the parent (e.g., looping over objects and rendering them to HTML).

The part I question is if this is something specific to the MVC, or if it's a capability/feature of laminas-view that stands alone.

As for the navigation and fee parts of laminas-view:

  • I think a laminas-view-navigation package would be good for providing bindings between the two. While the laminas-navigation package is primarily consumed via view helpers, in its current state it does not need to be. Pushing the helpers into a separate package would potentially inspire folks to start building navigations for other templating systems using it as the basis.
  • I think that the view-related pieces of laminas-feed would be better served by a laminas-view-feed package; most of the time, consuming laminas-feed does not require a view layer at all (I generally render them directly to a response!).

@gsteel
Copy link
Member Author

gsteel commented Aug 8, 2022

I didn't realise that it was possible to use different rendering strategies per child model - having looked up the relevant tests, this makes sense as not necessarily MVC specific.

Ultimately, the various rendering strategies implement injectResponse to populate the Laminas\Stdlib\ResponseInterface which is what makes it "feel" MVC specific - I guess the question here is whether this feature is used outside of an MVC context in the wild which is very difficult to answer - as you suggest, focussing on the obviously MVC specific helpers makes good sense!

MVC Specific View Helpers

The list of helpers relevant here is quite short:

  • ServerUrl
  • Url
  • BasePath
  • FlashMessenger (Already deprecated for removal in 3.0)

Navigation helper tests do a lot of MVC scaffolding but the purpose of this is currently unclear to me - it's very possible this could be removed with the suggested laminas-view-navigation component.

@froschdesign
Copy link
Member

@weierophinney

  • I think that the view-related pieces of laminas-feed would be better served by a laminas-view-feed package; most of the time, consuming laminas-feed does not require a view layer at all (I generally render them directly to a response!).

The entire functionality for feeds in laminas-view can be completely reduced to a class for creating a response, as it exists in laminas-diactoros.

@gsteel

Navigation helper tests do a lot of MVC scaffolding but the purpose of this is currently unclear to me…

This can be clearly separated from the MVC part. I will help here and I already have something in the pipeline.

@weierophinney
Copy link
Member

  • FlashMessenger (Already deprecated for removal in 3.0)

Yes - this one is already in laminas/laminas-mvc-plugin-flashmessenger. Since it relies on laminas-session and laminas-mvc both (it provides a controller plugin for laminas-mvc and view helpers for laminas-session), it's a "bridge" component.

Ultimately, the various rendering strategies implement injectResponse to populate the Laminas\Stdlib\ResponseInterface which is what makes it "feel" MVC specific - I guess the question here is whether this feature is used outside of an MVC context in the wild which is very difficult to answer - as you suggest, focussing on the obviously MVC specific helpers makes good sense!

The View::render() method conflates things. Internally, it is triggering ViewEvent::EVENT_RESPONSE at the end, which injects the response instance with the results of rendering. This ONLY happens with the root view model; for rendering of children, the results of rendering are returned directly (and then View::renderChildren() uses that return value to seed a variable named after the child in the parent view model... making that result available to the parent when it is rendered).

I guess what we'd need to determine is if this ability to render trees (represented by TreeRendererInterface, and implemented by all but the FeedRenderer) should be part of the core rendering capabilities of laminas-view, or if it is somehow MVC-specific. If it's core, we'd need to keep View around, but we could potentially make the response aspect of it, and the strategies, part of a new component that wraps View.

Off the cuff:

  • In laminas-view:
    • We deprecate the ViewEvent and mark it for removal in v3.
    • We provide a "strategy mapper" that allows providing callbacks that receive a view model, and return null or a rendererer.
    • We deprecate the Strategy classes, and mark them for removal in v3.
    • We create a new RenderedView class, which copies the View class, but:
      • It composes a strategy mapper instead of an event manager.
      • It removes request/response awareness.
      • In render(), it uses the strategy mapper to identify a matching renderer
      • It always returns rendered content (which would be mixed)
  • In laminas-mvc-view:
    • We port over the original ViewEvent
    • We port over the original Strategy classes from laminas-view.
    • We create a strategy mapper implementation that triggers the ViewEvent::EVENT_RENDERER and ViewEvent::EVENT_RENDERER_POST events, returning the matched renderer as injected in the ViewEvent.
    • We create a custom View class that decorates/proxies the laminas-view RenderedView class, and has a render() method that calls the laminas-view RenderedView::render() method and then inspects the model on completion to see if it is a child model or the root model; in the case of a root model, it triggers ViewEvent::EVENT_RESPONSE, and does not return a value (or, rather, returns null).

In laminas-mvc, we'd add the new package as a dependency, and wire the View service to the new package.

This would reduce the number of dependencies we'd need for v3 and retain the tree rendering.

@froschdesign
Copy link
Member

@gsteel
Can we close this?

@gsteel
Copy link
Member Author

gsteel commented Dec 20, 2022

Yes, I think so - further conversation. can be moved to https://github.com/laminas/laminas-mvc-view

@gsteel gsteel closed this as completed Dec 20, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Component Proposal Proposal for a new component to be added to Laminas Project, including Mezzio subproject RFC
Projects
None yet
Development

No branches or pull requests

3 participants