      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: