symfony2 embedded collection edit form issue - forms

I have a problem with edititng embedded collection form. I have two object with many-to-one relation. When I create an object "Good" with related "photos" all successfully. When I update the Good object by adding some new photos all works fine too. But, if I try to delete a one photo in some Good object after update photo is not deleted.
Good.php
/**
* #ORM\OneToMany(targetEntity="Photo", mappedBy="good", cascade={"persist", "remove"})
**/
private $photos;
/**
* Add photos
*
* #param \VDKP\Site\BackendBundle\Entity\Photo $photos
* #return Good
*/
public function addPhoto(\VDKP\Site\BackendBundle\Entity\Photo $photos)
{
$photos->setGood($this);
$this->photos->add($photos);
return $this;
}
/**
* Remove photos
*
* #param \VDKP\Site\BackendBundle\Entity\Photo $photos
*/
public function removePhoto(\VDKP\Site\BackendBundle\Entity\Photo $photos)
{
$this->photos->removeElement($photos);
}
/**
* Get photos
*
* #return \Doctrine\Common\Collections\Collection
*/
public function getPhotos()
{
return $this->photos;
}
Photo.php
/**
* #ORM\ManyToOne(targetEntity="Good", inversedBy="photos")
* #ORM\JoinColumn(name="good_id", referencedColumnName="id")
**/
private $good;
GoodController, updateACtion:
public function updateAction(Request $request, $id)
{
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('VDKPSiteBackendBundle:Good')->find($id);
if (!$entity) {
throw $this->createNotFoundException('Unable to find Good entity.');
}
$originalPhotos = new \Doctrine\Common\Collections\ArrayCollection();
foreach ($entity->getPhotos() as $photo) {
$originalPhotos->add($photo);
}
$editForm = $this->createEditForm($entity);
$editForm->handleRequest($request);
if ($editForm->isValid()) {
foreach ($originalPhotos as $photo) {
if (false === $entity->getPhotos()->contains($photo)) {
$photo->setGood(null);
$em->persist($photo);
}
}
$em->persist($entity);
$em->flush();
}
return $this->redirect($this->generateUrl('good_edit', array('id' => $id)));
return array(
'entity' => $entity,
'edit_form' => $editForm->createView(),
'delete_form' => $deleteForm->createView(),
);
}
I did everything as written in the documentation here.
Sorry for my english. Thank you for your help.

It looks like you missed this part of docs:
foreach ($originalTags as $tag) {
if (false === $task->getTags()->contains($tag)) {
// remove the Task from the Tag
$tag->getTasks()->removeElement($task);
// if it was a many-to-one relationship, remove the relationship like this
// $tag->setTask(null);
$em->persist($tag);
// if you wanted to delete the Tag entirely, you can also do that
// $em->remove($tag);
}
}
So, I think you have to do something similar with your data types: Good and Photo.

I think, documentation is inaccurate, because:
In this part of code:
$originalTags = new ArrayCollection();
// Create an ArrayCollection of the current Tag objects in the database
foreach ($task->getTags() as $tag) {
$originalTags->add($tag);
}
we collect Tags, which have relations with current Task in database.
In this part of code:
foreach ($originalTags as $tag) {
if (false === $task->getTags()->contains($tag)) {
// remove the Task from the Tag
$tag->getTasks()->removeElement($task);
// if it was a many-to-one relationship, remove the relationship like this
// $tag->setTask(null);
$em->persist($tag);
// if you wanted to delete the Tag entirely, you can also do that
// $em->remove($tag);
}
}
we must compare $request data and $originalTags array data. But, we compare $originalTags with $task->getTags(), which is essentially the same.

Related

What is the best way to update an Entity whitout form, FosRest

I'm currently build an API with FosRestBundle. I search how can i make a reusable and optimize service for update my entities.
For now, in my controller i get two entites with paramConverter :
/**
* #Rest\Put("/enseignes/{enseigne_id}",
* requirements={"id" = "\d+"})
*#ParamConverter("enseigne", options={"id":"enseigne_id"})
*#ParamConverter("enseigneUpdate",
* converter="fos_rest.request_body")
*
* #Rest\View()
*/
public function updateEnseigneAction(Enseigne $enseigne,Enseigne $enseigneUpdate, ConstraintViolationList $violations)
{
if (count($violations)){
return $this->view($violations,Response::HTTP_BAD_REQUEST);
}
$mapData = $this->get('app.mapdata');
$mapData->mapDataOnEntity($enseigneUpdate,$enseigne);
$em = $this->getDoctrine()->getManager();
$em->flush();
return $enseigne;
}
So, one entity currently in my bdd with id parameter (and check if the id exist ), and another one who is validate with the converter of fosRest. GOOD
My service look like :
class MapData {
private $propertyMetadata;
private $serializer;
function __construct(MetadataFactory $metadataFactory,Serializer $serializer)
{
$this->propertyMetadata = $metadataFactory;
$this->serializer = $serializer;
}
public function mapDataOnEntity($entityUpdate, $targetEntity)
{
if (get_class($entityUpdate) != get_class($targetEntity)){
throw new BadRequestHttpException('Entity doesnt match');
}
$this->fillProperties($targetEntity,$entityUpdate );
}
/**
*
* #param object $targetEntity
* #param object $entityUpdate
*/
protected function fillProperties($targetEntity, $entityUpdate)
{
$propertyAccessor = new PropertyAccessor();
$reflectorTargetEntity = new \ReflectionClass($entityUpdate);
// dump($classAnnotaions);die();
// Recupere les propriétés de targetEntity
$properties = $reflectorTargetEntity->getProperties();
// dump($properties);die();
foreach ($properties as $property){
if ($property->getName() != 'id'){
$newValue = $propertyAccessor->getValue($entityUpdate,$property->getName());
$propertyAccessor->setValue($targetEntity,$property->getName(),$newValue);
}
}
}
}
First :
In the properties of my class i have the properties of relation with other entities and i don't want it !
Second:
How i can use this code for manage the PATCH too ? And what do you think about this solution ?

Symfony forms -- removing an optional one-to-one relationship in an embedded form

I'm trying to use Symfony Forms to edit an existing entity that has a one-to-one relationship with another entity that is optional. I want to make it so that if it receives nothing for the associated entity, it will delete the entity.
Here's the gist of the code I've written:
class AType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('BType', new BType(), ['required' => false]);
}
}
The A entity's association with B:
class A
{
/**
* #ORM\OneToOne(
* targetEntity="B",
* mappedBy="a",
* cascade={"persist", "remove"},
* orphanRemoval=true
* )
* #Assert\Valid()
*/
private $b;
....
When I try binding the form with the data, even though nothing was submitted for B, it'll make validation errors that B's fields are blank, because there is an existing B entity associated with A.
I've also looked at FormEvents, but I have not been able to find a way to fix the problem that way either -- example of what I've tried adding to AType's buildForm:
$builder->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) {
$a = $event->getData();
if($a->getType() != 'Package') {
$a->setB(null);
}
});
Even with this additional code, the errors regarding B are still appearing.
Update:
I think I've gotten closer, but though I can tell it's getting into the new code correctly, the B entity still doesn't ultimately get deleted, I think because despite the $a->setB(null), for $a = $form->getData(); in the controller, $a->getB(); still returns data (i.e. editing the entity in AType's POST_SUBMIT seems to only change that data locally?)
New Code:
$builder->addEventListener(FormEvents::PRE_SUBMIT, function(FormEvent $event) {
$data = $event->getData();
if(!isset($data['B'])) {
$event->getForm()->remove('B');
}
});
$builder->addEventListener(FormEvents::POST_SUBMIT, function(FormEvent $event) {
$a = $event->getData();
if(!$event->getForm()->has('B') && $a->getB()) {
$a->setB(null);
}
});
I'm really at a loss because while $a->setB(null) does not perpetuate to the controller, if I create a property $a->test and set that in the same location, that does perpetuate to the controller.
Update 2
As per comments, I'm adding some code from Entity B and the controller:
class B
{
/**
* #var \A
*
* #ORM\GeneratedValue(strategy="NONE")
* #ORM\OneToOne(targetEntity="A", inversedBy="b", cascade={"persist"})
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="a_id", referencedColumnName="id")
* })
*/
private $a;
As for the controller, it gets more complicated as I'm actually dealing with a 2 deep relation: C hasMany A hasOne B. It's also not using form inputs, but rather formatted json. I'm using http://jmsyst.com/bundles/JMSSerializerBundle/master/installation to serialize the output back into json, as well as a helper function to serialize any error messages.
//Where $c is either a new C entity or an existing C entity to be edited
private function handleForm($c)
{
$json = $this->getJsonFromRequest();
if (false === $json) {
throw new \Exception('Invalid JSON');
}
$form = $this->createForm(new CType(), $c);
$em = $this->getDoctrine()->getEntityManager();
if($form->bind(json_decode($json, true)) && $form->isValid()) {
$c = $form->getData();
...
$em->persist($c);
$em->flush();
$response = new Response($this->getSerializer()->serialize($c, 'json'));
$response->headers->set('Content-Type', 'application/json');
return $response;
} else {
$response = array('code' => 'invalid', 'details' => $this->getErrorMessages($form));
return new JsonResponse($response, 400);
}
}
class C
{
/**
* #ORM\OneToMany(targetEntity="A", mappedBy="c", cascade={"persist", "remove"}, indexBy="id")
* #Assert\Valid()
* #Serializer\Expose
*/
protected $a;
A's relationship to C
/**
* #var \C
*
* #ORM\ManyToOne(targetEntity="C", inversedBy="a")
* #ORM\JoinColumns({
* #ORM\JoinColumn(name="c_id", referencedColumnName="id")
* })
* #Assert\NotBlank
*/
private $c;
And CType
class CType extends AbstractType
{
$builder->add(
'a',
'collection',
array(
'type' => new AType(),
'by_reference' => false,
'allow_add' => true,
'allow_delete' => true
)
);

Force delete doctrine entity when using SoftDeletable by KnpLabs

I'm using SoftDeletable trait in entities from https://github.com/KnpLabs/DoctrineBehaviors/#softDeletable It's working fine, but sometimes I'd like to force delete the entity. How can I do that?
When I use $em->remove($entity), it gets soft-deleted but I need to remove it completely from the database.
I found simple solution. Entity will be softdeleted at first, but if it is already been soft deleted it will be hard deleted so my simple solution was:
$entity->setDeletedAt(new DateTime());
$entityManager->remove($entity);
$entityManager->flush();
Of course you need to disable 'softdelete' filter first and deletedAt is a sofdelete field.
Just remove the subscriber from the EventManager and add it back after the remove() / flush() operation.
// get the event-manager
$eventManager = $this->get('doctrine')->getEventManager();
// get the listener
$subscriber = $this->get('knp.doctrine_behaviors.softdeletable_subscriber');
// remove the the subscriber for all events
$eventManager->removeEventListener($subscriber->getSubscribedEvents(), $subscriber);
// remove the entity
$em->remove($entity);
$em->flush();
// add it back to the event-manager
$eventManager->addEventSubscriber($subscriber);
Since nifr's answer doesn't work anymore in the current version of the behaviors, I had a deeper look at the problem and got to that solution:
$em = $this->getDoctrine()->getManager();
// initiate an array for the removed listeners
$originalEventListeners = array();
// cycle through all registered event listeners
foreach ($em->getEventManager()->getListeners() as $eventName => $listeners) {
foreach ($listeners as $listener) {
if ($listener instanceof Knp\DoctrineBehaviors\ORM\SoftDeletable\SoftDeletableSubscriber) {
// store the event listener, that gets removed
$originalEventListeners[$eventName] = $listener;
// remove the SoftDeletableSubscriber event listener
$em->getEventManager()->removeEventListener($eventName, $listener);
}
}
}
// remove the entity
$em->remove($entity);
$em->flush();
// re-add the removed listener back to the event-manager
foreach ($originalEventListeners as $eventName => $listener) {
$em->getEventManager()->addEventListener($eventName, $listener);
}
See also https://stackoverflow.com/a/22838467/2564552
I have writte a service to disable and reenable the soft delete filter behaviour:
<?php
namespace App\Util;
use Doctrine\ORM\EntityManagerInterface;
use Gedmo\SoftDeleteable\SoftDeleteableListener;
class SoftDeleteFilter
{
/**
* #var string
*/
private $eventName;
/**
* #var object
*/
private $originalEventListener;
/**
* #param EntityManagerInterface $em
*/
public function removeSoftDeleteFilter(EntityManagerInterface $em)
{
foreach ($em->getEventManager()->getListeners() as $eventName => $listeners) {
foreach ($listeners as $listener) {
if ($listener instanceof SoftDeleteableListener) {
if ($eventName === 'onFlush') {
$this->eventName = $eventName;
$this->originalEventListener = $listener;
$em->getEventManager()->removeEventListener($eventName, $listener);
}
}
}
}
}
/**
* #param EntityManagerInterface $em
*/
public function undoRemoveSoftDeleteFilter(EntityManagerInterface $em)
{
if (empty($this->originalEventListener) || empty($this->eventName)) {
throw new \Exception('can not undo remove, soft delete listener was not removed');
}
// re-add the removed listener back to the event-manager
$em->getEventManager()->addEventListener($this->eventName, $this->originalEventListener);
}
}
usage:
$this->softDeleteFilter->removeSoftDeleteFilter($this->entityManager);
$this->entityManager->remove($issue);
$this->entityManager->flush();
$this->softDeleteFilter->undoRemoveSoftDeleteFilter($this->entityManager);

Checkbox field in symfony2

Good morning everyone! Is a form of.
Class ReleasesType:
$builder
->add('doid', 'text')
->add('dourl', 'text')
->add('artists', 'entity', array(
'class' => 'MReleaseCoreBundle:Artists',
'property' => 'name',
'expanded' => true ,
'multiple' => true
));
Сonnection with them one-to-many:
Class 'Artists':
/**
* #ORM\OneToMany(targetEntity="ReleasesArtists" , mappedBy="artists" , cascade={"all"})
* */
private $da;
public function __construct() {
$this->da = new \Doctrine\Common\Collections\ArrayCollection();
}
Class 'ReleasesArtists':
/**
* #ORM\ManyToOne(targetEntity="Releases", inversedBy="da")
* #ORM\JoinColumn(name="releases_id", referencedColumnName="id")
* */
private $releases;
/**
* #ORM\ManyToOne(targetEntity="Artists", inversedBy="da")
* #ORM\JoinColumn(name="artists_id", referencedColumnName="id")
* */
private $artists;
And of course the entity 'Releases':
/**
* #ORM\OneToMany(targetEntity="ReleasesArtists" , mappedBy="releases", cascade={"all"} , orphanRemoval=true)
*/
private $da;
public function getArtists() {
$artists = new ArrayCollection();
foreach($this->da as $p) {
$artists[] = $p->getArtists()->getName();
}
return $artists;
}
public function addDa($da) {
$this->da[] = $da;
}
public function setArtists($artists) {
foreach($artists as $p) {
$po = new \MRelease\CoreBundle\Entity\ReleasesArtists();
$po->setReleases($this);
$po->setArtists($p);
$this->addDa($po);
}
}
Connection is working correctly, all outputs. But does not "checked". In what may be the problem?
Thanks!
Into your controller, where you build and output your form, you have to do something like this
public function myFooAction(Request $request, $releasesId)
{
$repo = $this->getDoctrine()->getManager()->getRepository('YourBundleName:Releases');
$releasesObject = $repo->findOneById($releasesId);
$form = $this->createForm(new ReleasesType(), $releasesObject);
return $this->render('YourBundle::TemplateToRender, array('form'=>$form);
}
What happen here, and why is working?
I've made some assumptions as you don't provide any controller code. First of all, I assume that you have an action like myFooAction() where you do form operation and I suppose, also, that you pass to this action an id for load object from DB and tie it to your form - if I understood correctly your question.
So, first line of action is for retrieve repository for this object. Once you've got repo, you can fetch your object (second line). On third line I use Symfony2 form's facility and "connect" object to his form type: with this, all values contained into this object will be reported into your form (so checkboxes will have correct value). Last line is for render form.
Obviously, your action logic could be different but concept expressed here could be replicated with "different" implementation everywhere.

Idea discussion: dynamic view script switching in zend MVC implementation [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 11 years ago.
This is basically the "Am i doing it right?" question.
I have an idea how i can transparently switch views for default/mobile version/admin areas at run time. And I would like to know what pros and cons you see in this approach.
Main requirements are:
switch entire application with
little to no coding
integrate into zend MVC workflow,
not overwrite it
fallback to default
preserve standard functionality
controllers shouldn't be aware of
changes
Here is my pseudohelper
class Xrks_Controller_Action_Helper_VrExtension extends Zend_Controller_Action_Helper_Abstract
{
public function postDispatch()
{
if(!$this->_shouldRender()) {
return; //just skip
}
try {
$vr = $this->_getViewRenderer();
$backupView = clone $vr->view;
$this->_setBasePaths(); //set base path(s) through ViewRenderer::initView($path)
$oldSpecArray = $this->_setVrPathSpecs(); //set VR view script path specs
$vr->render();
$vr->setNoRender(true); //disable renderer
} catch(Zend_View_Exception $e) { //fallback to default viewscripts if view script file not found
$vr->setView($backupView); //restore view on error
} catch(Exception $e) {
$vr->setView($backupView); //restore view on error
$this->_setVrPathSpecs($oldSpecArray); //restore script path spec
throw $e;
}
$this->_setVrPathSpecs($oldSpecArray);//restore script path spec
}
/**
* Same functionality as ViewRenderer helper _shouldRender method
* #return boolean
*/
protected function _shouldRender();
/**
* #return Zend_Controller_Action_Helper_ViewRenderer
*/
protected function _getViewRenderer();
/**
* Sets viewRenderer path specifications
*
* #param array $spec if NULL uses $this->_viewRendererPathSpecs
* #return array old path spec (0 => pathSpec, 1 => pathNoControllerSpec)
*/
protected function _setVrPathSpecs(array $spec = NULL);
}
How exactly helper should be configured is not important and that part skipped
Here is example how it supposed to work:
$this->_setBasePaths(); sets view base paths to application/views/default/ and application/views/admin/
$this->_setVrPathSpecs(); set path specification to ':module/:controller/:action.:suffix'
so for foo-baz-bar it will search at
1. application/views/admin/scripts/foo/baz/bar.phtml
2. application/views/default/scripts/foo/baz/bar.phtml
if view script not found fall back to default ViewRenderer:
3. application/modules/foo/views/scripts/baz/bar.phtml
Ask questions if I missed something
Upd: After some research i decided to use action helper to autoregister view scriptPaths based on specification for inflector and specified variables. I also modified partial helpers to register scriptPaths if partial from other module requested.
This is crude but working version of action helper:
class Xrks_Controller_Action_Helper_ViewRendererPathstack extends Zend_Controller_Action_Helper_Abstract
{
const PATH_APPEND = 'append';
const PATH_PREPEND = 'prepend';
protected $_enabled = FALSE;
protected $_viewScriptPaths = array();
/**
* By default following vars available: baseDir, area, theme, module
* #var string
*/
protected $_viewScriptPathSpec = ':baseDir/:area/:module';
protected $_defaults = array(
'area' => 'frontend',
'theme' => 'default',
);
protected $_vars = array();
protected $_inflector;
protected $_viewRenderer;
public function __construct($baseDir = NULL)
{
if($baseDir == NULL) {
$baseDir = APPLICATION_PATH . DS . 'views';
}
$this->setDefaultVar('baseDir', $baseDir);
$this->addPath(array());
}
/**
* Enter description here ...
* #return Zend_Controller_Action_Helper_ViewRenderer
*/
protected function _getViewRenderer()
{
if(!$this->_viewRenderer) {
$this->_viewRenderer = Zend_Controller_Action_HelperBroker::getStaticHelper('viewRenderer');
}
return $this->_viewRenderer;
}
/**
* Should the ViewRenderer render a view script?
*
* #return boolean
*/
protected function _shouldRender()
{
$vR = $this->_getViewRenderer();
return (!$this->getFrontController()->getParam('noViewRenderer')
&& !$vR->getNeverRender()
&& !$vR->getNoRender()
&& (null !== $vR->getActionController())
&& $vR->getRequest()->isDispatched()
&& !$vR->getResponse()->isRedirect()
);
}
public function generatePaths(array $vars = array())
{
$this->_registerVarsWithInflector();
$vars = array_merge($this->_defaults, $this->_vars, $vars);
$inflector = $this->getInflector();
$generatedPaths = array();
foreach($this->_viewScriptPaths as $path) {
$pathVars = array_merge($vars, $path);
$generatedPaths[] = $inflector->filter($pathVars);
}
return array_reverse(array_unique(array_reverse($generatedPaths)));//last occurence more important than first
// array('test', 'test2', 'test') => array('test2', 'test')
// #todo rethink this code piece later. must be better solution
}
protected function _registerVarsWithInflector()
{
$vars = array_merge($this->_defaults, $this->_vars);
$inflector = $this->getInflector();
$unregistered = array_keys(array_diff_key($vars, $inflector->getRules()));
sort($unregistered, SORT_DESC);//more specific first (moduleDir prior to module key)
foreach($unregistered as $var) {
$inflector->addFilterRule($var, array('Word_CamelCaseToDash', 'StringToLower'));
}
}
protected function _viewAddScriptPaths(Zend_View_Abstract $view, $paths)
{
foreach ($paths as $path) {
$view->addScriptPath($path);
}
}
/**
* Get inflector
*
* #return Zend_Filter_Inflector
*/
public function getInflector()
{
if (null === $this->_inflector) {
$this->_inflector = new Zend_Filter_Inflector();
$this->_inflector->setThrowTargetExceptionsOn(true);
//setup default rules
$this->_inflector->addRules(array(
':baseDir' => array(),
))
->setTargetReference($this->_viewScriptPathSpec);
}
return $this->_inflector;
}
/**
*
* #return array
*/
public function getPaths()
{
return $this->_basePaths;
}
public function getEnabled()
{
return $this->_enabled;
}
public function setEnabled($flag = TRUE)
{
$this->_enabled = (bool)$flag;
return $this;
}
/**
*
* #todo add check for $pathVars keys and values validity
* #param array $pathVars associative array
* #param string $placement either append or prepend
* #return Xrks_Controller_Action_Helper_ViewRendererPathstack
*/
public function addPath(array $pathVars, $placement = self::PATH_APPEND)
{
if($placement == self::PATH_PREPEND) {
array_unshift($this->_viewScriptPaths, $pathVars);
} else {
$this->_viewScriptPaths[] = $pathVars;
}
return $this;
}
/**
*
* #param array|Zend_Config $paths
* #param string $placement either append or prepend
* #return Xrks_Controller_Action_Helper_ViewRendererPathstack
* #throws Xrks_Exception
*/
public function addPaths($paths, $placement = self::PATH_APPEND)
{
if($paths instanceof Zend_Config) {
$paths = $paths->toArray();
} elseif (!is_array($paths)) {
throw new Xrks_Exception('$paths should be either array or instance of Zend_Config');
}
if($placement == self::PATH_PREPEND) {
$paths = array_reverse($paths);
}
foreach($paths as $path) {
$this->addPath((array)$path, $placement);
}
return $this;
}
/**
*
* #param array $pathVars associative array
* #return Xrks_Controller_Action_Helper_ViewRendererPathstack
*/
public function setPath(array $pathVars)
{
$this->_basePaths = array();
$this->addPath($pathVars);
return $this;
}
/**
*
* #param array|Zend_Config $paths
* #return Xrks_Controller_Action_Helper_ViewRendererPathstack
* #throws Xrks_Exception
*/
public function setPaths($paths)
{
$this->_basePaths = array();
$this->addPaths($paths);
return $this;
}
/**
*
* #param string $varName
* #return string |NULL
*/
public function getDefaultVar($varName)
{
if(key_exists($varName, $this->_defaults)) {
return $this->_defaults[$varName];
}
return NULL;
}
/**
* #param string $varName
* #param string $value
* #return Xrks_Controller_Action_Helper_ViewRendererPathstack Provides fluent interface
*/
public function setDefaultVar($varName, $value)
{
$this->_defaults[$varName] = (string)$value;
return $this;
}
/**
*
* #param string $name
* #return string |NULL
*/
public function getVar($name, $defaults = false)
{
if(key_exists($name, $this->_vars)) {
return $this->_vars[$name];
}
return $defaults ? $this->getDefaultVar($name) : NULL;
}
/**
* #param string $varName
* #param string $value
* #return Xrks_Controller_Action_Helper_ViewRendererPathstack Provides fluent interface
*/
public function setVar($varName, $value)
{
$this->_vars[$varName] = $value;
return $this;
}
public function unsetVar($name)
{
if(key_exists($name, $this->_vars)) {
unset($this->_vars[$name]);
}
return $this;
}
public function postDispatch()
{
if(!$this->getEnabled() || !$this->_shouldRender()) {
return; //just skip
}
try {
$vr = $this->_getViewRenderer();
$this->setVar('module', $vr->getModule());
$paths = $this->generatePaths();
$this->_viewAddScriptPaths($vr->view, $paths);
if(Zend_Registry::isRegistered('Zend_Log')) {
Zend_Registry::get('Zend_Log')
->log($paths, Zend_Log::DEBUG);
}
} catch(Exception $e) {
if(Zend_Registry::isRegistered('Zend_Log')) {
Zend_Registry::get('Zend_Log')
->log($e, Zend_Log::WARN);
}
throw $e;
}
}
}
The way I usually handle this:
I register a Layout Plugin, extending Zend_Layout_Controller_Plugin_Layout
I use the preDispatch hook to determine what module, controller, action I am in
I switch between layouts and views depending on the context
For me, that's by far the easiest method.
GJ