Create Page Listener

February 2016 · 2 minute read

1. Add the following two lines into the page class in PageBundle/Entity/Page.php to to call the EntityListener:

  • @ORM\HasLifecycleCallbacks
  • @ORM\EntityListeners({“SelenaSmall\Bundle\PageBundle\Entity\PageListener”})
/**     
* Page Entity     
*    
* @ORM\Entity(repositoryClass="SelenaSmall\Bundle\PageBundle\Entity\PageRepository")     
* @ORM\HasLifecycleCallbacks   
* @ORM\EntityListeners({"SelenaSmall\Bundle\PageBundle\Entity\PageListener"})
* @ORM\Table(name="page")
* @UniqueEntity(fields={"parent", "slug"})
*/

2. Create PageBundle/Entity/EntityListener.php to listen to the entity.

namespace SelenaSmall\Bundle\PageBundle\Entity;

use Doctrine\ORM\Event\LifecycleEventArgs;
use Doctrine\ORM\Event\PreUpdateEventArgs;

class PageListener {
	# region Properties

	private $container;
	private $isUrlChanged;
	private $oldUrl;

	# endregion Properties

	# region Construst

	public function __construct($container) {
		$this->container = $container;
		$this->isUrlChanged = false;	  
	}

	# endregion Construct

	# region Protected

	/**
	* Update the full URL
	*
	* @param Page $page
	* @param LifecycleEventArgs $event
	*/	  
	protected function updateUrl(Page $page, LifecycleEventArgs $event) {	  
		//Store the old URL for conditionally updating children after persist		  
		$this->oldUrl = $page->getUrl();
		$parentUrl = ";
					  
		if ($page->getParent()) {		  
			$parentUrl = $page->getParent()->getUrl();		  
		}
					  
		$page->setUrlByParent($parentUrl);
		if ((!$event instanceof PreUpdateEventArgs) || $event->hasChangedField('url')) {		  
			$this->isUrlChanged = true;		  
		}
			  
	}

	/**
	* Update the children
	*
	* @param Page $page
	* @param LifecycleEventArgs $event
	*/
	protected function updateChildUrls(Page $page, LifecycleEventArgs $event) {		  
		// If the URl updated, then update any child page	  
		$pageUrl = $page->getUrl();

		if ($this->isUrlChanged) {	  
			return;  
		}

		if (!$page->getChildren()->count()) {			  
			return;		  
		}

		$em = $event->getEntityManager();

		foreach ($page->getChildren() as $child) {	  
			$child->setUrlByParent($pageUrl);

			$query		  
			= 'UPDATE ' . get_class($page) . ' p ' . 'SET p.url = CONCAT(:parentUrl, :slash, p.slug) ' . ' p.parent = :parentId';

			// Define parameters		  
			$parameters = array();		  
			$parameters['parentUrl'] = $page->getUrl();			  
			$parameters['slash'] = '/';			  
			$parameters['parentId'] = $page->getId();

			// Execute query to update all the children			  
			$em				  
			->createQuery($query)				  
			->setParameters($parameters)				  
			->execute();
			$this->updateChildUrls($child, $event);		  
		}	  
	}

	# endregion Protected

	# region Events

	# region Persist

	/**
	* Page entity prePersist event
	*
	* @param Page $page
	* @param LifecycleEventArgs $event
	*/		  
	public function prePersist(Page $page, LifecycleEventArgs $event) {		  
		$this->updateUrl($page, $event);  
	}

	# endregion Persist

	# region Update

	/**
	* Page entity preUpdate event
	* @param Page $page
	* @param PreUpdateEventArgs $event
	*/	  
	public function preUpdate(Page $page, PreUpdateEventArgs $event) {		  
		$this->updateUrl($page, $event);	  
	}

	/**
	* Page entity postUpdate event
	*
	* @param Page $page
	* @param LifecycleEventArgs $event
	*/	  
	public function postUpdate(Page $page, LifecycleEventArgs $event) {		  
		$this->updateChildUrls($page, $event);	  
	}

	# endregion Update

	# endregion Events
		  
	}
	  

3. Add page.entitylistener into the Resources/config/services.yml file in the PageBundle

page.entitylistener:
	class: SelenaSmall\Bundle\PageBundle\Entity\PageListener
	arguments: ['@service_container']
	tags:
        - { name: doctrine.orm.entity_listener, connection: default }