Skip to content

Commit 2697171

Browse files
committed
Merge pull request #12 from robcaw/feature/NullOnly
Override feature
2 parents 6ad0f28 + b815485 commit 2697171

5 files changed

Lines changed: 110 additions & 21 deletions

File tree

README.md

Lines changed: 20 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# StringGeneratorBundle
22

3+
[![Build Status](https://scrutinizer-ci.com/g/vivait/StringGeneratorBundle/badges/build.png?b=master)](https://scrutinizer-ci.com/g/vivait/StringGeneratorBundle/build-status/master) [![Scrutinizer Code Quality](https://scrutinizer-ci.com/g/vivait/StringGeneratorBundle/badges/quality-score.png?b=master)](https://scrutinizer-ci.com/g/vivait/StringGeneratorBundle/?branch=master)
4+
35
This bundle allows you to automatically generate a unique random string on an entity property, useful for
46
creating keys. Using Doctrine's `prePersist` callback, StringGenerator adds the generated string to a property
57
before the entity is persisted. It also checks whether the string is unique to that property (just in case) and if not, quietly
@@ -21,7 +23,7 @@ public function registerBundles()
2123
## Configure
2224

2325
The default configuration is shown below:
24-
26+
2527
```yaml
2628
vivait_string_generator:
2729
generators:
@@ -33,14 +35,16 @@ vivait_string_generator:
3335
* `SecureBytesGenerator` generates a secure random string using the `Symfony\Component\Security\Core\Util\SecureRandom` class
3436

3537
### Custom generators
36-
You can use your own generators by implementing `GeneratorInterface` and defining the generator in the configuration,
38+
You can use your own generators by implementing `GeneratorInterface` and defining the generator in the configuration,
3739
using either its service or classname.
3840

3941
## Basic usage
4042

41-
Add the `@Generate(generator="generator_name")` annotation to an entity property
43+
Add the `@Generate(generator="generator_name")` annotation to an entity property
4244
(where `generator_name` is the name of a generator defined in the configuration).
4345

46+
`generator` is a required property of the annotation.
47+
4448
```php
4549
use Vivait\StringGeneratorBundle\Annotation\GeneratorAnnotation as Generate;
4650
@@ -79,9 +83,9 @@ To change the length of the generated string, add `length` to the annotation.
7983
```
8084

8185
### Callbacks
82-
83-
It's possible to define callbacks on the `Generator` class that you are using.
84-
For example, with the bundled StringGenerator, you may wish to set the character pool.
86+
87+
It's possible to define callbacks on the `Generator` class that you are using.
88+
For example, with the bundled StringGenerator, you may wish to set the character pool.
8589

8690
This can be achieved by setting the `callbacks` option. For example:
8791

@@ -110,11 +114,20 @@ public function getPrefix()
110114

111115
In this case `StringGenerator::setPrefix("default")` will be called
112116

113-
117+
114118
### Unique
115119

116120
Setting `unique` is boolean and tell if the string must be unique or not, by default `true`
117121

118122
```php
119123
@Generate(generator="secure_bytes", unique=false)
120124
```
125+
126+
### Override
127+
128+
By default, `override` is set to true, so a string is always generated for a property.
129+
However, by setting `override` to false, only null properties will have a string generated for them.
130+
131+
```php
132+
@Generate(generator="string", override=false)
133+
```

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"require": {
1313
"php": ">=5.3.3",
1414
"doctrine/common": "~2.2",
15+
"doctrine/orm": "~2.2",
1516
"symfony/security": "~2.1"
1617
},
1718
"require-dev": {

spec/Vivait/StringGeneratorBundle/EventListener/GeneratorListenerSpec.php

Lines changed: 73 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,12 @@
33
namespace spec\Vivait\StringGeneratorBundle\EventListener;
44

55
use Doctrine\Common\Annotations\Reader;
6+
7+
8+
use Doctrine\ORM\EntityManagerInterface;
9+
use Doctrine\ORM\EntityRepository;
10+
use Doctrine\ORM\Event\LifecycleEventArgs;
11+
use Doctrine\ORM\Mapping\ClassMetadata;
612
use PhpSpec\ObjectBehavior;
713
use Prophecy\Argument;
814
use Vivait\StringGeneratorBundle\Annotation\GeneratorAnnotation;
@@ -11,42 +17,100 @@
1117

1218
class GeneratorListenerSpec extends ObjectBehavior
1319
{
20+
public $mockEntity;
21+
1422
function it_is_initializable()
1523
{
1624
$this->shouldHaveType('Vivait\StringGeneratorBundle\EventListener\GeneratorListener');
1725
}
1826

19-
function let(Reader $reader, Registry $registry)
27+
function let(Reader $reader, Registry $registry, EntityRepository $entityRepository, ClassMetadata $meta, EntityManagerInterface $entityManager, LifecycleEventArgs $args)
2028
{
2129
$this->beConstructedWith($reader, $registry);
30+
31+
//Set up for EM etc.
32+
$this->mockEntity = new Entity();
33+
$args->getEntity()->willReturn($this->mockEntity);
34+
$args->getEntityManager()->willReturn($entityManager);
35+
$entityManager->getClassMetadata(Argument::any())->willReturn($meta);
36+
$entityManager->getRepository(Argument::any())->willReturn($entityRepository);
37+
$meta->getName()->willReturn('Entity');
38+
2239
}
2340

24-
function it_performs_callbacks_on_the_generator(StringGenerator $generator, Entity $mockEntity)
41+
function it_performs_callbacks_on_the_generator(StringGenerator $generator)
2542
{
2643
$annotation = new GeneratorAnnotation([]);
2744
$annotation->callbacks = ['setChars' => 'abcdef'];
28-
$this->shouldNotThrow('\InvalidArgumentException')->duringPerformCallbacks($generator, $annotation, $mockEntity);
45+
$this->shouldNotThrow('\InvalidArgumentException')->duringPerformCallbacks($generator, $annotation, $this->mockEntity);
2946

3047
$annotation->callbacks = ['noMethod' => 'something'];
31-
$this->shouldThrow('\InvalidArgumentException')->duringPerformCallbacks($generator, $annotation, $mockEntity);
48+
$this->shouldThrow('\InvalidArgumentException')->duringPerformCallbacks($generator, $annotation, $this->mockEntity);
3249
}
3350

34-
function it_can_get_callback_values_from_annotated_object(StringGenerator $generator, Entity $mockEntity)
51+
function it_can_get_callback_values_from_annotated_object(StringGenerator $generator)
3552
{
3653
$annotation = new GeneratorAnnotation([]);
37-
$annotation->callbacks = ['setPrefix' => 'getPrefix'];
54+
$annotation->callbacks = ['setPrefix' => 'createPrefix'];
3855

39-
$mockEntity->getPrefix()->willReturn('VIVA_');
56+
$this->mockEntity->createPrefix();
4057
$generator->setPrefix('VIVA_')->shouldBeCalled();
41-
$this->performCallbacks($generator, $annotation, $mockEntity);
58+
$this->performCallbacks($generator, $annotation, $this->mockEntity);
59+
}
60+
61+
function it_sets_null_properties_if_override_set_to_true(Registry $registry, Reader $reader, LifecycleEventArgs $args, StringGenerator $generator)
62+
{
63+
$annotation = new GeneratorAnnotation([]);
64+
$annotation->override = false;
65+
$annotation->unique = false;
66+
67+
$reader->getPropertyAnnotations(Argument::any())->willReturn([$annotation]);
68+
69+
$registry->get(Argument::any())->willReturn($generator)->shouldBeCalled();
70+
$generator->generate()->shouldBeCalled();
71+
$generator->setLength(Argument::any())->shouldBeCalled();
72+
73+
$this->prePersist($args);
74+
}
75+
function it_wont_set_non_null_properties_if_override_set_to_true(Reader $reader, LifecycleEventArgs $args, StringGenerator $generator)
76+
{
77+
$this->mockEntity->setName('Robin');
78+
$annotation = new GeneratorAnnotation([]);
79+
$annotation->override = false;
80+
81+
$reader->getPropertyAnnotations(Argument::any())->willReturn([$annotation]);
82+
$generator->generate()->shouldNotBeCalled();
83+
84+
$this->prePersist($args);
85+
}
86+
87+
function it_generates_a_string_on_a_property(Registry $registry, Reader $reader, LifecycleEventArgs $args, StringGenerator $generator)
88+
{
89+
$annotation = new GeneratorAnnotation([]);
90+
91+
$reader->getPropertyAnnotations(Argument::any())->willReturn([$annotation]);
92+
93+
$registry->get(Argument::any())->willReturn($generator);
94+
$generator->generate()->shouldBeCalled();
95+
$generator->setLength(Argument::any())->shouldBeCalled();
96+
97+
$this->prePersist($args);
4298
}
4399
}
44100

45101
class Entity
46102
{
47-
public function getPrefix()
103+
private $name;
104+
105+
public function createPrefix()
48106
{
107+
return 'VIVA_';
108+
}
49109

110+
public function setName($name)
111+
{
112+
$this->name = $name;
50113
}
114+
51115
}
52116

src/Vivait/StringGeneratorBundle/Annotation/GeneratorAnnotation.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,4 +27,6 @@ class GeneratorAnnotation extends Annotation
2727
* @var boolean
2828
*/
2929
public $unique = true;
30+
31+
public $override = true;
3032
}

src/Vivait/StringGeneratorBundle/EventListener/GeneratorListener.php

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,21 @@
33
namespace Vivait\StringGeneratorBundle\EventListener;
44

55
use Doctrine\Common\Annotations\Reader;
6+
use Doctrine\ORM\EntityRepository;
67
use Doctrine\ORM\Event\LifecycleEventArgs;
78
use Vivait\StringGeneratorBundle\Annotation\GeneratorAnnotation;
89
use Vivait\StringGeneratorBundle\Model\GeneratorInterface;
910
use Vivait\StringGeneratorBundle\Registry\Registry;
1011

1112
class GeneratorListener
1213
{
14+
/**
15+
* @var Reader
16+
*/
1317
private $reader;
18+
/**
19+
* @var EntityRepository
20+
*/
1421
private $repo;
1522
/**
1623
* @var GeneratorInterface
@@ -45,11 +52,15 @@ public function prePersist(LifecycleEventArgs $args)
4552

4653
foreach ($object->getProperties() as $property) {
4754
foreach ($this->reader->getPropertyAnnotations($property) as $annotation) {
48-
4955
if ($annotation instanceof GeneratorAnnotation) {
50-
$string = $this->generateString($property->name, $annotation, $object);
5156

52-
$meta->getReflectionProperty($property->name)->setValue($entity, $string);
57+
$property->setAccessible(true);
58+
if (!$annotation->override && $property->getValue($entity)) {
59+
break;
60+
}
61+
62+
$string = $this->generateString($property->name, $annotation, $object);
63+
$property->setValue($entity, $string);
5364
}
5465
}
5566
}
@@ -77,13 +88,11 @@ private function generateString($property, GeneratorAnnotation $annotation, $obj
7788
return $str;
7889
}
7990

80-
8191
if ($this->repo->findOneBy([$property => $str])) {
8292
return $this->generateString($property, $annotation, $object);
8393
} else {
8494
return $str;
8595
}
86-
8796
}
8897

8998
/**

0 commit comments

Comments
 (0)