1: <?php
2:
3: /*
4: * This file is part of the CRUDlex package.
5: *
6: * (c) Philip Lehmann-Böhm <philip@philiplb.de>
7: *
8: * For the full copyright and license information, please view the LICENSE
9: * file that was distributed with this source code.
10: */
11:
12: namespace CRUDlex;
13:
14: use Silex\Application;
15: use Silex\ServiceProviderInterface;
16: use Symfony\Component\Yaml\Yaml;
17:
18: use CRUDlex\CRUDEntityDefinition;
19: use CRUDlex\CRUDDataFactoryInterface;
20: use CRUDlex\CRUDEntity;
21: use CRUDlex\CRUDFileProcessorInterface;
22: use CRUDlex\CRUDSimpleFilesystemFileProcessor;
23:
24: /**
25: * The CRUDServiceProvider setups and initializes the whole CRUD system.
26: * After adding it to your Silex-setup, it offers access to {@see CRUDData}
27: * instances, one for each defined entity off the CRUD YAML file.
28: */
29: class CRUDServiceProvider implements ServiceProviderInterface {
30:
31: /**
32: * Holds the {@see CRUDData} instances.
33: */
34: protected $datas;
35:
36: /**
37: * Holds the translation map.
38: */
39: protected $strings;
40:
41: /**
42: * Formats the given time value to a timestring defined by the $pattern
43: * parameter.
44: *
45: * If the value is false (like null), an empty string is
46: * returned. Else, the value is tried to be parsed as datetime via the
47: * given pattern. If that fails, it is tried to be parsed with the pattern
48: * 'Y-m-d H:i:s'. If that fails, the value is returned unchanged. Else, it
49: * is returned formatted with the given pattern. The effect is to shorten
50: * 'Y-m-d H:i:s' to 'Y-m-d' for example.
51: *
52: * @param string $value
53: * the value to be formatted
54: * @param string $pattern
55: * the pattern with which the value is parsed and formatted
56: *
57: * @return string
58: * the formatted value
59: */
60: protected function formatTime($value, $pattern) {
61: if (!$value) {
62: return '';
63: }
64: $result = \DateTime::createFromFormat($pattern, $value);
65: if ($result === false) {
66: $result = \DateTime::createFromFormat('Y-m-d H:i:s', $value);
67: }
68: if ($result === false) {
69: return $value;
70: }
71: return $result->format($pattern);
72: }
73:
74: /**
75: * Initializes the instance.
76: *
77: * @param CRUDDataFactoryInterface $dataFactory
78: * the factory to create the concrete CRUDData instances
79: * @param string $crudFile
80: * the CRUD YAML file to parse
81: * @param string $stringsFile
82: * the YAML file containing the displayed strings
83: * @param CRUDFileProcessorInterface $fileProcessor
84: * the file processor used for file fields
85: */
86: public function init(CRUDDataFactoryInterface $dataFactory, $crudFile, $stringsFile, CRUDFileProcessorInterface $fileProcessor) {
87: $stringsContent = @file_get_contents($stringsFile);
88: if ($stringsContent === false) {
89: throw new \Exception('Could not open CRUD strings file');
90: }
91: $this->strings = Yaml::parse($stringsContent);
92:
93: $crudsContent = @file_get_contents($crudFile);
94: if ($crudsContent === false) {
95: throw new \Exception('Could not open CRUD definition file');
96: }
97: $cruds = Yaml::parse($crudsContent);
98: $this->datas = array();
99: foreach ($cruds as $name => $crud) {
100: $label = key_exists('label', $crud) ? $crud['label'] : $name;
101: $standardFieldLabels = array(
102: 'id' => $this->translate('label.id'),
103: 'created_at' => $this->translate('label.created_at'),
104: 'updated_at' => $this->translate('label.updated_at')
105: );
106: $listFields = key_exists('listFields', $crud) ? $crud['listFields'] : null;
107: $childrenLabelFields = key_exists('childrenLabelFields', $crud) ? $crud['childrenLabelFields'] : array();
108: $definition = new CRUDEntityDefinition($crud['table'],
109: $crud['fields'],
110: $label,
111: $listFields,
112: $standardFieldLabels,
113: $childrenLabelFields);
114: $this->datas[$name] = $dataFactory->createData($definition, $fileProcessor);
115: }
116:
117: foreach($this->datas as $name => $data) {
118: $fields = $data->getDefinition()->getFieldNames();
119: foreach ($fields as $field) {
120: if ($data->getDefinition()->getType($field) == 'reference') {
121: $this->datas[$data->getDefinition()->getReferenceEntity($field)]->getDefinition()->addChild($data->getDefinition()->getTable(), $field, $name);
122: }
123: }
124: }
125:
126: }
127:
128: /**
129: * Implements ServiceProviderInterface::register() registering $app['crud'].
130: * $app['crud'] contains an instance of the CRUDServiceProvider afterwards.
131: *
132: * @param Application $app
133: * the Application instance of the Silex application
134: */
135: public function register(Application $app) {
136: $app['crud'] = $app->share(function() use ($app) {
137: $result = new CRUDServiceProvider();
138: $stringsFile = $app->offsetExists('crud.stringsfile') ? $app['crud.stringsfile'] : __DIR__.'/../strings.yml';
139: $fileProcessor = $app->offsetExists('crud.fileprocessor') ? $app['crud.fileprocessor'] : new CRUDSimpleFilesystemFileProcessor();
140: $result->init($app['crud.datafactory'], $app['crud.file'], $stringsFile, $fileProcessor);
141: return $result;
142: });
143: }
144:
145:
146: /**
147: * Implements ServiceProviderInterface::boot().
148: *
149: * @param Application $app
150: * the Application instance of the Silex application
151: */
152: public function boot(Application $app) {
153: }
154:
155: /**
156: * Getter for the {@see CRUDData} instances.
157: *
158: * @param string $name
159: * the entity name of the desired CRUDData instance
160: *
161: * @return CRUDData
162: * the CRUDData instance or null on invalid name
163: */
164: public function getData($name) {
165: if (!key_exists($name, $this->datas)) {
166: return null;
167: }
168: return $this->datas[$name];
169: }
170:
171: /**
172: * Getter for all available entity names.
173: *
174: * @return array
175: * a list of all available entity names
176: */
177: public function getEntities() {
178: return array_keys($this->datas);
179: }
180:
181: /**
182: * Formats the given value to a date of the format 'Y-m-d'.
183: *
184: * @param string $value
185: * the value, might be of the format 'Y-m-d H:i' or 'Y-m-d'
186: *
187: * @return string
188: * the formatted result or an empty string on null value
189: */
190: public function formatDate($value) {
191: return $this->formatTime($value, 'Y-m-d');
192: }
193:
194:
195: /**
196: * Formats the given value to a date of the format 'Y-m-d H:i'.
197: *
198: * @param string $value
199: * the value, might be of the format 'Y-m-d H:i'
200: *
201: * @return string
202: * the formatted result or an empty string on null value
203: */
204: public function formatDateTime($value) {
205: return $this->formatTime($value, 'Y-m-d H:i');
206: }
207:
208: /**
209: * Picks up the string of the given key from the strings and returns the
210: * value. Optionally replaces placeholder from "{0}" to "{n}" with the values given via
211: * the array $placeholders.
212: *
213: * @param string $key
214: * the key
215: * @param array $placeholders
216: * the optional placeholders
217: *
218: * @return string
219: * the string value or the key in case there was no string found for the key
220: */
221: public function translate($key, array $placeholders = array()) {
222: if (!key_exists($key, $this->strings)) {
223: return $key;
224: }
225: $result = $this->strings[$key];
226: $amount = count($placeholders);
227: for ($i = 0; $i < $amount; ++$i) {
228: $result = str_replace('{'.$i.'}', $placeholders[$i], $result);
229: }
230: return $result;
231: }
232:
233: /**
234: * Calls PHPs
235: * {@link http://php.net/manual/en/function.basename.php basename} and
236: * returns it's result.
237: *
238: * @param string $value
239: * the value to be handed to basename
240: *
241: * @return string
242: * the result of basename
243: */
244: public function basename($value) {
245: return basename($value);
246: }
247:
248: }
249: