1: <?php
2:
3: 4: 5: 6: 7: 8: 9: 10:
11:
12: namespace CRUDlex;
13:
14: use Silex\Application;
15: use Silex\ControllerProviderInterface;
16: use Symfony\Component\HttpFoundation\Response;
17: use Symfony\Component\HttpFoundation\StreamedResponse;
18:
19: use CRUDlex\CRUDEntity;
20:
21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41:
42: class CRUDControllerProvider implements ControllerProviderInterface {
43:
44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54:
55: protected function getNotFoundPage(Application $app, $error) {
56: return new Response($app['twig']->render('@crud/notFound.twig', array(
57: 'error' => $error,
58: 'crudEntity' => '',
59: 'layout' => $app['crud.layout']
60: )), 404);
61: }
62:
63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76:
77: protected function getLayout(Application $app, $action, $entity) {
78: if ($app->offsetExists('crud.layout.'.$action.'.'.$entity)) {
79: return $app['crud.layout.'.$action.'.'.$entity];
80: }
81: if ($app->offsetExists('crud.layout.'.$entity)) {
82: return $app['crud.layout.'.$entity];
83: }
84: if ($app->offsetExists('crud.layout.'.$action)) {
85: return $app['crud.layout.'.$action];
86: }
87: return $app['crud.layout'];
88: }
89:
90:
91: 92: 93: 94: 95: 96: 97: 98: 99: 100:
101: public function connect(Application $app) {
102: if ($app->offsetExists('twig.loader.filesystem')) {
103: $app['twig.loader.filesystem']->addPath(__DIR__ . '/../views/', 'crud');
104: }
105:
106: if (!$app->offsetExists('crud.layout')) {
107: $app['crud.layout'] = '@crud/layout.twig';
108: }
109:
110: $class = get_class($this);
111: $factory = $app['controllers_factory'];
112: $factory->get('/resource/static', $class.'::staticFile')
113: ->bind('static');
114: $factory->match('/{entity}/create', $class.'::create')
115: ->bind('crudCreate');
116: $factory->match('/{entity}', $class.'::showList')
117: ->bind('crudList');
118: $factory->match('/{entity}/{id}', $class.'::show')
119: ->bind('crudShow');
120: $factory->match('/{entity}/{id}/edit', $class.'::edit')
121: ->bind('crudEdit');
122: $factory->post('/{entity}/{id}/delete', $class.'::delete')
123: ->bind('crudDelete');
124: $factory->match('/{entity}/{id}/{field}/file', $class.'::renderFile')
125: ->bind('crudRenderFile');
126: $factory->post('/{entity}/{id}/{field}/delete', $class.'::deleteFile')
127: ->bind('crudDeleteFile');
128: return $factory;
129: }
130:
131: 132: 133: 134: 135: 136: 137: 138: 139: 140: 141:
142: public function create(Application $app, $entity) {
143: $crudData = $app['crud']->getData($entity);
144: if (!$crudData) {
145: return $this->getNotFoundPage($app, $app['crud']->translate('entityNotFound'));
146: }
147:
148: $errors = array();
149: $instance = $crudData->createEmpty();
150: $definition = $crudData->getDefinition();
151: $fields = $definition->getEditableFieldNames();
152:
153: if ($app['request']->getMethod() == 'POST') {
154: foreach ($fields as $field) {
155: if ($definition->getType($field) == 'file') {
156: $file = $app['request']->files->get($field);
157: if ($file) {
158: $instance->set($field, $file->getClientOriginalName());
159: }
160: } else {
161: $instance->set($field, $app['request']->get($field));
162: }
163: }
164: $validation = $instance->validate($crudData);
165: if (!$validation['valid']) {
166: $errors = $validation['errors'];
167: $app['session']->getFlashBag()->add('danger', $app['crud']->translate('create.error'));
168: } else {
169: $crudData->create($instance);
170: $id = $instance->get('id');
171: $crudData->createFiles($app['request'], $instance, $entity);
172:
173: $app['session']->getFlashBag()->add('success', $app['crud']->translate('create.success', array($crudData->getDefinition()->getLabel(), $id)));
174: return $app->redirect($app['url_generator']->generate('crudShow', array('entity' => $entity, 'id' => $id)));
175: }
176: }
177:
178: $definition = $crudData->getDefinition();
179:
180: return $app['twig']->render('@crud/form.twig', array(
181: 'crudEntity' => $entity,
182: 'crudData' => $crudData,
183: 'entity' => $instance,
184: 'mode' => 'create',
185: 'errors' => $errors,
186: 'layout' => $this->getLayout($app, 'create', $entity)
187: ));
188: }
189:
190: 191: 192: 193: 194: 195: 196: 197: 198: 199: 200:
201: public function showList(Application $app, $entity) {
202: $crudData = $app['crud']->getData($entity);
203: if (!$crudData) {
204: return $this->getNotFoundPage($app, $app['crud']->translate('entityNotFound'));
205: }
206: $entitiesRaw = $crudData->listEntries();
207: $entities = array();
208: foreach ($entitiesRaw as $curEntity) {
209: $crudData->fetchReferences($curEntity);
210: $entities[] = $curEntity;
211: }
212: $definition = $crudData->getDefinition();
213: return $app['twig']->render('@crud/list.twig', array(
214: 'crudEntity' => $entity,
215: 'definition' => $definition,
216: 'entities' => $entities,
217: 'layout' => $this->getLayout($app, 'list', $entity)
218: ));
219: }
220:
221: 222: 223: 224: 225: 226: 227: 228: 229: 230: 231: 232: 233:
234: public function show(Application $app, $entity, $id) {
235: $crudData = $app['crud']->getData($entity);
236: if (!$crudData) {
237: return $this->getNotFoundPage($app, $app['crud']->translate('entityNotFound'));
238: }
239: $instance = $crudData->get($id);
240: $crudData->fetchReferences($instance);
241: if (!$instance) {
242: return $this->getNotFoundPage($app, $app['crud']->translate('instanceNotFound'));
243: }
244: $definition = $crudData->getDefinition();
245:
246: $childrenLabelFields = $definition->getChildrenLabelFields();
247: $children = array();
248: if (count($childrenLabelFields) > 0) {
249: foreach ($definition->getChildren() as $child) {
250: $childField = $child[1];
251: $childEntity = $child[2];
252: $childLabelField = key_exists($childEntity, $childrenLabelFields) ? $childrenLabelFields[$childEntity] : 'id';
253: $childCrud = $app['crud']->getData($childEntity);
254: $children[] = array(
255: $childCrud->getDefinition()->getLabel(),
256: $childEntity,
257: $childLabelField,
258: $childCrud->listEntries(array($childField => $instance->get('id')))
259: );
260: }
261: }
262:
263: return $app['twig']->render('@crud/show.twig', array(
264: 'crudEntity' => $entity,
265: 'entity' => $instance,
266: 'children' => $children,
267: 'layout' => $this->getLayout($app, 'show', $entity)
268: ));
269: }
270:
271: 272: 273: 274: 275: 276: 277: 278: 279: 280: 281: 282: 283:
284: public function edit(Application $app, $entity, $id) {
285: $crudData = $app['crud']->getData($entity);
286: if (!$crudData) {
287: return $this->getNotFoundPage($app, $app['crud']->translate('entityNotFound'));
288: }
289: $instance = $crudData->get($id);
290: if (!$instance) {
291: return $this->getNotFoundPage($app, $app['crud']->translate('instanceNotFound'));
292: }
293:
294: $definition = $crudData->getDefinition();
295:
296: $errors = array();
297: $fields = $definition->getEditableFieldNames();
298:
299:
300: if ($app['request']->getMethod() == 'POST') {
301: foreach ($fields as $field) {
302: if ($definition->getType($field) == 'file') {
303: $file = $app['request']->files->get($field);
304: if ($file) {
305: $instance->set($field, $file->getClientOriginalName());
306: }
307: } else {
308: $instance->set($field, $app['request']->get($field));
309: }
310: }
311: $validation = $instance->validate($crudData);
312: if (!$validation['valid']) {
313: $app['session']->getFlashBag()->add('danger', $app['crud']->translate('edit.error'));
314: $errors = $validation['errors'];
315: } else {
316: $crudData->update($instance);
317: $crudData->updateFiles($app['request'], $instance, $entity);
318: $app['session']->getFlashBag()->add('success', $app['crud']->translate('edit.success', array($crudData->getDefinition()->getLabel(), $id)));
319: return $app->redirect($app['url_generator']->generate('crudShow', array('entity' => $entity, 'id' => $id)));
320: }
321: }
322:
323: return $app['twig']->render('@crud/form.twig', array(
324: 'crudEntity' => $entity,
325: 'crudData' => $crudData,
326: 'entity' => $instance,
327: 'mode' => 'edit',
328: 'errors' => $errors,
329: 'layout' => $this->getLayout($app, 'edit', $entity)
330: ));
331: }
332:
333: 334: 335: 336: 337: 338: 339: 340: 341: 342: 343: 344: 345:
346: public function delete(Application $app, $entity, $id) {
347: $crudData = $app['crud']->getData($entity);
348: if (!$crudData) {
349: return $this->getNotFoundPage($app, $app['crud']->translate('entityNotFound'));
350: }
351: $instance = $crudData->get($id);
352: if (!$instance) {
353: return $this->getNotFoundPage($app, $app['crud']->translate('instanceNotFound'));
354: }
355:
356: $crudData->deleteFiles($instance, $entity);
357: $deleted = $crudData->delete($id);
358: if ($deleted) {
359: $app['session']->getFlashBag()->add('success', $app['crud']->translate('delete.success', array($crudData->getDefinition()->getLabel())));
360: return $app->redirect($app['url_generator']->generate('crudList', array('entity' => $entity)));
361: } else {
362: $app['session']->getFlashBag()->add('danger', $app['crud']->translate('delete.error', array($crudData->getDefinition()->getLabel())));
363: return $app->redirect($app['url_generator']->generate('crudShow', array('entity' => $entity, 'id' => $id)));
364: }
365: }
366:
367: 368: 369: 370: 371: 372: 373: 374: 375: 376: 377: 378: 379: 380: 381:
382: public function renderFile(Application $app, $entity, $id, $field) {
383: $crudData = $app['crud']->getData($entity);
384: if (!$crudData) {
385: return $this->getNotFoundPage($app, $app['crud']->translate('entityNotFound'));
386: }
387: $instance = $crudData->get($id);
388: $definition = $crudData->getDefinition();
389: if (!$instance) {
390: return $this->getNotFoundPage($app, $app['crud']->translate('instanceNotFound'));
391: }
392: if ($definition->getType($field) != 'file' || !$instance->get($field)) {
393: return $this->getNotFoundPage($app, $app['crud']->translate('instanceNotFound'));
394: }
395: return $crudData->renderFile($instance, $entity, $field);
396: }
397:
398: 399: 400: 401: 402: 403: 404: 405: 406: 407: 408: 409: 410: 411: 412:
413: public function deleteFile(Application $app, $entity, $id, $field) {
414: $crudData = $app['crud']->getData($entity);
415: if (!$crudData) {
416: return $this->getNotFoundPage($app, $app['crud']->translate('entityNotFound'));
417: }
418: $instance = $crudData->get($id);
419: if (!$instance) {
420: return $this->getNotFoundPage($app, $app['crud']->translate('instanceNotFound'));
421: }
422: if (!$crudData->getDefinition()->isRequired($field)) {
423: $crudData->deleteFile($instance, $entity, $field);
424: $instance->set($field, '');
425: $crudData->update($instance);
426: $app['session']->getFlashBag()->add('success', $app['crud']->translate('file.deleted'));
427: } else {
428: $app['session']->getFlashBag()->add('danger', $app['crud']->translate('file.notdeleted'));
429: }
430: return $app->redirect($app['url_generator']->generate('crudShow', array('entity' => $entity, 'id' => $id)));
431: }
432:
433: 434: 435: 436: 437: 438: 439: 440: 441:
442: public function staticFile(Application $app) {
443: $fileParam = $app['request']->get('file');
444: if (!$fileParam) {
445: return $this->getNotFoundPage($app, $app['crud']->translate('resourceNotFound'));
446: }
447:
448: $file = __DIR__.'/../static/'.$fileParam;
449: if (!file_exists($file)) {
450: return $this->getNotFoundPage($app, $app['crud']->translate('resourceNotFound'));
451: }
452:
453: $extension = pathinfo($file, PATHINFO_EXTENSION);
454: $mimeType = '';
455: if (strtolower($extension) === 'css') {
456: $mimeType = 'text/css';
457: } else {
458: $finfo = finfo_open(FILEINFO_MIME_TYPE);
459: $mimeType = finfo_file($finfo, $file);
460: finfo_close($finfo);
461: }
462:
463: $size = filesize($file);
464:
465: $response = new StreamedResponse(function () use ($file) {
466: set_time_limit(0);
467: $handle = fopen($file,"rb");
468: if ($handle !== false) {
469: $chunkSize = 1024 * 1024;
470: while (!feof($handle)) {
471: $buffer = fread($handle, $chunkSize);
472: echo $buffer;
473: flush();
474: }
475: fclose($handle);
476: }
477: }, 200, array(
478: 'Content-Type' => $mimeType,
479: 'Content-Disposition' => 'attachment; filename="'.basename($file).'"',
480: 'Content-length' => $size
481: ));
482: $response->send();
483:
484: return $response;
485: }
486: }
487: