Merge branch '2.2' into 2.3

* 2.2:
  No Entity Manager defined exception
  fixed CS
  [Acl] Fix for issue #9433
  [Validator] fix docblock typos
  [DependencyInjection] removed the unused Reference and Parameter classes use statements from the compiled container class
  Fix mistake in translation's service definition.
  if handler_id is identical to null fix
  CS fix
  Fixed ModelChoiceList tests in Propel1 bridge.
  [AclProvider] Fix incorrect behaviour when partial results returned from cache
  Check if the pipe array is empty before calling stream_select()
  re-factor Propel1 ModelChoiceList
  [Locale] fixed the failing test described in #9455
  [Process] fix phpdoc and timeout of 0
  bug #9445 [BrowserKit] fixed protocol-relative url redirection

Conflicts:
	src/Symfony/Component/BrowserKit/Tests/ClientTest.php
	src/Symfony/Component/Locale/Tests/Stub/StubIntlDateFormatterTest.php
This commit is contained in:
Fabien Potencier 2013-11-23 22:11:41 +01:00
commit dfc54f9e96
28 changed files with 638 additions and 220 deletions

View File

@ -367,4 +367,50 @@ class UniqueValidatorTest extends \PHPUnit_Framework_TestCase
);
$violationsList = $validator->validate($associated);
}
public function testDedicatedEntityManagerNullObject()
{
$uniqueFields = array('name');
$entityManagerName = 'foo';
$registry = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry');
$constraint = new UniqueEntity(array(
'fields' => $uniqueFields,
'em' => $entityManagerName,
));
$uniqueValidator = new UniqueEntityValidator($registry);
$entity = new SingleIntIdEntity(1, null);
$this->setExpectedException(
'Symfony\Component\Validator\Exception\ConstraintDefinitionException',
'Object manager "foo" does not exist.'
);
$uniqueValidator->validate($entity, $constraint);
}
public function testEntityManagerNullObject()
{
$uniqueFields = array('name');
$registry = $this->getMock('Doctrine\Common\Persistence\ManagerRegistry');
$constraint = new UniqueEntity(array(
'fields' => $uniqueFields,
));
$uniqueValidator = new UniqueEntityValidator($registry);
$entity = new SingleIntIdEntity(1, null);
$this->setExpectedException(
'Symfony\Component\Validator\Exception\ConstraintDefinitionException',
'Unable to find the object manager associated with an entity of class "Symfony\Bridge\Doctrine\Tests\Fixtures\SingleIntIdEntity"'
);
$uniqueValidator->validate($entity, $constraint);
}
}

View File

@ -62,8 +62,16 @@ class UniqueEntityValidator extends ConstraintValidator
if ($constraint->em) {
$em = $this->registry->getManager($constraint->em);
if (!$em) {
throw new ConstraintDefinitionException(sprintf('Object manager "%s" does not exist.', $constraint->em));
}
} else {
$em = $this->registry->getManagerForClass(get_class($entity));
if (!$em) {
throw new ConstraintDefinitionException(sprintf('Unable to find the object manager associated with an entity of class "%s".', get_class($entity)));
}
}
$className = $this->context->getClassName();

View File

@ -20,7 +20,7 @@ use Symfony\Component\Form\Extension\Core\ChoiceList\ObjectChoiceList;
use Symfony\Component\PropertyAccess\PropertyAccessorInterface;
/**
* Widely inspired by the EntityChoiceList.
* A choice list for object choices based on Propel model.
*
* @author William Durand <william.durand1@gmail.com>
* @author Toni Uebernickel <tuebernickel@gmail.com>
@ -58,7 +58,7 @@ class ModelChoiceList extends ObjectChoiceList
protected $loaded = false;
/**
* Whether to use the identifier for index generation
* Whether to use the identifier for index generation.
*
* @var Boolean
*/
@ -67,7 +67,7 @@ class ModelChoiceList extends ObjectChoiceList
/**
* Constructor.
*
* @see Symfony\Bridge\Propel1\Form\Type\ModelType How to use the preferred choices.
* @see \Symfony\Bridge\Propel1\Form\Type\ModelType How to use the preferred choices.
*
* @param string $class The FQCN of the model class to be loaded.
* @param string $labelPath A property path pointing to the property used for the choice labels.
@ -86,8 +86,8 @@ class ModelChoiceList extends ObjectChoiceList
$queryClass = $this->class.'Query';
$query = new $queryClass();
$this->identifier = $query->getTableMap()->getPrimaryKeys();
$this->query = $queryObject ?: $query;
$this->identifier = $this->query->getTableMap()->getPrimaryKeys();
$this->loaded = is_array($choices) || $choices instanceof \Traversable;
if ($preferred instanceof ModelCriteria) {
@ -101,7 +101,7 @@ class ModelChoiceList extends ObjectChoiceList
$preferred = array();
}
if (1 === count($this->identifier) && $this->isInteger(current($this->identifier))) {
if (1 === count($this->identifier) && $this->isScalar(current($this->identifier))) {
$this->identifierAsIndex = true;
}
@ -109,7 +109,7 @@ class ModelChoiceList extends ObjectChoiceList
}
/**
* Returns the class name
* Returns the class name of the model.
*
* @return string
*/
@ -119,162 +119,135 @@ class ModelChoiceList extends ObjectChoiceList
}
/**
* Returns the list of model objects
*
* @return array
*
* @see Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface
* {@inheritdoc}
*/
public function getChoices()
{
if (!$this->loaded) {
$this->load();
}
$this->load();
return parent::getChoices();
}
/**
* Returns the values for the model objects
*
* @return array
*
* @see Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface
* {@inheritdoc}
*/
public function getValues()
{
if (!$this->loaded) {
$this->load();
}
$this->load();
return parent::getValues();
}
/**
* Returns the choice views of the preferred choices as nested array with
* the choice groups as top-level keys.
*
* @return array
*
* @see Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface
* {@inheritdoc}
*/
public function getPreferredViews()
{
if (!$this->loaded) {
$this->load();
}
$this->load();
return parent::getPreferredViews();
}
/**
* Returns the choice views of the choices that are not preferred as nested
* array with the choice groups as top-level keys.
*
* @return array
*
* @see Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface
* {@inheritdoc}
*/
public function getRemainingViews()
{
if (!$this->loaded) {
$this->load();
}
$this->load();
return parent::getRemainingViews();
}
/**
* Returns the model objects corresponding to the given values.
*
* @param array $values
*
* @return array
*
* @see Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface
* {@inheritdoc}
*/
public function getChoicesForValues(array $values)
{
if (empty($values)) {
return array();
}
/**
* This performance optimization reflects a common scenario:
* * A simple select of a model entry.
* * The choice option "expanded" is set to false.
* * The current request is the submission of the selected value.
*
* @see \Symfony\Component\Form\Extension\Core\DataTransformer\ChoicesToValuesTransformer::reverseTransform
* @see \Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToValueTransformer::reverseTransform
*/
if (!$this->loaded) {
if (1 === count($this->identifier)) {
$filterBy = 'filterBy'.current($this->identifier)->getPhpName();
return (array) $this->query->create()
// The initial query is cloned, so all additional filters are applied correctly.
$query = clone $this->query;
$result = (array) $query
->$filterBy($values)
->find();
}
$this->load();
// Preserve the keys as provided by the values.
$models = array();
foreach ($values as $index => $value) {
foreach ($result as $eachModel) {
if ($value === $this->createValue($eachModel)) {
// Make sure to convert to the right format
$models[$index] = $this->fixChoice($eachModel);
// If all values have been assigned, skip further loops.
unset($values[$index]);
if (0 === count($values)) {
break 2;
}
}
}
}
return $models;
}
}
$this->load();
return parent::getChoicesForValues($values);
}
/**
* Returns the values corresponding to the given model objects.
*
* @param array $models
*
* @return array
*
* @see Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface
* {@inheritdoc}
*/
public function getValuesForChoices(array $models)
{
if (!$this->loaded) {
// Optimize performance for single-field identifiers. We already
// know that the IDs are used as values
if (empty($models)) {
return array();
}
// Attention: This optimization does not check choices for existence
if (!$this->loaded) {
/**
* This performance optimization assumes the validation of the respective values will be done by other means.
*
* It correlates with the performance optimization in {@link ModelChoiceList::getChoicesForValues()}
* as it won't load the actual entries from the database.
*
* @see \Symfony\Component\Form\Extension\Core\DataTransformer\ChoicesToValuesTransformer::transform
* @see \Symfony\Component\Form\Extension\Core\DataTransformer\ChoiceToValueTransformer::transform
*/
if (1 === count($this->identifier)) {
$values = array();
foreach ($models as $model) {
foreach ($models as $index => $model) {
if ($model instanceof $this->class) {
// Make sure to convert to the right format
$values[] = $this->fixValue(current($this->getIdentifierValues($model)));
$values[$index] = $this->fixValue(current($this->getIdentifierValues($model)));
}
}
return $values;
}
$this->load();
}
return parent::getValuesForChoices($models);
}
$this->load();
/**
* Returns the indices corresponding to the given models.
*
* @param array $models
*
* @return array
*
* @see Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface
*/
public function getIndicesForChoices(array $models)
{
$indices = array();
if (!$this->loaded) {
// Optimize performance for single-field identifiers. We already
// know that the IDs are used as indices
// Attention: This optimization does not check choices for existence
if ($this->identifierAsIndex) {
foreach ($models as $model) {
if ($model instanceof $this->class) {
// Make sure to convert to the right format
$indices[] = $this->fixIndex(current($this->getIdentifierValues($model)));
}
}
return $indices;
}
$this->load();
}
$values = array();
$availableValues = $this->getValues();
/*
* Overwriting default implementation.
@ -286,12 +259,61 @@ class ModelChoiceList extends ObjectChoiceList
* The choicelist will retrieve the list of available related models with a different query, resulting in different objects.
*/
$choices = $this->fixChoices($models);
foreach ($this->getChoices() as $i => $choice) {
foreach ($choices as $j => $givenChoice) {
if (null !== $givenChoice && $this->getIdentifierValues($choice) === $this->getIdentifierValues($givenChoice)) {
$indices[] = $i;
unset($choices[$j]);
foreach ($choices as $i => $givenChoice) {
if (null === $givenChoice) {
continue;
}
foreach ($this->getChoices() as $j => $choice) {
if ($this->isEqual($choice, $givenChoice)) {
$values[$i] = $availableValues[$j];
// If all choices have been assigned, skip further loops.
unset($choices[$i]);
if (0 === count($choices)) {
break 2;
}
}
}
}
return $values;
}
/**
* {@inheritdoc}
*/
public function getIndicesForChoices(array $models)
{
if (empty($models)) {
return array();
}
$this->load();
$indices = array();
/*
* Overwriting default implementation.
*
* The two objects may represent the same entry in the database,
* but if they originated from different queries, there are not the same object within the code.
*
* This happens when using m:n relations with either sides model as data_class of the form.
* The choicelist will retrieve the list of available related models with a different query, resulting in different objects.
*/
$choices = $this->fixChoices($models);
foreach ($choices as $i => $givenChoice) {
if (null === $givenChoice) {
continue;
}
foreach ($this->getChoices() as $j => $choice) {
if ($this->isEqual($choice, $givenChoice)) {
$indices[$i] = $j;
// If all choices have been assigned, skip further loops.
unset($choices[$i]);
if (0 === count($choices)) {
break 2;
}
@ -303,28 +325,16 @@ class ModelChoiceList extends ObjectChoiceList
}
/**
* Returns the models corresponding to the given values.
*
* @param array $values
*
* @return array
*
* @see Symfony\Component\Form\Extension\Core\ChoiceList\ChoiceListInterface
* {@inheritdoc}
*/
public function getIndicesForValues(array $values)
{
if (!$this->loaded) {
// Optimize performance for single-field identifiers. We already
// know that the IDs are used as indices and values
// Attention: This optimization does not check values for existence
if ($this->identifierAsIndex) {
return $this->fixIndices($values);
}
$this->load();
if (empty($values)) {
return array();
}
$this->load();
return parent::getIndicesForValues($values);
}
@ -362,7 +372,7 @@ class ModelChoiceList extends ObjectChoiceList
*/
protected function createValue($model)
{
if (1 === count($this->identifier)) {
if ($this->identifierAsIndex) {
return (string) current($this->getIdentifierValues($model));
}
@ -370,10 +380,16 @@ class ModelChoiceList extends ObjectChoiceList
}
/**
* Loads the list with model objects.
* Loads the complete choice list entries, once.
*
* If data has been loaded the choice list is initialized with the retrieved data.
*/
private function load()
{
if ($this->loaded) {
return;
}
$models = (array) $this->query->find();
$preferred = array();
@ -384,15 +400,15 @@ class ModelChoiceList extends ObjectChoiceList
try {
// The second parameter $labels is ignored by ObjectChoiceList
parent::initialize($models, array(), $preferred);
$this->loaded = true;
} catch (StringCastException $e) {
throw new StringCastException(str_replace('argument $labelPath', 'option "property"', $e->getMessage()), null, $e);
}
$this->loaded = true;
}
/**
* Returns the values of the identifier fields of an model
* Returns the values of the identifier fields of a model.
*
* Propel must know about this model, that is, the model must already
* be persisted or added to the idmodel map before. Otherwise an
@ -404,6 +420,10 @@ class ModelChoiceList extends ObjectChoiceList
*/
private function getIdentifierValues($model)
{
if (!$model instanceof $this->class) {
return array();
}
if ($model instanceof Persistent) {
return array($model->getPrimaryKey());
}
@ -413,7 +433,7 @@ class ModelChoiceList extends ObjectChoiceList
return array($model->getPrimaryKey());
}
if (null === $model) {
if (!method_exists($model, 'getPrimaryKeys')) {
return array();
}
@ -421,14 +441,39 @@ class ModelChoiceList extends ObjectChoiceList
}
/**
* Whether this column in an integer
* Whether this column contains scalar values (to be used as indices).
*
* @param \ColumnMap $column
*
* @return Boolean
*/
private function isInteger(\ColumnMap $column)
private function isScalar(\ColumnMap $column)
{
return $column->getPdoType() === \PDO::PARAM_INT;
return in_array($column->getPdoType(), array(
\PDO::PARAM_BOOL,
\PDO::PARAM_INT,
\PDO::PARAM_STR,
));
}
/**
* Check the given choices for equality.
*
* @param mixed $choice
* @param mixed $givenChoice
*
* @return Boolean
*/
private function isEqual($choice, $givenChoice)
{
if ($choice === $givenChoice) {
return true;
}
if ($this->getIdentifierValues($choice) === $this->getIdentifierValues($givenChoice)) {
return true;
}
return false;
}
}

View File

@ -20,12 +20,20 @@ class ItemQuery
'is_active' => \PropelColumnTypes::BOOLEAN,
'enabled' => \PropelColumnTypes::BOOLEAN_EMU,
'updated_at' => \PropelColumnTypes::TIMESTAMP,
'updated_at' => \PropelColumnTypes::TIMESTAMP,
'updated_at' => \PropelColumnTypes::TIMESTAMP,
'updated_at' => \PropelColumnTypes::TIMESTAMP,
);
public static $result = array();
public function find()
{
return self::$result;
}
public function filterById($id)
{
return $this;
}
public function getTableMap()
{
// Allows to define methods in this class
@ -37,6 +45,7 @@ class ItemQuery
{
$cm = new \ColumnMap('id', new \TableMap());
$cm->setType('INTEGER');
$cm->setPhpName('Id');
return array('id' => $cm);
}

View File

@ -0,0 +1,135 @@
<?php
namespace Symfony\Bridge\Propel1\Tests\Form\ChoiceList;
use Symfony\Bridge\Propel1\Form\ChoiceList\ModelChoiceList;
use Symfony\Bridge\Propel1\Tests\Fixtures\Item;
use Symfony\Bridge\Propel1\Tests\Fixtures\ItemQuery;
use Symfony\Component\Form\Tests\Extension\Core\ChoiceList\AbstractChoiceListTest;
class CompatModelChoiceListTest extends AbstractChoiceListTest
{
const ITEM_CLASS = '\Symfony\Bridge\Propel1\Tests\Fixtures\Item';
/**
* @var \PHPUnit_Framework_MockObject_MockObject|\Symfony\Bridge\Propel1\Tests\Fixtures\ItemQuery
*/
protected $query;
protected $item1;
protected $item2;
protected $item3;
protected $item4;
public static function setUpBeforeClass()
{
if (!class_exists('\Propel')) {
self::markTestSkipped('Propel is not available.');
}
if (!class_exists('Symfony\Component\Form\Form')) {
self::markTestSkipped('The "Form" component is not available');
}
if (!class_exists('Symfony\Component\PropertyAccess\PropertyAccessor')) {
self::markTestSkipped('The "PropertyAccessor" component is not available');
}
parent::setUpBeforeClass();
}
public function testGetChoicesForValues()
{
$this->query
->expects($this->once())
->method('filterById')
->with(array(1, 2))
->will($this->returnSelf())
;
ItemQuery::$result = array(
$this->item2,
$this->item1,
);
parent::testGetChoicesForValues();
}
protected function setUp()
{
$this->query = $this->getMock('Symfony\Bridge\Propel1\Tests\Fixtures\ItemQuery', array(
'filterById',
), array(), '', true, true, true, false, true);
$this->query
->expects($this->any())
->method('filterById')
->with($this->anything())
->will($this->returnSelf())
;
$this->createItems();
ItemQuery::$result = array(
$this->item1,
$this->item2,
$this->item3,
$this->item4,
);
parent::setUp();
}
protected function createItems()
{
$this->item1 = new Item(1, 'Foo');
$this->item2 = new Item(2, 'Bar');
$this->item3 = new Item(3, 'Baz');
$this->item4 = new Item(4, 'Cuz');
}
protected function createChoiceList()
{
return new ModelChoiceList(self::ITEM_CLASS, 'value', null, $this->query);
}
protected function getChoices()
{
return array(
1 => $this->item1,
2 => $this->item2,
3 => $this->item3,
4 => $this->item4,
);
}
protected function getLabels()
{
return array(
1 => 'Foo',
2 => 'Bar',
3 => 'Baz',
4 => 'Cuz',
);
}
protected function getValues()
{
return array(
1 => '1',
2 => '2',
3 => '3',
4 => '4',
);
}
protected function getIndices()
{
return array(
1,
2,
3,
4,
);
}
}

View File

@ -12,26 +12,34 @@
namespace Symfony\Bridge\Propel1\Tests\Form\ChoiceList;
use Symfony\Bridge\Propel1\Form\ChoiceList\ModelChoiceList;
use Symfony\Component\Form\Extension\Core\View\ChoiceView;
use Symfony\Bridge\Propel1\Tests\Fixtures\Item;
use Symfony\Bridge\Propel1\Tests\Fixtures\ReadOnlyItem;
use Symfony\Bridge\Propel1\Tests\Propel1TestCase;
use Symfony\Bridge\Propel1\Tests\Fixtures\Item;
use Symfony\Bridge\Propel1\Tests\Fixtures\ItemQuery;
use Symfony\Bridge\Propel1\Tests\Fixtures\ReadOnlyItem;
use Symfony\Component\Form\Extension\Core\View\ChoiceView;
class ModelChoiceListTest extends Propel1TestCase
{
const ITEM_CLASS = '\Symfony\Bridge\Propel1\Tests\Fixtures\Item';
protected function setUp()
public static function setUpBeforeClass()
{
parent::setUpBeforeClass();
if (!class_exists('Symfony\Component\Form\Form')) {
$this->markTestSkipped('The "Form" component is not available');
self::markTestSkipped('The "Form" component is not available');
}
if (!class_exists('Symfony\Component\PropertyAccess\PropertyAccessor')) {
$this->markTestSkipped('The "PropertyAccessor" component is not available');
self::markTestSkipped('The "PropertyAccessor" component is not available');
}
}
protected function setUp()
{
ItemQuery::$result = array();
}
public function testEmptyChoicesReturnsEmpty()
{
$choiceList = new ModelChoiceList(
@ -173,6 +181,11 @@ class ModelChoiceListTest extends Propel1TestCase
$item1 = new Item(1, 'Foo');
$item2 = new Item(2, 'Bar');
ItemQuery::$result = array(
$item1,
$item2,
);
$choiceList = new ModelChoiceList(
self::ITEM_CLASS,
'value',
@ -189,6 +202,11 @@ class ModelChoiceListTest extends Propel1TestCase
public function testDifferentEqualObjectsAreChoosen()
{
$item = new Item(1, 'Foo');
ItemQuery::$result = array(
$item,
);
$choiceList = new ModelChoiceList(
self::ITEM_CLASS,
'value',
@ -198,6 +216,7 @@ class ModelChoiceListTest extends Propel1TestCase
$choosenItem = new Item(1, 'Foo');
$this->assertEquals(array(1), $choiceList->getIndicesForChoices(array($choosenItem)));
$this->assertEquals(array('1'), $choiceList->getValuesForChoices(array($choosenItem)));
}
public function testGetIndicesForNullChoices()
@ -211,4 +230,17 @@ class ModelChoiceListTest extends Propel1TestCase
$this->assertEquals(array(), $choiceList->getIndicesForChoices(array(null)));
}
public function testDontAllowInvalidChoiceValues()
{
$item = new Item(1, 'Foo');
$choiceList = new ModelChoiceList(
self::ITEM_CLASS,
'value',
array($item)
);
$this->assertEquals(array(), $choiceList->getValuesForChoices(array(new Item(2, 'Bar'))));
$this->assertEquals(array(), $choiceList->getChoicesForValues(array(2)));
}
}

View File

@ -13,10 +13,10 @@ namespace Symfony\Bridge\Propel1\Tests;
abstract class Propel1TestCase extends \PHPUnit_Framework_TestCase
{
protected function setUp()
public static function setUpBeforeClass()
{
if (!class_exists('\Propel')) {
$this->markTestSkipped('Propel is not available.');
self::markTestSkipped('Propel is not available.');
}
}
}

View File

@ -316,7 +316,7 @@ class FrameworkExtension extends Extension
$container->setParameter('session.storage.options', $options);
// session handler (the internal callback registered with PHP session management)
if (null == $config['handler_id']) {
if (null === $config['handler_id']) {
// Set the handler class to be null
$container->getDefinition('session.storage.native')->replaceArgument(1, null);
$container->getDefinition('session.storage.php_bridge')->replaceArgument(0, null);

View File

@ -82,7 +82,7 @@
<tag name="translation.loader" alias="res" />
</service>
<service id="translation.loader.dat" class="%translation.loader.res.class%">
<service id="translation.loader.dat" class="%translation.loader.dat.class%">
<tag name="translation.loader" alias="dat" />
</service>

View File

@ -559,6 +559,11 @@ abstract class Client
);
}
// protocol relative URL
if (0 === strpos($uri, '//')) {
return parse_url($currentUri, PHP_URL_SCHEME).':'.$uri;
}
// anchor?
if (!$uri || '#' == $uri[0]) {
return preg_replace('/#.*?$/', '', $currentUri).$uri;

View File

@ -388,6 +388,18 @@ class ClientTest extends \PHPUnit_Framework_TestCase
$client->request('GET', 'http://www.example.com/foo/foobar');
$this->assertEquals('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() follows a redirect if any');
$client->setNextResponse(new Response('', 302, array('Location' => '/redirected')));
$client->request('GET', 'http://www.example.com/foo/foobar');
$this->assertEquals('http://www.example.com/redirected', $client->getRequest()->getUri(), '->followRedirect() follows relative URLs');
$client = new TestClient();
$client->setNextResponse(new Response('', 302, array('Location' => '//www.example.org/')));
$client->request('GET', 'https://www.example.com/');
$this->assertEquals('https://www.example.org/', $client->getRequest()->getUri(), '->followRedirect() follows protocol-relative URLs');
$client = new TestClient();
$client->setNextResponse(new Response('', 302, array('Location' => 'http://www.example.com/redirected')));
$client->request('POST', 'http://www.example.com/foo/foobar', array('name' => 'bar'));

View File

@ -722,8 +722,6 @@ use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Parameter;
$bagClass
/**

View File

@ -6,8 +6,6 @@ use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
/**

View File

@ -6,8 +6,6 @@ use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
/**

View File

@ -6,8 +6,6 @@ use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
/**

View File

@ -6,8 +6,6 @@ use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
/**

View File

@ -6,8 +6,6 @@ use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
/**

View File

@ -6,8 +6,6 @@ use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\ParameterBag\ParameterBag;
/**

View File

@ -6,8 +6,6 @@ use Symfony\Component\DependencyInjection\Exception\InactiveScopeException;
use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
use Symfony\Component\DependencyInjection\Exception\LogicException;
use Symfony\Component\DependencyInjection\Exception\RuntimeException;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\Parameter;
use Symfony\Component\DependencyInjection\ParameterBag\FrozenParameterBag;
/**

View File

@ -160,7 +160,7 @@ abstract class Bundle extends ContainerAware implements BundleInterface
$name = get_class($this);
$pos = strrpos($name, '\\');
return $this->name = false === $pos ? $name : substr($name, $pos + 1);
return $this->name = false === $pos ? $name : substr($name, $pos + 1);
}
/**

View File

@ -119,12 +119,12 @@ class Process
/**
* Constructor.
*
* @param string $commandline The command line to run
* @param string $cwd The working directory
* @param array $env The environment variables or null to inherit
* @param string $stdin The STDIN content
* @param integer $timeout The timeout in seconds
* @param array $options An array of options for proc_open
* @param string $commandline The command line to run
* @param string|null $cwd The working directory or null to use the working dir of the current PHP process
* @param array|null $env The environment variables or null to inherit
* @param string|null $stdin The STDIN content
* @param integer|float|null $timeout The timeout in seconds or null to disable
* @param array $options An array of options for proc_open
*
* @throws RuntimeException When proc_open is not installed
*
@ -692,7 +692,7 @@ class Process
/**
* Gets the process timeout.
*
* @return integer|null The timeout in seconds or null if it's disabled
* @return float|null The timeout in seconds or null if it's disabled
*/
public function getTimeout()
{
@ -704,7 +704,7 @@ class Process
*
* To disable the timeout, set this value to null.
*
* @param float|null $timeout The timeout in seconds
* @param integer|float|null $timeout The timeout in seconds
*
* @return self The current Process instance
*
@ -712,15 +712,11 @@ class Process
*/
public function setTimeout($timeout)
{
if (null === $timeout) {
$this->timeout = null;
return $this;
}
$timeout = (float) $timeout;
if ($timeout < 0) {
if (0.0 === $timeout) {
$timeout = null;
} elseif ($timeout < 0) {
throw new InvalidArgumentException('The timeout value must be a valid positive integer or float number.');
}
@ -756,11 +752,10 @@ class Process
/**
* Gets the working directory.
*
* @return string The current working directory
* @return string|null The current working directory or null on failure
*/
public function getWorkingDirectory()
{
// This is for BC only
if (null === $this->cwd) {
// getcwd() will return false if any one of the parent directories does not have
// the readable or search mode set, even if the current directory does
@ -823,7 +818,7 @@ class Process
/**
* Gets the contents of STDIN.
*
* @return string The current contents
* @return string|null The current contents
*/
public function getStdin()
{
@ -833,7 +828,7 @@ class Process
/**
* Sets the contents of STDIN.
*
* @param string $stdin The new contents
* @param string|null $stdin The new contents
*
* @return self The current Process instance
*/
@ -932,7 +927,7 @@ class Process
*/
public function checkTimeout()
{
if (0 < $this->timeout && $this->timeout < microtime(true) - $this->starttime) {
if (null !== $this->timeout && $this->timeout < microtime(true) - $this->starttime) {
$this->stop(0);
throw new RuntimeException('The process timed-out.');

View File

@ -156,8 +156,8 @@ class ProcessPipes
/**
* Writes stdin data.
*
* @param Boolean $blocking Whether to use blocking calls or not.
* @param string $stdin The data to write.
* @param Boolean $blocking Whether to use blocking calls or not.
* @param string|null $stdin The data to write.
*/
public function write($blocking, $stdin)
{
@ -247,6 +247,10 @@ class ProcessPipes
*/
private function readStreams($blocking, $close = false)
{
if (empty($this->pipes)) {
return array();
}
$read = array();
$r = $this->pipes;

View File

@ -19,6 +19,16 @@ use Symfony\Component\Process\Exception\RuntimeException;
*/
abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
{
public function testThatProcessDoesNotThrowWarningDuringRun()
{
@trigger_error('Test Error', E_USER_NOTICE);
$process = $this->getProcess("php -r 'sleep(3)'");
$process->run();
$actualError = error_get_last();
$this->assertEquals('Test Error', $actualError['message']);
$this->assertEquals(E_USER_NOTICE, $actualError['type']);
}
/**
* @expectedException \Symfony\Component\Process\Exception\InvalidArgumentException
*/
@ -36,12 +46,17 @@ abstract class AbstractProcessTest extends \PHPUnit_Framework_TestCase
$p->setTimeout(-1);
}
public function testNullTimeout()
public function testFloatAndNullTimeout()
{
$p = $this->getProcess('');
$p->setTimeout(10);
$p->setTimeout(null);
$p->setTimeout(10);
$this->assertSame(10.0, $p->getTimeout());
$p->setTimeout(null);
$this->assertNull($p->getTimeout());
$p->setTimeout(0.0);
$this->assertNull($p->getTimeout());
}

View File

@ -165,8 +165,17 @@ class AclProvider implements AclProviderInterface
// Is it time to load the current batch?
if ((self::MAX_BATCH_SIZE === count($currentBatch) || ($i + 1) === $c) && count($currentBatch) > 0) {
$loadedBatch = $this->lookupObjectIdentities($currentBatch, $sids, $oidLookup);
try {
$loadedBatch = $this->lookupObjectIdentities($currentBatch, $sids, $oidLookup);
} catch (AclNotFoundException $aclNotFoundexception) {
if ($result->count()) {
$partialResultException = new NotAllAclsFoundException('The provider could not find ACLs for all object identities.');
$partialResultException->setPartialResult($result);
throw $partialResultException;
} else {
throw $aclNotFoundexception;
}
}
foreach ($loadedBatch as $loadedOid) {
$loadedAcl = $loadedBatch->offsetGet($loadedOid);

View File

@ -252,6 +252,22 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
}
}
// check properties for deleted, and created ACEs, and perform deletions
// we need to perfom deletions before updating existing ACEs, in order to
// preserve uniqueness of the order field
if (isset($propertyChanges['classAces'])) {
$this->updateOldAceProperty('classAces', $propertyChanges['classAces']);
}
if (isset($propertyChanges['classFieldAces'])) {
$this->updateOldFieldAceProperty('classFieldAces', $propertyChanges['classFieldAces']);
}
if (isset($propertyChanges['objectAces'])) {
$this->updateOldAceProperty('objectAces', $propertyChanges['objectAces']);
}
if (isset($propertyChanges['objectFieldAces'])) {
$this->updateOldFieldAceProperty('objectFieldAces', $propertyChanges['objectFieldAces']);
}
// this includes only updates of existing ACEs, but neither the creation, nor
// the deletion of ACEs; these are tracked by changes to the ACL's respective
// properties (classAces, classFieldAces, objectAces, objectFieldAces)
@ -259,20 +275,20 @@ class MutableAclProvider extends AclProvider implements MutableAclProviderInterf
$this->updateAces($propertyChanges['aces']);
}
// check properties for deleted, and created ACEs
// check properties for deleted, and created ACEs, and perform creations
if (isset($propertyChanges['classAces'])) {
$this->updateAceProperty('classAces', $propertyChanges['classAces']);
$this->updateNewAceProperty('classAces', $propertyChanges['classAces']);
$sharedPropertyChanges['classAces'] = $propertyChanges['classAces'];
}
if (isset($propertyChanges['classFieldAces'])) {
$this->updateFieldAceProperty('classFieldAces', $propertyChanges['classFieldAces']);
$this->updateNewFieldAceProperty('classFieldAces', $propertyChanges['classFieldAces']);
$sharedPropertyChanges['classFieldAces'] = $propertyChanges['classFieldAces'];
}
if (isset($propertyChanges['objectAces'])) {
$this->updateAceProperty('objectAces', $propertyChanges['objectAces']);
$this->updateNewAceProperty('objectAces', $propertyChanges['objectAces']);
}
if (isset($propertyChanges['objectFieldAces'])) {
$this->updateFieldAceProperty('objectFieldAces', $propertyChanges['objectFieldAces']);
$this->updateNewFieldAceProperty('objectFieldAces', $propertyChanges['objectFieldAces']);
}
// if there have been changes to shared properties, we need to synchronize other
@ -740,12 +756,12 @@ QUERY;
}
/**
* This processes changes on an ACE related property (classFieldAces, or objectFieldAces).
* This processes new entries changes on an ACE related property (classFieldAces, or objectFieldAces).
*
* @param string $name
* @param array $changes
*/
private function updateFieldAceProperty($name, array $changes)
private function updateNewFieldAceProperty($name, array $changes)
{
$sids = new \SplObjectStorage();
$classIds = new \SplObjectStorage();
@ -782,9 +798,29 @@ QUERY;
}
}
}
}
/**
* This process old entries changes on an ACE related property (classFieldAces, or objectFieldAces).
*
* @param string $name
* @param array $changes
*/
private function updateOldFieldAceProperty($ane, array $changes)
{
$currentIds = array();
foreach ($changes[1] as $field => $new) {
for ($i = 0, $c = count($new); $i < $c; $i++) {
$ace = $new[$i];
if (null !== $ace->getId()) {
$currentIds[$ace->getId()] = true;
}
}
}
foreach ($changes[0] as $old) {
for ($i=0,$c=count($old); $i<$c; $i++) {
for ($i = 0, $c = count($old); $i < $c; $i++) {
$ace = $old[$i];
if (!isset($currentIds[$ace->getId()])) {
@ -796,12 +832,12 @@ QUERY;
}
/**
* This processes changes on an ACE related property (classAces, or objectAces).
* This processes new entries changes on an ACE related property (classAces, or objectAces).
*
* @param string $name
* @param array $changes
*/
private function updateAceProperty($name, array $changes)
private function updateNewAceProperty($name, array $changes)
{
list($old, $new) = $changes;
@ -838,8 +874,28 @@ QUERY;
$currentIds[$ace->getId()] = true;
}
}
}
for ($i=0,$c=count($old); $i<$c; $i++) {
/**
* This processes old entries changes on an ACE related property (classAces, or objectAces).
*
* @param string $name
* @param array $changes
*/
private function updateOldAceProperty($name, array $changes)
{
list($old, $new) = $changes;
$currentIds = array();
for ($i=0,$c=count($new); $i<$c; $i++) {
$ace = $new[$i];
if (null !== $ace->getId()) {
$currentIds[$ace->getId()] = true;
}
}
for ($i = 0, $c = count($old); $i < $c; $i++) {
$ace = $old[$i];
if (!isset($currentIds[$ace->getId()])) {
@ -857,26 +913,41 @@ QUERY;
private function updateAces(\SplObjectStorage $aces)
{
foreach ($aces as $ace) {
$propertyChanges = $aces->offsetGet($ace);
$sets = array();
if (isset($propertyChanges['mask'])) {
$sets[] = sprintf('mask = %d', $propertyChanges['mask'][1]);
}
if (isset($propertyChanges['strategy'])) {
$sets[] = sprintf('granting_strategy = %s', $this->connection->quote($propertyChanges['strategy']));
}
if (isset($propertyChanges['aceOrder'])) {
$sets[] = sprintf('ace_order = %d', $propertyChanges['aceOrder'][1]);
}
if (isset($propertyChanges['auditSuccess'])) {
$sets[] = sprintf('audit_success = %s', $this->connection->getDatabasePlatform()->convertBooleans($propertyChanges['auditSuccess'][1]));
}
if (isset($propertyChanges['auditFailure'])) {
$sets[] = sprintf('audit_failure = %s', $this->connection->getDatabasePlatform()->convertBooleans($propertyChanges['auditFailure'][1]));
}
$this->connection->executeQuery($this->getUpdateAccessControlEntrySql($ace->getId(), $sets));
$this->updateAce($aces, $ace);
}
}
private function updateAce(\SplObjectStorage $aces, $ace)
{
$propertyChanges = $aces->offsetGet($ace);
$sets = array();
if (isset($propertyChanges['aceOrder'])
&& $propertyChanges['aceOrder'][1] > $propertyChanges['aceOrder'][0]
&& $propertyChanges == $aces->offsetGet($ace)) {
$aces->next();
if ($aces->valid()) {
$this->updateAce($aces, $aces->current());
}
}
if (isset($propertyChanges['mask'])) {
$sets[] = sprintf('mask = %d', $propertyChanges['mask'][1]);
}
if (isset($propertyChanges['strategy'])) {
$sets[] = sprintf('granting_strategy = %s', $this->connection->quote($propertyChanges['strategy']));
}
if (isset($propertyChanges['aceOrder'])) {
$sets[] = sprintf('ace_order = %d', $propertyChanges['aceOrder'][1]);
}
if (isset($propertyChanges['auditSuccess'])) {
$sets[] = sprintf('audit_success = %s', $this->connection->getDatabasePlatform()->convertBooleans($propertyChanges['auditSuccess'][1]));
}
if (isset($propertyChanges['auditFailure'])) {
$sets[] = sprintf('audit_failure = %s', $this->connection->getDatabasePlatform()->convertBooleans($propertyChanges['auditFailure'][1]));
}
$this->connection->executeQuery($this->getUpdateAccessControlEntrySql($ace->getId(), $sets));
}
}

View File

@ -359,6 +359,54 @@ class MutableAclProviderTest extends \PHPUnit_Framework_TestCase
$this->assertEquals($newParentParentAcl->getId(), $reloadedAcl->getParentAcl()->getParentAcl()->getId());
}
public function testUpdateAclInsertingMultipleObjectFieldAcesThrowsDBConstraintViolations()
{
$provider = $this->getProvider();
$oid = new ObjectIdentity(1, 'Foo');
$sid1 = new UserSecurityIdentity('johannes', 'FooClass');
$sid2 = new UserSecurityIdentity('guilro', 'FooClass');
$sid3 = new UserSecurityIdentity('bmaz', 'FooClass');
$fieldName = 'fieldName';
$acl = $provider->createAcl($oid);
$acl->insertObjectFieldAce($fieldName, $sid1, 4);
$provider->updateAcl($acl);
$acl = $provider->findAcl($oid);
$acl->insertObjectFieldAce($fieldName, $sid2, 4);
$provider->updateAcl($acl);
$acl = $provider->findAcl($oid);
$acl->insertObjectFieldAce($fieldName, $sid3, 4);
$provider->updateAcl($acl);
}
public function testUpdateAclDeletingObjectFieldAcesThrowsDBConstraintViolations()
{
$provider = $this->getProvider();
$oid = new ObjectIdentity(1, 'Foo');
$sid1 = new UserSecurityIdentity('johannes', 'FooClass');
$sid2 = new UserSecurityIdentity('guilro', 'FooClass');
$sid3 = new UserSecurityIdentity('bmaz', 'FooClass');
$fieldName = 'fieldName';
$acl = $provider->createAcl($oid);
$acl->insertObjectFieldAce($fieldName, $sid1, 4);
$provider->updateAcl($acl);
$acl = $provider->findAcl($oid);
$acl->insertObjectFieldAce($fieldName, $sid2, 4);
$provider->updateAcl($acl);
$index = 0;
$acl->deleteObjectFieldAce($index, $fieldName);
$provider->updateAcl($acl);
$acl = $provider->findAcl($oid);
$acl->insertObjectFieldAce($fieldName, $sid3, 4);
$provider->updateAcl($acl);
}
/**
* Data must have the following format:
* array(

View File

@ -18,7 +18,7 @@ use Symfony\Component\Validator\Constraint;
* Default implementation of the ConstraintValidatorFactoryInterface.
*
* This enforces the convention that the validatedBy() method on any
* Constrain will return the class name of the ConstraintValidator that
* Constraint will return the class name of the ConstraintValidator that
* should validate the Constraint.
*/
class ConstraintValidatorFactory implements ConstraintValidatorFactoryInterface

View File

@ -15,7 +15,7 @@ use Symfony\Component\Validator\Constraint;
/**
* Specifies an object able to return the correct ConstraintValidatorInterface
* instance given a Constrain object.
* instance given a Constraint object.
*/
interface ConstraintValidatorFactoryInterface
{