Skip to content

Commit

Permalink
feature #5 Add LazyChainProvider for lazy loading providers (sstok)
Browse files Browse the repository at this point in the history
This PR was merged into the 1.0-dev branch.

Discussion
----------

| Q             | A
| ------------- | ---
| Bug fix?      | no
| New feature?  | yes
| BC breaks?    | no
| Deprecations? | no
| Tests pass?   | yes
| Fixed tickets | Fixes #2 
| License       | MIT

Commits
-------

9dc1ef3 Add LazyChainProvider for lazy loading providers
  • Loading branch information
sstok authored Aug 21, 2017
2 parents ed8e4d1 + 9dc1ef3 commit f655fdc
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 25 deletions.
12 changes: 12 additions & 0 deletions docs/blacklist.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,18 @@ $blacklistProvider = new ChainProvider([
]);
```

### LazyChainProvider

Alternatively it's recommended to use the `Rollerworks\Component\PasswordStrength\Blacklist\LazyChainProvider`
as this allows to load providers lazy (and thus preventing opening resources unneeded).

```php
$container = ...; // \Psr\Container\ContainerInterface
$serviceIds = ['provider1']; // An array of service-id's to use for lazy loading providers.

$blacklistProvider = new LazyChainProvider($container, $serviceIds);
```

## Updating the blacklist database

To update your blacklist providers with new entries (or purge outdated outdated entries)
Expand Down
53 changes: 53 additions & 0 deletions src/Blacklist/LazyChainProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
<?php

/*
* This file is part of the RollerworksPasswordStrengthValidator package.
*
* (c) Sebastiaan Stok <s.stok@rollerscapes.net>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Rollerworks\Component\PasswordStrength\Blacklist;

use Psr\Container\ContainerInterface;

/**
* Chained blacklist provider.
*
* @author Sebastiaan Stok <s.stok@rollerscapes.net>
*/
final class LazyChainProvider implements BlacklistProviderInterface
{
private $container;
private $providers;

/**
* Constructor.
*
* @param ContainerInterface $container
* @param string[] $providers
*/
public function __construct(ContainerInterface $container, array $providers)
{
$this->container = $container;
$this->providers = $providers;
}

/**
* {@inheritdoc}
*
* Runs trough all the providers until one returns true.
*/
public function isBlacklisted($password)
{
foreach ($this->providers as $provider) {
if (true === $this->container->get($provider)->isBlacklisted($password)) {
return true;
}
}

return false;
}
}
52 changes: 52 additions & 0 deletions tests/BlackListMockProviderTrait.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
<?php

/*
* This file is part of the RollerworksPasswordStrengthValidator package.
*
* (c) Sebastiaan Stok <s.stok@rollerscapes.net>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Rollerworks\Component\PasswordStrength\Tests;

use Prophecy\Argument;
use Prophecy\Prophecy\ObjectProphecy;
use Psr\Container\ContainerInterface;
use Rollerworks\Component\PasswordStrength\Blacklist\BlacklistProviderInterface;

/**
* Trait BlackListMockProviderTrait.
*
* @method ObjectProphecy prophesize($class)
*/
trait BlackListMockProviderTrait
{
protected function createMockedProvider($blacklisted)
{
$mockProvider = $this->prophesize(BlacklistProviderInterface::class);
$mockProvider->isBlacklisted($blacklisted)->willReturn(true);
$mockProvider->isBlacklisted(Argument::any())->willReturn(false);

return $mockProvider->reveal();
}

/**
* @param array $loaders
*
* @return ContainerInterface|object
*/
protected function createLoadersContainer(array $loaders)
{
$loadersProphecy = $this->prophesize(ContainerInterface::class);
$loadersProphecy->has(Argument::any())->willReturn(false);

foreach ($loaders as $name => $loader) {
$loadersProphecy->has($name)->willReturn(true);
$loadersProphecy->get($name)->willReturn($loader);
}

return $loadersProphecy->reveal();
}
}
66 changes: 66 additions & 0 deletions tests/Blacklist/LazyChainProviderTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
<?php

/*
* This file is part of the RollerworksPasswordStrengthValidator package.
*
* (c) Sebastiaan Stok <s.stok@rollerscapes.net>
*
* This source file is subject to the MIT license that is bundled
* with this source code in the file LICENSE.
*/

namespace Rollerworks\Component\PasswordStrength\Tests\Blacklist;

use PHPUnit\Framework\TestCase;
use Rollerworks\Component\PasswordStrength\Blacklist\BlacklistProviderInterface;
use Rollerworks\Component\PasswordStrength\Blacklist\LazyChainProvider;
use Rollerworks\Component\PasswordStrength\Tests\BlackListMockProviderTrait;

final class LazyChainProviderTest extends TestCase
{
use BlackListMockProviderTrait;

public function testBlackList()
{
$loader1 = $this->createMockedProvider('foobar');
$loader2 = $this->createMockedProvider('god');

$this->createLoadersContainer(['first' => $loader1, 'second' => $loader2]);

$provider = new LazyChainProvider(
$this->createLoadersContainer(['first' => $loader1, 'second' => $loader2]),
['first', 'second']
);

self::assertTrue($provider->isBlacklisted('god'));
self::assertTrue($provider->isBlacklisted('foobar'));

self::assertFalse($provider->isBlacklisted('tests'));
self::assertFalse($provider->isBlacklisted(null));
self::assertFalse($provider->isBlacklisted(false));
}

public function testStopsLoadingOnFirstHit()
{
$loader1 = $this->createMockedProvider('foobar');
$loader2 = $this->createNotExpectedMockedProvider();

$this->createLoadersContainer(['first' => $loader1, 'second' => $loader2]);

$provider = new LazyChainProvider(
$this->createLoadersContainer(['first' => $loader1, 'second' => $loader2]),
['first', 'second']
);

self::assertTrue($provider->isBlacklisted('foobar'));
}

protected function createNotExpectedMockedProvider()
{
// Prophesize acts funny...
$mock = $this->createMock(BlacklistProviderInterface::class);
$mock->expects(self::never())->method('isBlacklisted');

return $mock;
}
}
28 changes: 3 additions & 25 deletions tests/Validator/BlacklistValidationTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,17 @@

namespace Rollerworks\Component\PasswordStrength\Tests\Validator;

use Prophecy\Argument;
use Psr\Container\ContainerInterface;
use Rollerworks\Component\PasswordStrength\Blacklist\ArrayProvider;
use Rollerworks\Component\PasswordStrength\Blacklist\BlacklistProviderInterface;
use Rollerworks\Component\PasswordStrength\Tests\BlackListMockProviderTrait;
use Rollerworks\Component\PasswordStrength\Validator\Constraints\Blacklist;
use Rollerworks\Component\PasswordStrength\Validator\Constraints\BlacklistValidator;
use Symfony\Component\Validator\Exception\RuntimeException;
use Symfony\Component\Validator\Test\ConstraintValidatorTestCase;

class BlacklistValidationTest extends ConstraintValidatorTestCase
{
use BlackListMockProviderTrait;

public function getMock($originalClassName, $methods = [], array $arguments = [], $mockClassName = '', $callOriginalConstructor = true, $callOriginalClone = true, $callAutoload = true, $cloneArguments = false, $callOriginalMethods = false, $proxyTarget = null)
{
if (func_num_args() === 1 && preg_match('/^Symfony\\\\Component\\\\([a-z]+\\\\)+[a-z]+Interface$/i', $originalClassName)) {
Expand Down Expand Up @@ -137,26 +137,4 @@ public function testThrowsExceptionWhenNoProvidersWereGiven()

$this->validator->validate('dope', new Blacklist(['message' => 'myMessage', 'provider' => 'array']));
}

private function createMockedProvider($blacklisted)
{
$mockProvider = $this->prophesize(BlacklistProviderInterface::class);
$mockProvider->isBlacklisted($blacklisted)->willReturn(true);
$mockProvider->isBlacklisted(Argument::any())->willReturn(false);

return $mockProvider->reveal();
}

private function createLoadersContainer(array $loaders)
{
$loadersProphecy = $this->prophesize(ContainerInterface::class);
$loadersProphecy->has(Argument::any())->willReturn(false);

foreach ($loaders as $name => $loader) {
$loadersProphecy->has($name)->willReturn(true);
$loadersProphecy->get($name)->willReturn($loader);
}

return $loadersProphecy->reveal();
}
}

0 comments on commit f655fdc

Please sign in to comment.