Commit 8bf675f5 authored by Fabien Potencier's avatar Fabien Potencier

merged branch alexkappa/master (PR #628)

This PR was merged into the master branch.

Discussion
----------

Ported ConstraintValidatorFactory.php to Silex

Included a modified version of `ConstraintValidatorFactory` to Silex for use with custom constraints.

Since Silex comes with `ValidatorServiceProvider` built in, I guess it makes sense to include this, in case users might want dependencies with their custom validators.

Usage would be:

```php
// Custom.php
public function validatedBy()
{
    return 'my.validator.custom';
}

// index.php
$app['validator.custom'] = $app->share(function ($app) {
    return new CustomValidator();
});
$app->register(new ValidatorServiceProvider(), array(
    'validator.validator_service_ids' => array(
        'my.validator.custom' => 'validator.custom'
    )
));
```

Commits
-------

c4466a18 Changed constructor type hint to Pimple
fd72c6ab Incorporated changes suggested by @Igorow. Separating $this->validators (instances) and $this->serviceNames.
fa15389b Separating validator service names and instances
0c3234d2 Minor refactoring
83266af9 Changed mapping of 'validator.validator_service_ids' to use ternary operator
278c5e01 Backward compatibility for UserPasswordValidator
40734452 Changed deprecated namespaces
4d8956f3 Added custom constraint and validator to properly test the ConstraintValidatorFactory.
b45b4fb2 SecurityServiceProvider now registers a UserPasswordValidator if ValidatorServiceProvider is registered.
70c1e365 Registering a ValidatorServiceProvider can take a validator.validator_service_ids parameter which is now an associative array of aliases as keys and service names as values so that ConstraintValidatorFactory can lazy load the validators.
77af56be Removed Symfony\Component\Validator\ConstraintValidatorFactory altogether from ValidatorServiceProvider. Custom validators are now lazy loaded. removed obsolete test.
423138aa - Type hint in Silex\ConstraintValidatorFactory constructor for container - Modifed Silex\Provider\ValidatorServiceProvider to accept an optional   'validator.validator_service_ids' parameter wich allows users to register   custom validators. - Added test to verify that if users registered ValidatorServiceProvider   using optional 'validator.validator_service_ids' parameter then the new   Silex\ConstraintValidatorFactory will be used instead of the one provided   in  Symfony.
eaf0af2a Ported ConstraintValidatorFactory.php to Silex/Pimple
parents 0b6aed30 c4466a18
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Silex;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidatorFactoryInterface;
use Symfony\Component\Validator\ConstraintValidator;
/**
* Uses a service container to create constraint validators with dependencies.
*
* @author Kris Wallsmith <kris@symfony.com>
* @author Alex Kalyvitis <alex.kalyvitis@gmail.com>
*/
class ConstraintValidatorFactory implements ConstraintValidatorFactoryInterface
{
/**
* @var \Pimple
*/
protected $container;
/**
* @var array
*/
protected $serviceNames;
/**
* @var array
*/
protected $validators;
/**
* Constructor
*
* @param \Pimple $container DI container
* @param array $serviceNames Validator service names
*/
public function __construct(\Pimple $container, array $serviceNames = array())
{
$this->container = $container;
$this->serviceNames = $serviceNames;
$this->validators = array();
}
/**
* Returns the validator for the supplied constraint.
*
* @param Constraint $constraint A constraint
* @return ConstraintValidator A validator for the supplied constraint
*/
public function getInstance(Constraint $constraint)
{
$name = $constraint->validatedBy();
if (isset($this->validators[$name])) {
return $this->validators[$name];
}
$this->validators[$name] = $this->createValidator($name);
return $this->validators[$name];
}
/**
* Returns the validator instance
*
* @param string $name
* @return ConstraintValidator
*/
private function createValidator($name)
{
if (isset($this->serviceNames[$name])) {
return $this->container[$this->serviceNames[$name]];
}
return new $name();
}
}
......@@ -32,6 +32,8 @@ use Symfony\Component\Security\Core\Authorization\Voter\RoleHierarchyVoter;
use Symfony\Component\Security\Core\Authorization\Voter\AuthenticatedVoter;
use Symfony\Component\Security\Core\Authorization\AccessDecisionManager;
use Symfony\Component\Security\Core\Role\RoleHierarchy;
use Symfony\Component\Security\Core\Validator\Constraints\UserPasswordValidator;
use Symfony\Component\Security\Core\Validator\Constraint\UserPasswordValidator as DeprecatedUserPasswordValidator;
use Symfony\Component\Security\Http\Firewall;
use Symfony\Component\Security\Http\FirewallMap;
use Symfony\Component\Security\Http\Firewall\AbstractAuthenticationListener;
......@@ -519,6 +521,24 @@ class SecurityServiceProvider implements ServiceProviderInterface
return new AnonymousAuthenticationProvider($name);
});
});
if (isset($app['validator'])) {
$app['security.validator.user_password_validator'] = $app->share(function ($app) {
// FIXME: in Symfony 2.2 Symfony\Component\Security\Core\Validator\Constraint
// is replaced by Symfony\Component\Security\Core\Validator\Constraints
if (class_exists('Symfony\Component\Security\Core\Validator\Constraints\UserPasswordValidator')) {
return new UserPasswordValidator($app['security'], $app['security.encoder_factory']);
}
return new DeprecatedUserPasswordValidator($app['security'], $app['security.encoder_factory']);
});
if (!isset($app['validator.validator_service_ids'])) {
$app['validator.validator_service_ids'] = array();
}
$app['validator.validator_service_ids'] = array_merge($app['validator.validator_service_ids'], array('security.validator.user_password' => 'security.validator.user_password_validator'));
}
}
public function boot(Application $app)
......
......@@ -13,12 +13,12 @@ namespace Silex\Provider;
use Silex\Application;
use Silex\ServiceProviderInterface;
use Silex\ConstraintValidatorFactory;
use Symfony\Component\Validator\Validator;
use Symfony\Component\Validator\DefaultTranslator;
use Symfony\Component\Validator\Mapping\ClassMetadataFactory;
use Symfony\Component\Validator\Mapping\Loader\StaticMethodLoader;
use Symfony\Component\Validator\ConstraintValidatorFactory;
/**
* Symfony Validator component Provider.
......@@ -58,8 +58,10 @@ class ValidatorServiceProvider implements ServiceProviderInterface
return new ClassMetadataFactory(new StaticMethodLoader());
});
$app['validator.validator_factory'] = $app->share(function () {
return new ConstraintValidatorFactory();
$app['validator.validator_factory'] = $app->share(function() use ($app) {
$validators = isset($app['validator.validator_service_ids']) ? $app['validator.validator_service_ids'] : array();
return new ConstraintValidatorFactory($app, $validators);
});
}
......
......@@ -15,6 +15,7 @@ use Silex\Application;
use Silex\WebTestCase;
use Silex\Provider\SecurityServiceProvider;
use Silex\Provider\SessionServiceProvider;
use Silex\Provider\ValidatorServiceProvider;
use Symfony\Component\HttpKernel\Client;
use Symfony\Component\HttpFoundation\Request;
......@@ -118,6 +119,38 @@ class SecurityServiceProviderTest extends WebTestCase
$this->assertEquals('admin', $client->getResponse()->getContent());
}
public function testUserPasswordValidatorIsRegistered()
{
if (!is_dir(__DIR__.'/../../../../vendor/symfony/validator')) {
$this->markTestSkipped('Validator dependency was not installed.');
}
$app = new Application();
$app->register(new ValidatorServiceProvider());
$app->register(new SecurityServiceProvider(), array(
'security.firewalls' => array(
'admin' => array(
'pattern' => '^/admin',
'http' => true,
'users' => array(
'admin' => array('ROLE_ADMIN', '513aeb0121909'),
)
),
),
));
$app->boot();
// FIXME: in Symfony 2.2 Symfony\Component\Security\Core\Validator\Constraint
// is replaced by Symfony\Component\Security\Core\Validator\Constraints
if (class_exists('Symfony\Component\Security\Core\Validator\Constraints\UserPasswordValidator')) {
$this->assertInstanceOf('Symfony\Component\Security\Core\Validator\Constraints\UserPasswordValidator', $app['security.validator.user_password_validator']);
} else {
$this->assertInstanceOf('Symfony\Component\Security\Core\Validator\Constraint\UserPasswordValidator', $app['security.validator.user_password_validator']);
}
}
public function createApplication($authenticationMethod = 'form')
{
$app = new Application();
......
......@@ -15,6 +15,8 @@ use Silex\Application;
use Silex\Provider\ValidatorServiceProvider;
use Silex\Provider\FormServiceProvider;
use Symfony\Component\Validator\Constraints as Assert;
use Silex\Tests\Provider\ValidatorServiceProviderTest\Constraint\Custom;
use Silex\Tests\Provider\ValidatorServiceProviderTest\Constraint\CustomValidator;
/**
* ValidatorServiceProvider
......@@ -32,6 +34,34 @@ class ValidatorServiceProviderTest extends \PHPUnit_Framework_TestCase
return $app;
}
public function testRegisterWithCustomValidators()
{
$app = new Application();
$app['custom.validator'] = $app->share(function() {
return new CustomValidator();
});
$app->register(new ValidatorServiceProvider(), array(
'validator.validator_service_ids' => array(
'test.custom.validator' => 'custom.validator',
)
));
return $app;
}
/**
* @depends testRegisterWithCustomValidators
*/
public function testConstraintValidatorFactory($app)
{
$this->assertInstanceOf('Silex\ConstraintValidatorFactory', $app['validator.validator_factory']);
$validator = $app['validator.validator_factory']->getInstance(new Custom());
$this->assertInstanceOf('Silex\Tests\Provider\ValidatorServiceProviderTest\Constraint\CustomValidator', $validator);
}
/**
* @depends testRegister
*/
......
<?php
/*
* This file is part of the Silex framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Silex\Tests\Provider\ValidatorServiceProviderTest\Constraint;
use Symfony\Component\Validator\Constraint;
/**
* @author Alex Kalyvitis <alex.kalyvitis@gmail.com>
*/
class Custom extends Constraint
{
public $message = 'This field must be ...';
public $table;
public $field;
public function validatedBy()
{
return 'test.custom.validator';
}
}
<?php
/*
* This file is part of the Silex framework.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/
namespace Silex\Tests\Provider\ValidatorServiceProviderTest\Constraint;
use Symfony\Component\Validator\Constraint;
use Symfony\Component\Validator\ConstraintValidator;
/**
* @author Alex Kalyvitis <alex.kalyvitis@gmail.com>
*/
class CustomValidator extends ConstraintValidator
{
public function isValid($value, Constraint $constraint)
{
// Validate...
return true;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment