Multiple views in MVC-like PHP Frameworks

I so much get this and like it.

Tom, it was mentioned above you had a working framework with possible similar logic in it. Is it true and if yes, can you point us to it?

Scott

I have a framework along these lines I’ve been using for a couple of years on various sites but it’s not quite where I want it to be, however from that I’ve been building a framework from the ground up. I’ll try to put up some code over the next couple of days after I’ve tidied it up a bit.

I had a bit of a stumbling block, I didn’t like the way the templates worked and have always been uneasy about having each route need two templates (one for the layout, one for the content and some way for a controller or something to select the layout) However, I’ve now solved that with transphporm so can get back on track :slight_smile:

No rush from my side. I was just interested in seeing what you have.

Scott

Let’s take a visit to the land of code with a simple example. We want to show the details of a single item.

public function showAction($request)
{
  $itemId = $request->getAttribute('id');

  $item = $this->itemRepository->find($itemId);

  $templateData = ['item' => $item];

  $html = $this->templating->render($this->templateName,$templateData);

  return new Response(200,$html);
}

So we inject a repository (for accessing the database), a templating engine for rendering(could be twig, coulld be php etc) and the name of the actual template file. For each type of item (product, email etc) we define a service and inject the specific dependencies. We then map each route, GET /product/:id:/show to a specific service.

The code seems reusable… Is it tightly coupled? I’ll let you answer that.

It’s also fairly easy to make a editAction in which we inject a form object to allow updating or creating items.

And of course this is a very simple case. Before we can really compare approaches we need to nail down actual use cases.

It’s probably worth having a read through the previous thread if you missed it at the time:

Thanks, @TomB! Based on the mentioned examples, I’d like to ask another question.

Again, in classical MVC, is there one view component per app, while there are many models with controllers? Or does an app consist of bundles, each packaging a model, a view and a controller? Do I misunderstand the concept by seeing the view as the visible user interface rather than a collection of templates that get rendered on demand?

In the context of this thread’s initial question: in $html, how would you access data from outside $this->itemRepository?

The latter, you’ll have multiple MVC triads each consisting of a model, a view and a controller. In some implementations views and controllers can access more than one model.

Generally an application will consist of many views. Each controller will generally have a related view. For example, in a basic CRUD app, you would at minimum have views for:

  • The list of records
  • The form for editing/inserting records

Each template is essentially a view, although it’s important to clarify that a view is just a single representation of some data. As such, the same model and controller can be used with different views which represent the data in different ways. For example, you could take the Album example from above, and have different views for representing the selected album as:

  • HTML
  • PDF
  • JSON
  • MarkDown
  • Etc

Similarly, you can have multiple variants of each (portrait or landscape PDF, for example).

Ouch :sob: Sorry for spamming this discussion :unamused:

I don’t want to open another thread for that, so maybe the one or other could have a quick look on this approach:
https://github.com/thomasgenter/MVC-for-web

Is it worth to follow up on that?

That looks like a good start. If you add the page where someone can view the list of published blogs, or an individual blog, you’ll see where the different controllers/models will be useful.

If you are talking about the sidebar information then within a twig template file you might have a line like:

{{ render(controller('sidebar_action') }}

That basically kicks off a sub-request (GET /sidebar) which in turn kicks off sidebarAction which would have whatever services that the side bar needs to render it’s part of the page.

More details here: http://symfony.com/doc/current/book/templating.html#embedding-controllers

There are other approaches. You can query the database directly from a template if you so chose.

I read it before. My eyes start to glaze over after seemingly endless snippets of code scattered across multiple posts. Give me a link to a code repository with a working app and I’ll be glad to take it for a test drive. High level descriptions are nice but it’s the implementation details that really matter to me.

Unfortunately, at the moment I only have a very rough prototype of the framework that is not much bigger than the bare-bones snippets of code presented mostly by TomB - it only does some simple ‘Hello World’ stuff so I think it’s not enough to bring anything new to the discussion.

However, in the past I used to use the concept partially even in traditional Web ala-MVC - I created a Template Model object that was passed to the templates at all times and when a template needed to render a module it requested its data like this (Smarty):

{include file="modules/module.tpl" products=$model->getRecentProducts()}

modules/module.tpl was the reusable template for rendering the recent products module and it got passed data from the main template, which requested the data from the model object. This worked pretty well.

The problem is that the popular template engines like Smarty or Twig don’t have any built-in tools to create the whole http response so if we wanted to use them we would need to extend them with some convenient methods to do so. Or, get rid of them entirely - which some developers would be willing to do while others not.

Is that really a problem or correct SoC? :wink:

Scott

Maybe not a problem but something that needs a solution. I think either extending the templating system with methods to be able to respond with a full http response, or leave the templating engine as is (creating plain code in string format) and have the View Model construct the http response using the templates as content source. What do you think?

This isn’t a good idea. One of the examples in the last thread was form submissions that can either be submitted via ajax or just via a normal POST. The normal POST request redirects on success, the ajax request returns JSON data containing success/failure and any error messages.

If anything other than the view is handling the headers then you can’t reuse that component for both types of request. In this example, you don’t want the redirect when the response type is JSON (and the request type is ajax)

I’ll have to admit, you lost me again there Tom. But, that is most probably my problem. LOL! :smiley:

Can you give an example of what could be reusable in the View between a response of HTML from a POST request and the response of an AJAX request returning JSON? I am all for reusability. Though. my meager knowledge isn’t allowing me to imagine the possibilities. :smiley:

Scott

Take a look at this post:

Specifically this code for the router:

else if ($_SERVER['REQUEST_URI'] === '/new' && $_SERVER['REQUEST_METHOD'] === 'POST' && $_SERVER['HTTP_X_REQUESTED_WITH'] == 'XmlHttpRequest')  {
	$model = new Model;
	$controller = new CreateController($model);;
    $controller->doAction($_POST);
    $view = new JsonView($model);	
} else if ($_SERVER['REQUEST_URI'] === '/new' && $_SERVER['REQUEST_METHOD'] === 'POST') {
	
	$model = new Model;
	$controller = new CreateController($model);
    $controller->doAction($_POST);
    $view = new View('newThing.html.php', $model);

}

You’ll see it routes slightly differently depending on whether it’s an ajax request, the only difference is the view being used, the same model and controller can deal with all the data processing, all we want from an ajax request is a different output: I want {"success": true} or {"success": false} rather than another HTML page or a redirect.

Essentially you can route to the same controller/model (to handle the same post data and process it). An ajax request should return {"success": true} whereas a non-ajax request will redirect. Putting that redirect in anywhere apart from the view limits the reusability of the code you place it in (in this case, if the redirect happened in the controller, I’d need to write a new controller action and a new view for the ajax/json request and the only real difference would be that the ajax request returns a different response: json rather than a redirect)

Ah, so not view code would be reusable, but rather code in other places like the controller?

Scott

May be I didn’t make myself clear - I wrote View Model but I actually meant something like a View object that is not a part of the templating system but only uses it when appropriate. So technically, it would still be the View sending the headers, only this would not be done in the templates. I was wondering how to get around the limitation of current templating systems, which can construct only string responses. Cram the whole view logic into the templates somehow (for example by additional template functions, etc., to be able to send the headers) or simply split the view into two parts - one responsible for the creation of the complete request (the outer View layer) and the other responsible for creating plain text content (the templates).

This topic was automatically closed 91 days after the last reply. New replies are no longer allowed.