1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace Pgs\RestfonyBundle\Generator; |
4
|
|
|
|
5
|
|
|
use Pgs\RestfonyBundle\Manipulator\RestFormServiceManipulator; |
6
|
|
|
use Sensio\Bundle\GeneratorBundle\Generator\Generator; |
7
|
|
|
use Symfony\Component\HttpKernel\Bundle\BundleInterface; |
8
|
|
|
use Doctrine\ORM\Mapping\ClassMetadataInfo; |
9
|
|
|
|
10
|
|
|
class DoctrineFormGenerator extends Generator |
11
|
|
|
{ |
12
|
|
|
protected $bundlePath; |
13
|
|
|
protected $entity; |
14
|
|
|
protected $entityClass; |
15
|
|
|
protected $namespace; |
16
|
|
|
protected $metadata; |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* @param BundleInterface $bundle The bundle in which to create the class |
20
|
|
|
* @param string $entity The entity relative class name |
21
|
|
|
* @param ClassMetadataInfo $metadata The entity metadata class |
22
|
|
|
*/ |
23
|
3 |
|
public function __construct(BundleInterface $bundle, $entity, ClassMetadataInfo $metadata) |
24
|
|
|
{ |
25
|
3 |
|
if (count($metadata->getIdentifier()) > 1) { |
26
|
1 |
|
throw new \RuntimeException(__CLASS__ . ' does not support entity classes with multiple primary keys.'); |
27
|
|
|
} |
28
|
|
|
|
29
|
2 |
|
$this->entityClass = $this->prepareEntityClass($entity); |
30
|
2 |
|
$this->namespace = $bundle->getNamespace(); |
31
|
2 |
|
$this->bundlePath = $bundle->getPath(); |
32
|
2 |
|
$this->entity = $entity; |
33
|
2 |
|
$this->metadata = $metadata; |
34
|
2 |
|
} |
35
|
|
|
|
36
|
2 |
|
protected function prepareEntityClass($entity) |
37
|
|
|
{ |
38
|
2 |
|
return substr($entity, strpos($entity, '\\')); |
39
|
|
|
} |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* Generates the entity form class if it does not exist. |
43
|
|
|
* |
44
|
|
|
* @param bool $forceOverwrite |
45
|
|
|
*/ |
46
|
2 |
|
public function generate($forceOverwrite = false) |
47
|
|
|
{ |
48
|
2 |
|
$formPath = $this->prepareFilePath('/Form/Type/', 'Type'); |
49
|
|
|
|
50
|
2 |
|
if (!$this->canWriteToFile($formPath, $forceOverwrite)) { |
51
|
1 |
|
throw new \RuntimeException(sprintf( |
52
|
1 |
|
'Unable to generate the %s form class as it already exists under the file: %s', |
53
|
1 |
|
$this->entityClass . 'Type', |
54
|
|
|
$formPath |
55
|
|
|
)); |
56
|
|
|
} |
57
|
|
|
|
58
|
1 |
|
$this->renderFile( |
59
|
1 |
|
'form/FormType.php.twig', |
60
|
|
|
$formPath, |
61
|
|
|
[ |
62
|
1 |
|
'fields' => $this->getFieldsFromMetadata($this->metadata), |
63
|
1 |
|
'associations' => $this->metadata->associationMappings, |
64
|
1 |
|
'namespace' => $this->namespace, |
65
|
1 |
|
'entity_namespace' => $this->prepareEntityNamespace($this->entity), |
66
|
1 |
|
'entity_class' => $this->entityClass, |
67
|
|
|
'rest_support' => true, |
68
|
1 |
|
'rest_form_type_name' => $this->prepareFormAlias($this->entityClass), |
69
|
1 |
|
'form_type_name' => $this->prepareFormTypeName($this->entity, $this->namespace, $this->entityClass) |
70
|
|
|
] |
71
|
|
|
); |
72
|
|
|
|
73
|
1 |
|
$this->renderFile( |
74
|
1 |
|
'form/FormFilterType.php.twig', |
75
|
1 |
|
$this->prepareFilePath('/Form/Filter/', 'FilterType'), |
76
|
|
|
[ |
77
|
1 |
|
'namespace' => $this->namespace, |
78
|
1 |
|
'entity_namespace' => $this->prepareEntityNamespace($this->entity), |
79
|
1 |
|
'entity_class' => $this->entityClass, |
80
|
|
|
'rest_support' => true, |
81
|
1 |
|
'rest_form_type_name' => $this->prepareFormAlias($this->entityClass), |
82
|
1 |
|
'form_type_name' => $this->prepareFormTypeName($this->entity, $this->namespace, $this->entityClass) . 'filter' |
83
|
|
|
] |
84
|
|
|
); |
85
|
1 |
|
} |
86
|
|
|
|
87
|
1 |
|
protected function canWriteToFile($path, $forceOverwrite = false) |
88
|
|
|
{ |
89
|
1 |
|
return !file_exists($path) || $forceOverwrite; |
90
|
|
|
} |
91
|
|
|
|
92
|
1 |
|
protected function prepareEntityNamespace($entity) |
93
|
|
|
{ |
94
|
1 |
|
$result = []; |
95
|
1 |
|
preg_match(addslashes('/:(([A-z0-9\]+)\)?[A-z0-9]+$/'), $entity, $result); |
96
|
1 |
|
return isset($result[2]) ? $result[2] : ''; |
97
|
|
|
} |
98
|
|
|
|
99
|
|
|
protected function prepareFormAlias($entityClass) |
100
|
|
|
{ |
101
|
1 |
|
return ltrim(preg_replace_callback('|[A-Z]+|', function ($data) { |
102
|
1 |
|
return '_'.strtolower($data[0]); |
103
|
1 |
|
}, $entityClass), '_'); |
104
|
|
|
} |
105
|
|
|
|
106
|
1 |
|
protected function prepareFormTypeName($entity, $namespace, $entityClass) |
107
|
|
|
{ |
108
|
1 |
|
$parts = explode('\\', $entity); |
109
|
1 |
|
return strtolower( |
110
|
1 |
|
str_replace('\\', '_', $namespace) |
111
|
1 |
|
. ($parts ? '_' : '') |
112
|
1 |
|
. implode('_', $parts) |
113
|
1 |
|
. '_' . $entityClass |
114
|
|
|
); |
115
|
|
|
} |
116
|
|
|
|
117
|
2 |
|
protected function prepareFilePath($path, $postfix) |
118
|
|
|
{ |
119
|
2 |
|
return $this->bundlePath . $path . str_replace('\\', '/', $this->entity) . $postfix . '.php'; |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* Returns an array of fields. Fields can be both column fields and |
124
|
|
|
* association fields. |
125
|
|
|
* |
126
|
|
|
* @param ClassMetadataInfo $metadata |
127
|
|
|
* |
128
|
|
|
* @return array $fields |
129
|
|
|
*/ |
130
|
1 |
|
protected function getFieldsFromMetadata(ClassMetadataInfo $metadata) |
131
|
|
|
{ |
132
|
1 |
|
$fields = array_merge($metadata->fieldMappings, $metadata->getAssociationMappings()); |
133
|
|
|
|
134
|
|
|
// Remove the primary key field if it's not managed manually |
135
|
1 |
|
if (!$metadata->isIdentifierNatural()) { |
136
|
1 |
|
foreach ($metadata->getIdentifier() as $identifier) { |
137
|
1 |
|
unset($fields[$identifier]); |
138
|
|
|
} |
139
|
|
|
} |
140
|
|
|
|
141
|
1 |
|
foreach ($metadata->getAssociationMappings() as $fieldName => $relation) { |
142
|
|
|
$multiTypes = array( |
143
|
1 |
|
ClassMetadataInfo::ONE_TO_MANY, |
144
|
1 |
|
ClassMetadataInfo::MANY_TO_MANY, |
145
|
|
|
); |
146
|
1 |
View Code Duplication |
if (in_array($relation['type'], $multiTypes)) { |
|
|
|
|
147
|
1 |
|
$fields[$fieldName]['relatedType'] = 'collection'; |
148
|
|
|
} else { |
149
|
1 |
|
$fields[$fieldName]['relatedType'] = 'entity'; |
150
|
|
|
} |
151
|
|
|
|
152
|
1 |
|
$fields[$fieldName]['relatedEntityShortcut'] = |
153
|
1 |
|
$this->getEntityBundleShortcut($fields[$fieldName]['targetEntity']); |
154
|
|
|
} |
155
|
|
|
|
156
|
1 |
|
return $fields; |
157
|
|
|
} |
158
|
|
|
|
159
|
|
|
/** |
160
|
|
|
* Take an entity name and return the shortcut name |
161
|
|
|
* eg Acme\DemoBundle\Entity\Notes -> AcemDemoBundle:Notes. |
162
|
|
|
* |
163
|
|
|
* @param string $entity fully qualified class name of the entity |
164
|
|
|
*/ |
165
|
1 |
|
protected function getEntityBundleShortcut($entity) |
166
|
|
|
{ |
167
|
|
|
// wrap in EntityManager's Class Metadata function avoid problems with cached proxy classes |
168
|
1 |
|
$path = explode('\Entity\\', $entity); |
169
|
|
|
|
170
|
1 |
|
return str_replace('\\', '', $path[0]).':'.$path[1]; |
171
|
|
|
} |
172
|
|
|
} |
173
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.