Doctrine + ZF2 tips: Doctrine filters and soft delete

By | 01 November 2012 | Comment


Doctrine 2 filters are a very powerful feature allowing you to easily modify every request sent to the database. This comes in very handy when you need to implement a soft delete filter: a filter which will load only records from database which are not marked as deleted.

With ZF2 dependency injection (DI) support, this is really easy to configure.

Soft delete is when a record is not deleted from the database, but rather just marked as deleted using a boolean field. Doctrine filters provide an easy and secure way to implement this.

As soft delete requires a column to mark records as deleted, you need the relevant entities to implement an interface called SoftDeleteInterface, which defines getters and setters for a field called 'deleted'. This ensures your entity will be consistent with the database model, and also allows the filter to recognise records with soft delete functionality.

You then create a DeletedFilter, which checks entities to see if they have implemented that interface, and if so, filters out any which have been set to deleted (deleted = 1). You can then add this filter to the configuration, which guarantees that only records with deleted=0 can be loaded anywhere in the system.

Why should you do this? Well, the simple answer is that this can increase your website's security: if you give the db user a limited set of permissions (select, insert, update), you can be sure that nobody can drop / delete / truncate content, even by accident.

To implement this, add the following to the module.config.php configuration for Doctrine:

'doctrine' => array(
'configuration' => array(
'orm_default' => array(
'filters' => array(
'soft_delete' => 'Admin\Filter\DeletedFilter'
)
)
),
'driver' => array(........

Then define a filter, similar to one which you can find in the Doctrine documentation. This uses reflection to check if the entity implements the SoftDeleteInterface:
<?php
namespace Admin\Filter;

use Doctrine\ORM\Query\Filter\SQLFilter;
use Doctrine\ORM\Mapping\ClassMetadata;
use Admin\Entity\SoftDeleteInterface;


class DeletedFilter extends SQLFilter
{

/**
* Gets the SQL query part to add to a query.
*
* @return string The constraint SQL if there is available, empty string otherwise
*/
public function addFilterConstraint(ClassMetadata $targetEntity, $targetTableAlias)
{

// Check if the entity implements the SoftDelete interface
if (!in_array("Admin\Entity\SoftDeleteInterface", $targetEntity->reflClass->getInterfaceNames())) {
return "";
}

return $targetTableAlias.'.deleted = '.SoftDeleteInterface::STATUS_NOT_DELETED;
}
}
Finally, the soft delete interface:
<?php

namespace Admin\Entity;

/**
* Interface to support soft delete
*/
Interface SoftDeleteInterface
{
const STATUS_NOT_DELETED = 0;
const STATUS_DELETED = 1;

/**
* @param int $deleted
*/

public function setDeleted($deleted);

public function getDeleted();
}

And last step - you need to enable filter. Add to Module.php:

  public function onBootstrap(MvcEvent $e)    {
  $entityManager = $e->getApplication()->getServiceManager()->get('doctrine.entitymanager.orm_default');
 $filter = $entityManager->getFilters()->enable("soft_delete");
}

Topics: Doctrine PHP ZendFramework ZF2

comments powered by Disqus

Other posts discussing this page