1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace BZIon\Form\Transformer; |
4
|
|
|
|
5
|
|
|
use Symfony\Component\Form\DataTransformerInterface; |
6
|
|
|
use Symfony\Component\Form\Exception\TransformationFailedException; |
7
|
|
|
|
8
|
|
|
abstract class AdvancedModelTransformer implements DataTransformerInterface |
9
|
|
|
{ |
10
|
|
|
/** |
11
|
|
|
* @var string[] |
12
|
|
|
*/ |
13
|
|
|
protected $types; |
14
|
|
|
|
15
|
|
|
/** |
16
|
|
|
* @param string[] $type The types of the models |
|
|
|
|
17
|
|
|
*/ |
18
|
1 |
|
public function __construct(array $types) |
19
|
|
|
{ |
20
|
1 |
|
if (empty($types)) { |
21
|
|
|
throw new \Exception("No type has been specified"); |
22
|
|
|
} |
23
|
|
|
|
24
|
1 |
|
$this->types = $types; |
25
|
1 |
|
} |
26
|
|
|
|
27
|
|
|
/** |
28
|
|
|
* Transforms an object (model) to the form representation |
29
|
|
|
* |
30
|
|
|
* @param Model|null $model |
|
|
|
|
31
|
|
|
* @return array |
32
|
|
|
*/ |
33
|
1 |
|
public function transform($models) |
34
|
|
|
{ |
35
|
1 |
|
if ($models === null) { |
36
|
1 |
|
$models = array(); |
37
|
1 |
|
} elseif (!is_array($models)) { |
38
|
|
|
$models = array($models); |
39
|
|
|
} |
40
|
|
|
|
41
|
1 |
|
$data = $json = array(); |
42
|
1 |
|
foreach ($models as $model) { |
43
|
1 |
|
$data[$model->getType()][] = $model->getName(); |
44
|
1 |
|
$json[] = array( |
45
|
1 |
|
'id' => $model->getID(), |
46
|
1 |
|
'name' => $model->getName(), |
47
|
1 |
|
'type' => ucfirst($model->getType()) |
48
|
|
|
); |
49
|
|
|
} |
50
|
|
|
|
51
|
1 |
|
foreach ($data as $type => &$value) { |
52
|
1 |
|
$value = implode(', ', $value); |
53
|
|
|
} |
54
|
|
|
|
55
|
1 |
|
$data['ids'] = json_encode(array( |
56
|
1 |
|
'data' => $json |
57
|
|
|
)); |
58
|
|
|
|
59
|
1 |
|
return $data; |
60
|
|
|
} |
61
|
|
|
|
62
|
|
|
/** |
63
|
|
|
* Get an invalid model of an acceptable type |
64
|
|
|
* |
65
|
|
|
* @param string|null $type The type of the model, or null to select one of |
66
|
|
|
* the specified types |
67
|
|
|
* @return \Model |
68
|
|
|
*/ |
69
|
|
|
protected function invalidModel($type = null) |
70
|
|
|
{ |
71
|
|
|
if ($type === null) { |
72
|
|
|
$type = reset($this->types); // Get the first value of $this->types |
73
|
|
|
} |
74
|
|
|
|
75
|
|
|
$type = ucfirst($type); |
76
|
|
|
|
77
|
|
|
return call_user_func(array($type, 'invalid')); |
78
|
|
|
} |
79
|
|
|
|
80
|
|
|
/** |
81
|
|
|
* Get a model from its name |
82
|
|
|
* @param string $name The name of the model |
83
|
|
|
* @param string $type The type of the model in lower case |
84
|
|
|
* @return NamedModel|null The model or null if no name was specified |
85
|
|
|
*/ |
86
|
1 |
|
protected function getModelFromName($name, $type) |
87
|
|
|
{ |
88
|
1 |
|
if ($name === '') { |
89
|
|
|
return null; |
90
|
|
|
} |
91
|
|
|
|
92
|
1 |
|
if ($type === 'player') { |
93
|
1 |
|
return \Player::getFromUsername($name); |
94
|
|
|
} elseif ($type === 'team') { |
95
|
|
|
return \Team::getFromName($name); |
96
|
|
|
} else { |
97
|
|
|
throw new \InvalidArgumentException('Unsupported model type'); |
98
|
|
|
} |
99
|
|
|
} |
100
|
|
|
|
101
|
|
|
/** |
102
|
|
|
* Transform JSON data provided by javascript to a list of Models |
103
|
|
|
* |
104
|
|
|
* @param string $json The JSON provided to us by javascript, containing |
|
|
|
|
105
|
|
|
* a list of Model IDs and types |
106
|
|
|
* @param array $include An array of Models of each type that will be |
107
|
|
|
* included in the final result |
108
|
|
|
* @return bool|Model[] A list of models, or false if the data was not |
109
|
|
|
* provided by javascript as JSON |
110
|
|
|
*/ |
111
|
1 |
|
protected function transformJSON(&$data, $include = array()) |
112
|
|
|
{ |
113
|
1 |
|
$json = json_decode($data['ids'], true); |
114
|
|
|
|
115
|
1 |
|
if (!isset($json['modified']) || $json['modified'] !== true) { |
116
|
|
|
// The JSON data was not modified; we can proceed to check input |
117
|
|
|
// from other sources |
118
|
1 |
|
return false; |
119
|
|
|
} |
120
|
|
|
|
121
|
|
|
// Array to store IDs for quick access so we can be sure that no |
122
|
|
|
// duplicates are saved |
123
|
|
|
$ids = array(); |
124
|
|
|
|
125
|
|
|
$models = array(); |
126
|
|
|
|
127
|
|
|
foreach ($include as $type => $includedModels) { |
128
|
|
|
foreach ($includedModels as $model) { |
129
|
|
|
$ids[$type][$model->getID()] = true; // Prevent duplication |
130
|
|
|
$models[] = $model; |
131
|
|
|
} |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
foreach ($json['data'] as $key => $object) { |
135
|
|
|
if ($key === 'modified') { |
136
|
|
|
// This is just an object that lets us know javascript provided |
137
|
|
|
// data, we should ignore it |
138
|
|
|
continue; |
139
|
|
|
} |
140
|
|
|
|
141
|
|
|
if (!isset($object['id']) || !isset($object['type'])) { |
142
|
|
|
throw new TransformationFailedException( |
143
|
|
|
"Invalid model provided" |
144
|
|
|
); |
145
|
|
|
} |
146
|
|
|
|
147
|
|
|
$type = strtolower($object['type']); |
148
|
|
|
|
149
|
|
|
// Sanity check so that the user can't generate arbitrary classes |
150
|
|
|
if (!in_array($type, $this->types)) { |
151
|
|
|
throw new TransformationFailedException( |
152
|
|
|
"Objects of type \"{$object['type']}\" are not supported" |
153
|
|
|
); |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
$class = ucfirst($object['type']); |
157
|
|
|
$model = $class::get($object['id']); |
158
|
|
|
|
159
|
|
View Code Duplication |
if ($model->isDeleted()) { |
|
|
|
|
160
|
|
|
// Show an error message if the model provided by javascript is |
161
|
|
|
// invalid - we don't let the validator handle this error, so |
162
|
|
|
// that the user doesn't see a vague warning |
163
|
|
|
throw new TransformationFailedException( |
164
|
|
|
"Invalid model ID provided" |
165
|
|
|
); |
166
|
|
|
} elseif (!isset($ids[$type][$model->getID()])) { |
167
|
|
|
// The model passed the duplication check |
168
|
|
|
$models[] = $model; |
169
|
|
|
$ids[$type][$model->getID()] = true; |
170
|
|
|
} |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
return $models; |
174
|
|
|
} |
175
|
|
|
} |
176
|
|
|
|
This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.
Consider the following example. The parameter
$italy
is not defined by the methodfinale(...)
.The most likely cause is that the parameter was removed, but the annotation was not.