Skip to content

Instantly share code, notes, and snippets.

@intellix
Created July 27, 2013 15:01
Show Gist options
  • Save intellix/6095091 to your computer and use it in GitHub Desktop.
Save intellix/6095091 to your computer and use it in GitHub Desktop.
User wants to send mail to many other users in the game. This validator checks that they all exist within a Doctrine Repository.. based on ObjectExists for Doctrine ZF2 module.
<?php
namespace Application\Validator;
use Zend\Validator\AbstractValidator;
use Zend\Validator\Exception;
use Doctrine\Common\Persistence\ObjectRepository;
use Zend\Stdlib\ArrayUtils;
/**
* Class that validates if all objects exist in a given repository with a field and separator
*
* Example: User wants to send a mail to: 'intellix, non_existant_username'
* Error: 'non_existant_username' does not exist!
*
* @license MIT
* @link http://www.konoro.org/
* @author Dominic Watson <domwatson@live.co.uk>
*/
class ManyObjectsExist extends AbstractValidator
{
/**
* Error constants
*/
const ERROR_NO_OBJECT_FOUND = 'noObjectFound';
const ERROR_NOT_ALL_OBJECTS_FOUND = 'notAllObjectsFound';
/**
* @var array Message templates
*/
protected $messageTemplates = array(
self::ERROR_NO_OBJECT_FOUND => "No object matching '%value%' was found",
self::ERROR_NOT_ALL_OBJECTS_FOUND => "The following objects were not found: %value%"
);
/**
* ObjectRepository from which to search for entities
*
* @var ObjectRepository
*/
protected $objectRepository;
/**
* Fields to be checked
*
* @var string
*/
protected $field;
/**
* String to split provided string up into multiple object searches
* @var string
*/
protected $separator;
/**
* Constructor
*
* @param array $options required keys are `object_repository`, which must be an instance of
* Doctrine\Common\Persistence\ObjectRepository, `field`, with either
* a string or an array of strings representing the fields to be matched by the validator.
* @throws \Zend\Validator\Exception\InvalidArgumentException
*/
public function __construct(array $options)
{
if (!isset($options['object_repository']) || !$options['object_repository'] instanceof ObjectRepository) {
if (!array_key_exists('object_repository', $options)) {
$provided = 'nothing';
} else {
if (is_object($options['object_repository'])) {
$provided = get_class($options['object_repository']);
} else {
$provided = getType($options['object_repository']);
}
}
throw new Exception\InvalidArgumentException(sprintf(
'Option "object_repository" is required and must be an instance of'
. ' Doctrine\Common\Persistence\ObjectRepository, %s given',
$provided
));
}
$this->objectRepository = $options['object_repository'];
if (!isset($options['field'])) {
throw new Exception\InvalidArgumentException(
'Key `field` must be provided and be a field to be used when searching for'
. ' existing instances'
);
}
$this->field = $options['field'];
$this->validateField();
if (!isset($options['separator'])) {
throw new Exception\InvalidArgumentException(
'Key `separator` must be provided and be a string for splitting input into an array for searching for'
. ' existing instances'
);
}
$this->separator = $options['separator'];
parent::__construct($options);
}
/**
* Filters and validates the fields passed to the constructor
*
* @throws \Zend\Validator\Exception\InvalidArgumentException
*/
private function validateField()
{
$field = $this->field;
if (!is_string($field)) {
throw new Exception\InvalidArgumentException(sprintf(
'Provided field must be a string, %s provided for key %s',
gettype($field),
$key
));
}
}
/**
* @param string|array $value a field value or an array of field values if more fields have been configured to be
* matched
* @return array
* @throws \Zend\Validator\Exception\RuntimeException
*/
protected function cleanSearchValue($value)
{
$matchedFieldValue = array();
$field = $this->field;
$separator = $this->separator;
$value = array_filter(array_map('trim', explode($this->separator, $value)));
$matchedFieldValue[$field] = $value;
return $matchedFieldValue;
}
/**
* For returning an array of values provided that weren't found
* within the object repository
* @param array $values clean list of values to search repository
* @param array $matches array of objects returned by repository
* @return array array of values that weren't found in the repository
*/
public function getValuesNotFound($values, $matches)
{
$field = $this->field;
$valuesNotFound = array_flip($values[$field]);
foreach ($matches as $key => $match) {
$fn = 'get' . ucfirst($field);
$value = $match->{$fn}();
if (in_array($value, $valuesNotFound)) {
unset($valuesNotFound[$value]);
}
}
return array_flip($valuesNotFound);
}
/**
* {@inheritDoc}
*/
public function isValid($value)
{
$field = $this->field;
$values = $this->cleanSearchValue($value);
$matches = $this->objectRepository->findBy($values);
if (count($matches) == count($values[$field])) {
return true;
}
$valuesNotFound = $this->getValuesNotFound($values, $matches);
$this->error(self::ERROR_NOT_ALL_OBJECTS_FOUND, implode(', ', $valuesNotFound));
return false;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment