Skip to content

Commit 64ae94b

Browse files
committed
Add an option to generate fluent mutators. Fix a bug.
1 parent 07b8014 commit 64ae94b

File tree

10 files changed

+126
-15
lines changed

10 files changed

+126
-15
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
* Generated classes include scalar typehints and return type
66
* Nullable typehints are generated instead of a default `null` value
7-
* A fluent interface isn't generated anymore
7+
* A fluent interface isn't generated anymore by default unless you set the `fluentMutatorMethods` config flag to `true`
88
* Useless PHPDoc (`@param` and `@return` annotations when a typehint exist and mutator description) isn't generated anymore
99
* `DateTimeInterface` is used instead of `DateTime` when possible
1010
* Add the ability to not generate mutator methods (useful when generating public properties)

composer.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,8 @@
3131
},
3232
"require-dev": {
3333
"doctrine/orm": "^2.2",
34-
"symfony/validator": "^2.7 || ^3.0 || ^4.0",
35-
"symfony/filesystem": "^2.7 || ^3.0 || ^4.0"
34+
"symfony/filesystem": "^2.7 || ^3.0 || ^4.0",
35+
"symfony/validator": "^2.7 || ^3.0 || ^4.0"
3636
},
3737
"suggest": {
3838
"doctrine/collections": "For Doctrine collections",

src/AnnotationGenerator/PhpDocAnnotationGenerator.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ public function generateSetterAnnotations(string $className, string $fieldName):
113113
*/
114114
public function generateAdderAnnotations(string $className, string $fieldName): array
115115
{
116-
if (!$this->isDocUseful($className, $fieldName)) {
116+
if (!$this->isDocUseful($className, $fieldName, true)) {
117117
return [];
118118
}
119119

@@ -125,16 +125,16 @@ public function generateAdderAnnotations(string $className, string $fieldName):
125125
*/
126126
public function generateRemoverAnnotations(string $className, string $fieldName): array
127127
{
128-
if (!$this->isDocUseful($className, $fieldName)) {
128+
if (!$this->isDocUseful($className, $fieldName, true)) {
129129
return [];
130130
}
131131

132132
return [sprintf('@param %s $%s', $this->toPhpType($this->classes[$className]['fields'][$fieldName], true), $fieldName)];
133133
}
134134

135-
private function isDocUseful(string $className, string $fieldName): bool
135+
private function isDocUseful(string $className, string $fieldName, $adderOrRemover = false): bool
136136
{
137-
$typeHint = $this->classes[$className]['fields'][$fieldName]['typeHint'] ?? false;
137+
$typeHint = $this->classes[$className]['fields'][$fieldName][$adderOrRemover ? 'adderRemoverTypeHint' : 'typeHint'] ?? false;
138138

139139
return false === $typeHint || 'array' === $typeHint;
140140
}

src/TypesGenerator.php

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -264,6 +264,10 @@ public function generate(array $config): void
264264
foreach ($class['fields'] as &$field) {
265265
$field['isEnum'] = isset($classes[$field['range']]) && $classes[$field['range']]['isEnum'];
266266
$field['typeHint'] = $this->fieldToTypeHint($field, $classes) ?? false;
267+
268+
if ('array' === $field['typeHint']) {
269+
$field['adderRemoverTypeHint'] = $this->fieldToAdderRemoverTypeHint($field, $classes) ?? false;
270+
}
267271
}
268272
}
269273

@@ -404,7 +408,7 @@ public function generate(array $config): void
404408
}
405409
}
406410

407-
if (!empty($interfaceMappings) && $config['doctrine']['resolveTargetEntityConfigPath']) {
411+
if (!$interfaceMappings && $config['doctrine']['resolveTargetEntityConfigPath']) {
408412
$file = $config['output'].'/'.$config['doctrine']['resolveTargetEntityConfigPath'];
409413
$dir = dirname($file);
410414
if (!file_exists($dir)) {
@@ -511,14 +515,19 @@ private function isDatatype(string $type): bool
511515

512516
private function fieldToTypeHint(array $field, array $classes): ?string
513517
{
514-
if ($field['isEnum']) {
515-
return null;
516-
}
517-
518518
if ($field['isArray']) {
519519
return 'array';
520520
}
521521

522+
return $this->fieldToAdderRemoverTypeHint($field, $classes);
523+
}
524+
525+
private function fieldToAdderRemoverTypeHint(array $field, array $classes): ?string
526+
{
527+
if ($field['isEnum']) {
528+
return 'string';
529+
}
530+
522531
switch ($field['range']) {
523532
case 'Boolean':
524533
return 'bool';

src/TypesGeneratorConfiguration.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ function ($rdfa) {
101101
->scalarNode('author')->defaultFalse()->info('The value of the phpDoc\'s @author annotation')->example('Kévin Dunglas <[email protected]>')->end()
102102
->enumNode('fieldVisibility')->values(['private', 'protected', 'public'])->defaultValue('private')->cannotBeEmpty()->info('Visibility of entities fields')->end()
103103
->booleanNode('mutatorMethods')->defaultTrue()->info('Set this flag to false to not generate getter, setter, adder and remover methods')->end()
104+
->booleanNode('fluentMutatorMethods')->defaultFalse()->info('Set this flag to true to generate fluent setter, adder and remover methods')->end()
104105
->arrayNode('types')
105106
->beforeNormalization()
106107
->always()

templates/class.php.twig

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,17 +67,21 @@ use {{ use }};
6767
* {{ annotation }}
6868
{% endfor %}
6969
*/
70-
public function add{{ field.name|ucfirst }}({% if field.typeHint and not field.isEnum %}{{ field.typeHint }} {% endif %}${{ field.name }}): void
70+
public function add{{ field.name|ucfirst }}({% if field.typeHint and not field.isEnum %}{{ field.adderRemoverTypeHint }} {% endif %}${{ field.name }}): {% if config.fluentMutatorMethods %}self{% else %}void{% endif %}
7171
{
7272
$this->{{ field.name }}[] = {% if field.isEnum %}(string) {% endif %}${{ field.name }};
73+
{% if config.fluentMutatorMethods %}
74+
75+
return $this;
76+
{% endif %}
7377
}
7478
7579
/**
7680
{% for annotation in field.removerAnnotations %}
7781
* {{ annotation }}
7882
{% endfor %}
7983
*/
80-
public function remove{{ field.name|ucfirst }}({% if field.typeHint %}{{ field.typeHint }} {% endif %}${{ field.name }}): void
84+
public function remove{{ field.name|ucfirst }}({% if field.typeHint %}{{ field.adderRemoverTypeHint }} {% endif %}${{ field.name }}): {% if config.fluentMutatorMethods %}self{% else %}void{% endif %}
8185
{
8286
{% if config.doctrine.useCollection and field.isArray and field.typeHint and not field.isEnum %}
8387
$this->{{ field.name }}->removeElement({% if field.isEnum %}(string) {% endif %}${{ field.name }});
@@ -86,6 +90,10 @@ use {{ use }};
8690
if (false !== $key) {
8791
unset($this->{{ field.name }}[$key]);
8892
}
93+
{% endif %}
94+
{% if config.fluentMutatorMethods %}
95+
96+
return $this;
8997
{% endif %}
9098
}
9199
{% else %}
@@ -94,9 +102,14 @@ use {{ use }};
94102
* {{ annotation }}
95103
{% endfor %}
96104
*/
97-
public function set{{ field.name|ucfirst }}({% if field.typeHint %}{% if field.isNullable %}?{% endif %}{{ field.typeHint }} {% endif %}${{ field.name }}): void
105+
public function set{{ field.name|ucfirst }}({% if field.typeHint %}{% if field.isNullable %}?{% endif %}{{ field.typeHint }} {% endif %}${{ field.name }}): {% if config.fluentMutatorMethods %}self{% else %}void{% endif %}
98106
{
99107
$this->{{ field.name }} = ${{ field.name }};
108+
109+
{% if config.fluentMutatorMethods %}
110+
111+
return $this;
112+
{% endif %}
100113
}
101114
{% endif %}
102115

tests/Command/DumpConfigurationTest.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,9 @@ interface: AppBundle\Model # Example: Acme\Model
9898
# Set this flag to false to not generate getter, setter, adder and remover methods
9999
mutatorMethods: true
100100
101+
# Set this flag to true to generate fluent setter, adder and remover methods
102+
fluentMutatorMethods: false
103+
101104
# Schema.org's types to use
102105
types:
103106

tests/Command/GenerateTypesCommandTest.php

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,44 @@ public function getArguments()
5656
[__DIR__.'/../../build/mongodb/ecommerce/', __DIR__.'/../config/mongodb/ecommerce.yaml'],
5757
];
5858
}
59+
60+
public function testFluentMutators()
61+
{
62+
$outputDir = __DIR__.'/../../build/fluent-mutators';
63+
$config = __DIR__.'/../config/fluent-mutators.yaml';
64+
65+
$this->fs->mkdir($outputDir);
66+
67+
$commandTester = new CommandTester(new GenerateTypesCommand());
68+
$this->assertEquals(0, $commandTester->execute(['output' => $outputDir, 'config' => $config]));
69+
70+
$organization = file_get_contents($outputDir.'/AppBundle/Entity/Person.php');
71+
72+
$this->assertContains(<<<'PHP'
73+
public function setUrl(?string $url): self
74+
{
75+
$this->url = $url;
76+
77+
return $this;
78+
}
79+
PHP
80+
, $organization);
81+
82+
$this->assertContains(<<<'PHP'
83+
public function addFriends(Person $friends): self
84+
{
85+
$this->friends[] = $friends;
86+
87+
return $this;
88+
}
89+
90+
public function removeFriends(Person $friends): self
91+
{
92+
$this->friends->removeElement($friends);
93+
94+
return $this;
95+
}
96+
PHP
97+
, $organization);
98+
}
5999
}

tests/TypesGeneratorTest.php

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,10 @@ private function getConfig(): array
170170
],
171171
'generateId' => true,
172172
'useInterface' => false,
173+
'doctrine' => [
174+
'useCollection' => true,
175+
'resolveTargetEntityConfigPath' => null,
176+
],
173177
];
174178
}
175179

tests/config/fluent-mutators.yaml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
rdfa: [{ uri: tests/data/schema.rdfa, format: rdfa }]
2+
relations: [tests/data/v1.owl]
3+
4+
fluentMutatorMethods: true
5+
types:
6+
Person:
7+
properties:
8+
name: ~
9+
familyName: ~
10+
givenName: ~
11+
additionalName: ~
12+
gender: ~
13+
address: { range: PostalAddress }
14+
# Custom range and custom ORM\Column content
15+
birthDate: { range: DateTime, ormColumn: 'type="datetimetz", nullable=true, options={"comment" = "Birthdate with timezone."}' }
16+
telephone: ~
17+
email: ~
18+
jobTitle: ~
19+
# Default relation table name would be "person_organization" for all following fields, but we customize them
20+
affiliation: ~
21+
brand: { relationTableName: "person_brand"}
22+
memberOf: { range: "Organization", cardinality: (1..*), relationTableName: "person_memberof"}
23+
worksFor: { range: "Organization", cardinality: (0..*), relationTableName: "person_worksfor"}
24+
# url field is a custom one without definition, it should render error
25+
url: ~
26+
friends: { range: "Person", cardinality: (0..*) }
27+
PostalAddress:
28+
# Disable the generation of the class hierarchy for this type
29+
properties:
30+
# Force the type of the addressCountry property to text
31+
addressCountry: { range: "Text" }
32+
addressLocality: ~
33+
addressRegion: ~
34+
postOfficeBoxNumber: ~
35+
postalCode: ~
36+
streetAddress: ~
37+
Organization:
38+
properties:
39+
name: ~
40+
# Custom property with custom ORM\Column content
41+
adminCode: {range: Text, ormColumn: 'type="string", length=3, unique=true, nullable=false, options={"comment" = "A code for central administration."}' }

0 commit comments

Comments
 (0)