Kunstmaan / KunstmaanBundlesStandardEdition

The "Kunstmaan Bundles Standard Edition" distribution
http://bundles.kunstmaan.be
MIT License
89 stars 39 forks source link

Controllers, routing and dynamic pages. #121

Closed bobemoe closed 9 years ago

bobemoe commented 9 years ago

I'm trying to work out the best way to integrate a standard style controller into the Kunstaamn routing... I think.

What I'm trying to achieve is best explained with the standard /hello/{name}/ route example.

I would like it to show up in the navigation, and be highlighted in the nav when it is the current page. So I think it needs to be created as a new page type (HelloPage) so it can be added as a standard node.

Clicking it in the navigation would take you to /hello/ (or whatever the slug for that page is set to) as normal, however, the route should also match for /hello/bob/ and anything else. {name} should be accessible from the page template, or service function in the page entity.

I have 2 use cases for this so far:

  1. I have an AdminList of entities. I would like a MyEntityPage page type that lists all the entities. No problem, new page type that fetches the list, passes it to the template, loop through, great! Now I would like a page per entity, this is where it gets tricky, I can create my own controller, but that breaks away from the CMS, the template has no navigation etc. I have solved this by having each entity implement the Articles functionality so that it is its own page, therefore has a slug that can be linked to.
  2. We will be pulling in and displaying data from an API feed. We need an ItemsPage page type that we can create multiple instances of. So for e.g. /items/ and /things/ pages. clicking either shows the page as normal, which the controller makes an API call to get the index list. Now, we need to be able to view the individual items, so /items/{id}/ needs to call the same page, but the controller makes a different API call and renders a different template. This one we cant do each item as a separate Page entity as there is a LOT of items, and we don’t know in advance what exists.

So there it is, hope that makes sense. Now I have a couple of ideas for implementing:

  1. My own controller and routing, bypassing the SlugControler, however this then does not allow the template to render as normal as no nodemenu or page etc gets passed to the template. I guess the controller could construct all these, but I wouldn’t know how to begin that!
  2. Create a new page that either accepts a slug with place holders (/hello/{name}/) or has another field to define variable parameters. Would need to modify/extend the SlugController to pull out {variables} and pass them to the entity->service.
  3. I'm hoping I've overlooked something and someone can suggest a better way of going about this? I can't imagine this is the first time someone wants to do this, but I have read the docs and searched the issues with no luck.

Any help greatly appreciated.
Thanks.

bobemoe commented 9 years ago

OK, think I've cracked it.. I've gone down implementation method 1 from above. Using my own controller and a getKumaTemplateVars function that generates the required variables for the template to render in full.

You have to create a blank page in the CMS admin where you set the title, slug, menu position etc, and then you have to pass its URL and locale to the getKumaTemplateVars function to specify it as the active page in the nav/crumbs, but that makes sense.

The code is mainly copied from the SlugAction. I intend to move the function to a service in the end so it is shareable across all of my controllers. Code is below in case anyone wants to do similar.

And thoughts/feedback still welcome. Could this be added as a service to the core bundles somewhere? Maybe it already exists and I can use that instead? Or if anyone would be interested in me publishing my finished service then maybe I could do that.

<?php
namespace Acme\DemoBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;

use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;

use Kunstmaan\AdminBundle\Helper\Security\Acl\Permission\PermissionMap;
use Kunstmaan\NodeBundle\Helper\NodeMenu;

class DefaultController extends Controller
{

    /**
     * @Route("/hello/{name}", name="hello")
     * @Template
     */
    public function indexAction(Request $request, $name){
        return array_merge($this->getKumaTemplateVars('hello','en'),array(
            'name'=>$name
        ));
    }

    public function getKumaTemplateVars($url,$locale){
        $em=$this->getDoctrine()->getManager();
        $nodeTranslation = $em->getRepository('KunstmaanNodeBundle:NodeTranslation')->getNodeTranslationForUrl($url, $locale);

        if (!$nodeTranslation) {
            throw $this->createNotFoundException('No page found for slug ' . $url);
        }

        $node   = $nodeTranslation->getNode();
        $entity = $nodeTranslation->getPublicNodeVersion()->getRef($em);

        $securityContext = $this->get('security.context');
        if (false === $securityContext->isGranted(PermissionMap::PERMISSION_VIEW, $node)) {
            throw new AccessDeniedException('You do not have sufficient rights to access this page.');
        }
        $aclHelper      = $this->container->get('kunstmaan_admin.acl.helper');
        $nodeMenu       = new NodeMenu($em, $securityContext, $aclHelper, $locale, $node, PermissionMap::PERMISSION_VIEW, $includeOffline=false);
        unset($securityContext);
        unset($aclHelper);

        return array(
            'nodetranslation' => $nodeTranslation,
            'slug'            => $url,
            'page'            => $entity,
            'resource'        => $entity,
            'nodemenu'        => $nodeMenu,
        );
    }

}
bobemoe commented 9 years ago

If anyone is interested, this functionality is provided as a service in my KumaBundle: https://github.com/bobemoe/JHodgesKumaBundle

krispypen commented 9 years ago

@bobemoe nice! we are looking at it :)

mtnorthrop commented 9 years ago

Thanks to @bobemoe for posting this solution; I had the same requirements and this really helped me out. It would be great if the core provided an easy way to integrate the CMS/node system with custom controllers. If I could offer something more constructive, I would, but I'm still a noob with the kuma bundles. :-)