1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
/* Copyright (C) 2015 Michael Giesler |
4
|
|
|
* |
5
|
|
|
* This file is part of Dembelo. |
6
|
|
|
* |
7
|
|
|
* Dembelo is free software: you can redistribute it and/or modify |
8
|
|
|
* it under the terms of the GNU Affero General Public License as published by |
9
|
|
|
* the Free Software Foundation, either version 3 of the License, or |
10
|
|
|
* (at your option) any later version. |
11
|
|
|
* |
12
|
|
|
* Dembelo is distributed in the hope that it will be useful, |
13
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of |
14
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15
|
|
|
* GNU Affero General Public License 3 for more details. |
16
|
|
|
* |
17
|
|
|
* You should have received a copy of the GNU Affero General Public License 3 |
18
|
|
|
* along with Dembelo. If not, see <http://www.gnu.org/licenses/>. |
19
|
|
|
*/ |
20
|
|
|
|
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* @package AdminBundle |
24
|
|
|
*/ |
25
|
|
|
|
26
|
|
|
namespace AdminBundle\Controller; |
27
|
|
|
|
28
|
|
|
use DembeloMain\Model\Repository\Doctrine\ODM\AbstractRepository; |
29
|
|
|
use DembeloMain\Document\Importfile; |
30
|
|
|
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; |
31
|
|
|
use Symfony\Bundle\FrameworkBundle\Controller\Controller; |
32
|
|
|
use Symfony\Component\HttpFoundation\Request; |
33
|
|
|
use Symfony\Component\HttpFoundation\Response; |
34
|
|
|
use StdClass; |
35
|
|
|
use DembeloMain\Document\Topic; |
36
|
|
|
use Symfony\Component\Serializer\Encoder\JsonEncoder; |
37
|
|
|
|
38
|
|
|
/** |
39
|
|
|
* Class DefaultController |
40
|
|
|
* @Route(service="app.admin_controller_default") |
41
|
|
|
*/ |
42
|
|
|
class DefaultController extends Controller |
43
|
|
|
{ |
44
|
|
|
|
45
|
|
|
/** |
46
|
|
|
* @var string |
47
|
|
|
*/ |
48
|
|
|
private $configTwineDirectory; |
49
|
|
|
|
50
|
|
|
/** |
51
|
|
|
* DefaultController constructor. |
52
|
|
|
* @param string $configTwineDirectory |
53
|
|
|
*/ |
54
|
12 |
|
public function __construct(string $configTwineDirectory) |
55
|
|
|
{ |
56
|
12 |
|
$this->configTwineDirectory = $configTwineDirectory; |
57
|
12 |
|
} |
58
|
|
|
|
59
|
|
|
/** |
60
|
|
|
* @Route("/", name="admin_mainpage") |
61
|
|
|
* |
62
|
|
|
* @return Response |
63
|
|
|
*/ |
64
|
|
|
public function indexAction(): Response |
65
|
|
|
{ |
66
|
|
|
$mainMenuData = [ |
67
|
|
|
['id' => '1', 'type' => 'folder', 'value' => 'Benutzer', 'css' => 'folder_music'], |
68
|
|
|
['id' => '2', 'type' => 'folder', 'value' => 'Lizenznehmer', 'css' => 'folder_music'], |
69
|
|
|
['id' => '3', 'type' => 'folder', 'value' => 'Themenfelder', 'css' => 'folder_music'], |
70
|
|
|
['id' => '4', 'type' => 'folder', 'value' => 'Importe', 'css' => 'folder_music'], |
71
|
|
|
['id' => '5', 'type' => 'folder', 'value' => 'Textknoten', 'css' => 'folder_music'], |
72
|
|
|
]; |
73
|
|
|
|
74
|
|
|
$jsonEncoder = new JsonEncoder(); |
75
|
|
|
|
76
|
|
|
return $this->render('AdminBundle::index.html.twig', array('mainMenuData' => $jsonEncoder->encode($mainMenuData, 'json'))); |
77
|
|
|
} |
78
|
|
|
|
79
|
|
|
/** |
80
|
|
|
* @Route("/users", name="admin_users") |
81
|
|
|
* |
82
|
|
|
* @param Request $request |
83
|
|
|
* @return Response |
84
|
|
|
*/ |
85
|
2 |
|
public function usersAction(Request $request): Response |
86
|
|
|
{ |
87
|
2 |
|
$repository = $this->get('app.model_repository_user'); |
88
|
|
|
|
89
|
2 |
|
$filters = $request->query->get('filter'); |
90
|
|
|
|
91
|
2 |
|
$query = $repository->createQueryBuilder(); |
92
|
2 |
|
if (null !== $filters) { |
93
|
2 |
View Code Duplication |
foreach ($filters as $field => $value) { |
|
|
|
|
94
|
|
|
if (empty($value) && $value !== '0') { |
95
|
|
|
continue; |
96
|
|
|
} |
97
|
|
|
if ($field === 'status') { |
98
|
|
|
//$value = $value === 'aktiv' ? 1 : 0; |
99
|
|
|
$query->field($field)->equals((int) $value); |
100
|
|
|
} else { |
101
|
|
|
$query->field($field)->equals(new \MongoRegex('/.*'.$value.'.*/i')); |
102
|
|
|
} |
103
|
|
|
} |
104
|
|
|
} |
105
|
2 |
|
$users = $query->getQuery()->execute(); |
106
|
|
|
|
107
|
2 |
|
$output = array(); |
108
|
|
|
/* @var $user \DembeloMain\Document\User */ |
109
|
2 |
|
foreach ($users as $user) { |
110
|
1 |
|
$obj = new StdClass(); |
111
|
1 |
|
$obj->id = $user->getId(); |
112
|
1 |
|
$obj->email = $user->getEmail(); |
113
|
1 |
|
$obj->roles = implode(', ', $user->getRoles()); |
114
|
1 |
|
$obj->licenseeId = is_null($user->getLicenseeId()) ? '' : $user->getLicenseeId(); |
115
|
1 |
|
$obj->gender = $user->getGender(); |
116
|
1 |
|
$obj->status = $user->getStatus(); // === 0 ? 'inaktiv' : 'aktiv'; |
117
|
1 |
|
$obj->source = $user->getSource(); |
118
|
1 |
|
$obj->reason = $user->getReason(); |
119
|
1 |
|
$obj->created = date('Y-m-d H:i:s', $user->getMetadata()['created']); |
120
|
1 |
|
$obj->updated = date('Y-m-d H:i:s', $user->getMetadata()['updated']); |
121
|
1 |
|
$output[] = $obj; |
122
|
|
|
} |
123
|
|
|
|
124
|
2 |
|
return new Response(\json_encode($output)); |
125
|
|
|
} |
126
|
|
|
|
127
|
|
|
/** |
128
|
|
|
* @Route("/licensees", name="admin_licensees") |
129
|
|
|
* |
130
|
|
|
* @return Response |
131
|
|
|
*/ |
132
|
2 |
View Code Duplication |
public function licenseesAction(): Response |
|
|
|
|
133
|
|
|
{ |
134
|
2 |
|
$repository = $this->get('app.model_repository_licensee'); |
135
|
|
|
|
136
|
2 |
|
$licensees = $repository->findAll(); |
137
|
|
|
|
138
|
2 |
|
$output = array(); |
139
|
|
|
/* @var $licensee \DembeloMain\Document\Licensee */ |
140
|
2 |
|
foreach ($licensees as $licensee) { |
141
|
1 |
|
$obj = new StdClass(); |
142
|
1 |
|
$obj->id = $licensee->getId(); |
143
|
1 |
|
$obj->name = $licensee->getName(); |
144
|
1 |
|
$output[] = $obj; |
145
|
|
|
} |
146
|
|
|
|
147
|
2 |
|
return new Response(\json_encode($output)); |
148
|
|
|
} |
149
|
|
|
|
150
|
|
|
/** |
151
|
|
|
* @Route("/licenseeSuggest", name="admin_licensee_suggest") |
152
|
|
|
* |
153
|
|
|
* @param Request $request |
154
|
|
|
* @return Response |
155
|
|
|
*/ |
156
|
|
View Code Duplication |
public function licenseeSuggestAction(Request $request): Response |
|
|
|
|
157
|
|
|
{ |
158
|
|
|
$filter = $request->query->get('filter'); |
159
|
|
|
|
160
|
|
|
$searchString = $filter['value']; |
161
|
|
|
|
162
|
|
|
$mongo = $this->get('doctrine_mongodb'); |
163
|
|
|
/* @var $repository \Doctrine\ODM\MongoDB\DocumentRepository */ |
164
|
|
|
$repository = $mongo->getRepository('DembeloMain:Licensee'); |
165
|
|
|
|
166
|
|
|
$licensees = $repository->findBy(array('name' => new \MongoRegex('/'.$searchString.'/')), null, 10); |
167
|
|
|
|
168
|
|
|
$output = array(); |
169
|
|
|
/* @var $licensee \DembeloMain\Document\Licensee */ |
170
|
|
|
foreach ($licensees as $licensee) { |
171
|
|
|
$output[] = array( |
172
|
|
|
'id' => $licensee->getId(), |
173
|
|
|
'value' => $licensee->getName(), |
174
|
|
|
); |
175
|
|
|
} |
176
|
|
|
|
177
|
|
|
return new Response(\json_encode($output)); |
178
|
|
|
} |
179
|
|
|
|
180
|
|
|
/** |
181
|
|
|
* @Route("/topicSuggest", name="admin_topic_suggest") |
182
|
|
|
* |
183
|
|
|
* @param Request $request |
184
|
|
|
* @return Response |
185
|
|
|
*/ |
186
|
|
View Code Duplication |
public function topicSuggestAction(Request $request): Response |
|
|
|
|
187
|
|
|
{ |
188
|
|
|
$filter = $request->query->get('filter'); |
189
|
|
|
|
190
|
|
|
$searchString = $filter['value']; |
191
|
|
|
|
192
|
|
|
$mongo = $this->get('doctrine_mongodb'); |
193
|
|
|
/* @var $repository \Doctrine\ODM\MongoDB\DocumentRepository */ |
194
|
|
|
$repository = $mongo->getRepository('DembeloMain:Topic'); |
195
|
|
|
|
196
|
|
|
/* @var $topics \DembeloMain\Document\Topic[] */ |
197
|
|
|
$topics = $repository->findBy(array('name' => new \MongoRegex('/'.$searchString.'/')), null, 10); |
198
|
|
|
|
199
|
|
|
$output = []; |
200
|
|
|
foreach ($topics as $topic) { |
201
|
|
|
$output[] = array( |
202
|
|
|
'id' => $topic->getId(), |
203
|
|
|
'value' => $topic->getName(), |
204
|
|
|
); |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
return new Response(\json_encode($output)); |
208
|
|
|
} |
209
|
|
|
|
210
|
|
|
/** |
211
|
|
|
* @Route("/topics", name="admin_topics") |
212
|
|
|
* |
213
|
|
|
* @return Response |
214
|
|
|
*/ |
215
|
|
View Code Duplication |
public function topicsAction(): Response |
|
|
|
|
216
|
|
|
{ |
217
|
|
|
$mongo = $this->get('doctrine_mongodb'); |
218
|
|
|
/* @var $repository \Doctrine\ODM\MongoDB\DocumentRepository */ |
219
|
|
|
$repository = $mongo->getRepository('DembeloMain:Topic'); |
220
|
|
|
|
221
|
|
|
$users = $repository->findAll(); |
222
|
|
|
|
223
|
|
|
$output = array(); |
224
|
|
|
/* @var $user \DembeloMain\Document\Topic */ |
225
|
|
|
foreach ($users as $user) { |
226
|
|
|
$obj = new StdClass(); |
227
|
|
|
$obj->id = $user->getId(); |
228
|
|
|
$obj->name = $user->getName(); |
229
|
|
|
$output[] = $obj; |
230
|
|
|
} |
231
|
|
|
|
232
|
|
|
return new Response(\json_encode($output)); |
233
|
|
|
} |
234
|
|
|
|
235
|
|
|
/** |
236
|
|
|
* @Route("/save", name="admin_formsave") |
237
|
|
|
* |
238
|
|
|
* @param Request $request |
239
|
|
|
* @return Response |
240
|
|
|
*/ |
241
|
5 |
|
public function formsaveAction(Request $request): Response |
242
|
|
|
{ |
243
|
5 |
|
$params = $request->request->all(); |
244
|
|
|
|
245
|
5 |
|
if (!isset($params['formtype']) || !in_array($params['formtype'], array('user', 'licensee', 'topic', 'importfile', 'textnode'))) { |
246
|
2 |
|
return new Response(\json_encode(array('error' => true))); |
247
|
|
|
} |
248
|
3 |
|
if (!isset($params['id'])) { |
249
|
1 |
|
return new Response(\json_encode(array('error' => true))); |
250
|
|
|
} |
251
|
2 |
|
$formtype = $params['formtype']; |
252
|
|
|
|
253
|
|
|
/* @var $repository AbstractRepository */ |
254
|
2 |
|
$repository = $this->get('app.model_repository_'.$formtype); |
255
|
|
|
|
256
|
2 |
|
if (isset($params['id']) && $params['id'] == 'new') { |
257
|
|
|
$className = $repository->getClassName(); |
258
|
|
|
$item = new $className(); |
259
|
|
|
} else { |
260
|
2 |
|
$item = $repository->find($params['id']); |
261
|
2 |
|
if (is_null($item) || $item->getId() != $params['id']) { |
262
|
1 |
|
return new Response(\json_encode(array('error' => true))); |
263
|
|
|
} |
264
|
|
|
} |
265
|
|
|
|
266
|
1 |
|
foreach ($params as $param => $value) { |
267
|
1 |
|
if (in_array($param, array('id', 'formtype', 'filename', 'orgname'))) { |
268
|
1 |
|
continue; |
269
|
|
|
} |
270
|
|
|
if ($param == 'password' && empty($value)) { |
271
|
|
|
continue; |
272
|
|
|
} elseif ($param == 'password') { |
273
|
|
|
$encoder = $this->get('security.password_encoder'); |
274
|
|
|
$value = $encoder->encodePassword($item, $value); |
275
|
|
|
} elseif ($param == 'licenseeId' && $value === '') { |
276
|
|
|
$value = null; |
277
|
|
|
} elseif ($param === 'imported' && $value === '') { |
278
|
|
|
$value = null; |
279
|
|
|
} |
280
|
|
|
$method = 'set'.ucfirst($param); |
281
|
|
|
if (method_exists($item, $method)) { |
282
|
|
|
$item->$method($value); |
283
|
|
|
} |
284
|
|
|
} |
285
|
|
|
//var_dump($item);die(); |
286
|
1 |
|
if (method_exists($item, 'setMetadata')) { |
287
|
1 |
|
$item->setMetadata('updated', time()); |
288
|
|
|
} |
289
|
1 |
|
$repository->save($item); |
290
|
|
|
|
291
|
1 |
|
if ($formtype === 'topic' && array_key_exists('imageFileName', $params) && !is_null($params['imageFileName'])) { |
292
|
|
|
$this->saveTopicImage($item, $params['imageFileName'], $params['originalImageName']); |
293
|
|
|
$repository->save($item); |
294
|
|
|
} |
295
|
|
|
|
296
|
1 |
|
if ($formtype == 'importfile' && array_key_exists('filename', $params)) { |
297
|
|
|
$this->saveFile($item, $params['filename'], $params['orgname']); |
298
|
|
|
$repository->save($item); |
299
|
|
|
} |
300
|
|
|
|
301
|
|
|
$output = array( |
302
|
1 |
|
'error' => false, |
303
|
1 |
|
'newId' => $item->getId(), |
304
|
|
|
); |
305
|
|
|
|
306
|
1 |
|
return new Response(\json_encode($output)); |
307
|
|
|
} |
308
|
|
|
|
309
|
|
|
/** |
310
|
|
|
* @Route("/useractivationmail", name="admin_user_activation_mail") |
311
|
|
|
* |
312
|
|
|
* @param Request $request |
313
|
|
|
* @return Response |
314
|
|
|
*/ |
315
|
|
|
public function useractivationmailAction(Request $request): Response |
316
|
|
|
{ |
317
|
|
|
$userId = $request->request->get('userId'); |
318
|
|
|
|
319
|
|
|
/* @var $mongo \Doctrine\Bundle\MongoDBBundle\ManagerRegistry */ |
320
|
|
|
$mongo = $this->get('doctrine_mongodb'); |
321
|
|
|
/* @var $dm \Doctrine\ODM\MongoDB\DocumentManager*/ |
322
|
|
|
$dm = $mongo->getManager(); |
323
|
|
|
|
324
|
|
|
$repository = $mongo->getRepository('DembeloMain:User'); |
325
|
|
|
|
326
|
|
|
/* @var $user \DembeloMain\Document\User */ |
327
|
|
|
$user = $repository->find($userId); |
328
|
|
|
if (null === $user) { |
329
|
|
|
return new Response(\json_encode(['error' => false])); |
330
|
|
|
} |
331
|
|
|
$user->setActivationHash(sha1($user->getEmail().$user->getPassword().\time())); |
332
|
|
|
|
333
|
|
|
$dm->persist($user); |
334
|
|
|
$dm->flush(); |
335
|
|
|
|
336
|
|
|
$message = (new \Swift_Message('waszulesen - Bestätigung der Email-Adresse')) |
337
|
|
|
->setFrom('[email protected]') |
338
|
|
|
->setTo($user->getEmail()) |
339
|
|
|
->setBody( |
340
|
|
|
$this->renderView( |
341
|
|
|
// app/Resources/views/Emails/registration.html.twig |
342
|
|
|
'AdminBundle::Emails/registration.txt.twig', |
343
|
|
|
array('hash' => $user->getActivationHash()) |
344
|
|
|
), |
345
|
|
|
'text/html' |
346
|
|
|
); |
347
|
|
|
|
348
|
|
|
$this->get('mailer')->send($message); |
349
|
|
|
|
350
|
|
|
return new Response(\json_encode(['error' => false])); |
351
|
|
|
} |
352
|
|
|
|
353
|
|
|
/** |
354
|
|
|
* @Route("/textnodes", name="admin_textnodes") |
355
|
|
|
* |
356
|
|
|
* @return Response |
357
|
|
|
*/ |
358
|
1 |
|
public function textnodesAction(): Response |
359
|
|
|
{ |
360
|
1 |
|
$repository = $this->get('app.model_repository_textNode'); |
361
|
1 |
|
$textnodes = $repository->findAll(); |
362
|
|
|
|
363
|
1 |
|
$licenseeIndex = $this->buildLicenseeIndex(); |
364
|
1 |
|
$importfileIndex = $this->buildImportfileIndex(); |
365
|
|
|
|
366
|
1 |
|
$output = array(); |
367
|
|
|
/* @var $textnode \DembeloMain\Document\Textnode */ |
368
|
1 |
|
foreach ($textnodes as $textnode) { |
369
|
1 |
|
$obj = new StdClass(); |
370
|
1 |
|
$obj->id = $textnode->getId(); |
371
|
1 |
|
$obj->arbitraryId = $textnode->getArbitraryId(); |
372
|
1 |
|
$obj->created = $textnode->getCreated()->format('d.m.Y, H:i:s'); |
373
|
1 |
|
$obj->status = $textnode->getStatus() ? 'aktiv' : 'inaktiv'; |
374
|
1 |
|
$obj->access = $textnode->getAccess() ? 'ja' : 'nein'; |
375
|
1 |
|
$obj->licensee = $licenseeIndex[$textnode->getLicenseeId()]; |
376
|
1 |
|
$obj->importfile = isset($importfileIndex[$textnode->getImportfileId()]) ? $importfileIndex[$textnode->getImportfileId()] : 'unbekannt'; |
377
|
1 |
|
$obj->beginning = substr(htmlentities(strip_tags($textnode->getText())), 0, 200)."..."; |
378
|
1 |
|
$obj->financenode = $textnode->isFinanceNode() ? 'ja' : 'nein'; |
379
|
1 |
|
$obj->twineId = $textnode->getTwineId(); |
380
|
1 |
|
$obj->metadata = $this->formatMetadata($textnode->getMetadata()); |
381
|
1 |
|
$output[] = $obj; |
382
|
|
|
} |
383
|
|
|
|
384
|
1 |
|
return new Response(\json_encode($output)); |
385
|
|
|
} |
386
|
|
|
|
387
|
|
|
/** |
388
|
|
|
* saves temporary file to final place |
389
|
|
|
* |
390
|
|
|
* @param Importfile $item importfile instance |
391
|
|
|
* @param string $filename filename hash |
392
|
|
|
* @param string $orgname original name |
393
|
|
|
* @throws \Symfony\Component\DependencyInjection\Exception\InvalidArgumentException |
394
|
|
|
* @throws \RuntimeException |
395
|
|
|
*/ |
396
|
|
|
private function saveFile(Importfile $item, $filename, $orgname) |
397
|
|
|
{ |
398
|
|
|
if (empty($filename) || empty($orgname)) { |
399
|
|
|
return; |
400
|
|
|
} |
401
|
|
|
|
402
|
|
|
$directory = $this->configTwineDirectory; |
403
|
|
|
$file = $directory.$filename; |
404
|
|
|
if (!file_exists($file)) { |
405
|
|
|
return; |
406
|
|
|
} |
407
|
|
|
$finalDirectory = $directory.$item->getLicenseeId().'/'; |
408
|
|
|
if (!is_dir($finalDirectory)) { |
409
|
|
|
if (!mkdir($finalDirectory) && !is_dir($finalDirectory)) { |
410
|
|
|
throw new \RuntimeException(sprintf('Directory "%s" was not created', $finalDirectory)); |
411
|
|
|
} |
412
|
|
|
} |
413
|
|
|
$finalName = $finalDirectory.$item->getId(); |
414
|
|
|
|
415
|
|
|
rename($file, $finalName); |
416
|
|
|
|
417
|
|
|
$item->setOriginalname($orgname); |
418
|
|
|
$item->setFilename($finalName); |
419
|
|
|
} |
420
|
|
|
|
421
|
1 |
|
private function buildLicenseeIndex(): array |
422
|
|
|
{ |
423
|
1 |
|
$repository = $this->get('app.model_repository_licensee'); |
424
|
1 |
|
$licensees = $repository->findAll(); |
425
|
1 |
|
$index = []; |
426
|
1 |
|
foreach ($licensees as $licensee) { |
427
|
1 |
|
$index[$licensee->getID()] = $licensee->getName(); |
428
|
|
|
} |
429
|
|
|
|
430
|
1 |
|
return $index; |
431
|
|
|
} |
432
|
|
|
|
433
|
1 |
|
private function buildImportfileIndex(): array |
434
|
|
|
{ |
435
|
1 |
|
$repository = $this->get('app.model_repository_importfile'); |
436
|
1 |
|
$importfiles = $repository->findAll(); |
437
|
1 |
|
$index = []; |
438
|
1 |
|
foreach ($importfiles as $importfile) { |
439
|
1 |
|
$index[$importfile->getID()] = $importfile->getName(); |
440
|
|
|
} |
441
|
|
|
|
442
|
1 |
|
return $index; |
443
|
|
|
} |
444
|
|
|
|
445
|
|
|
/** |
446
|
|
|
* saves temporary file to final place |
447
|
|
|
* |
448
|
|
|
* @param Topic $item topic instance |
449
|
|
|
* @param string $filename filename hash |
450
|
|
|
* @param string $orgname original name |
451
|
|
|
*/ |
452
|
|
|
private function saveTopicImage(Topic $item, $filename, $orgname) |
453
|
|
|
{ |
454
|
|
|
if (empty($filename) || empty($orgname)) { |
455
|
|
|
return; |
456
|
|
|
} |
457
|
|
|
$directory = $this->container->getParameter('topic_image_directory'); |
458
|
|
|
$finalDirectory = $directory.$item->getId().'/'; |
459
|
|
|
if (!is_dir($finalDirectory)) { |
460
|
|
|
mkdir($finalDirectory); |
461
|
|
|
} |
462
|
|
|
$finalName = $finalDirectory.$orgname; |
463
|
|
|
$file = $directory.$filename; |
464
|
|
|
rename($file, $finalName); |
465
|
|
|
$item->setOriginalImageName($orgname); |
466
|
|
|
$item->setImageFilename($finalName); |
467
|
|
|
} |
468
|
|
|
|
469
|
1 |
|
private function formatMetadata(array $metadata): string |
470
|
|
|
{ |
471
|
1 |
|
$string = ''; |
472
|
1 |
|
foreach ($metadata as $key => $value) { |
473
|
1 |
|
$string .= $key.': '.$value."\n"; |
474
|
|
|
} |
475
|
|
|
|
476
|
1 |
|
return $string; |
477
|
|
|
} |
478
|
|
|
} |
479
|
|
|
|
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.