Initial commit
This commit is contained in:
147
src/Service/AnalyzerService.php
Normal file
147
src/Service/AnalyzerService.php
Normal file
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
/**
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 magdev
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author magdev
|
||||
* @copyright 2018 Marco Grätsch
|
||||
* @package magdev/dossier
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
*/
|
||||
|
||||
namespace Magdev\Dossier\Service;
|
||||
|
||||
use Magdev\Dossier\Analyzer\Base\AnalyzableInterface;
|
||||
use Magdev\Dossier\Analyzer\Base\AnalyzerInterface;
|
||||
use Magdev\Dossier\Analyzer\Base\AnalyzerException;
|
||||
|
||||
/**
|
||||
* Service to analyze models
|
||||
*
|
||||
* @author magdev
|
||||
*/
|
||||
class AnalyzerService
|
||||
{
|
||||
/**
|
||||
* Configuration service
|
||||
* @var \Magdev\Dossier\Service\AnalyzerService
|
||||
*/
|
||||
protected $config = null;
|
||||
|
||||
/**
|
||||
* Monolog service
|
||||
* @var \Magdev\Dossier\Service\MonologService
|
||||
*/
|
||||
protected $logger = null;
|
||||
|
||||
/**
|
||||
* Analyzer objects
|
||||
* @var \ArrayObject
|
||||
*/
|
||||
protected $analyzers = null;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Magdev\Dossier\Service\ConfigService $config
|
||||
* @param \Magdev\Dossier\Service\MonologService $logger
|
||||
*/
|
||||
public function __construct(ConfigService $config, MonologService $logger)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->logger = $logger;
|
||||
$this->analyzers = new \ArrayObject();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get all analyzers
|
||||
*
|
||||
* @return \ArrayObject
|
||||
*/
|
||||
public function getAnalyzers(): \ArrayObject
|
||||
{
|
||||
return $this->analyzers;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add an analyzer
|
||||
*
|
||||
* @param \Magdev\Dossier\Analyzer\Base\AnalyzerInterface $analyzer
|
||||
* @return \Magdev\Dossier\Service\AnalyzerService
|
||||
* @throws \Magdev\Dossier\Analyzer\Base\AnalyzerException
|
||||
*/
|
||||
public function addAnalyzer(AnalyzerInterface $analyzer): AnalyzerService
|
||||
{
|
||||
if ($this->hasAnalyzer($analyzer->getName())) {
|
||||
throw new AnalyzerException('Analyzer with name '.$name.' already exists');
|
||||
}
|
||||
$this->analyzers->append($analyzer);
|
||||
$this->logger->debug('Analyzer '.get_class($analyzer).' added with name '.$analyzer->getName());
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if an analyzer name is already taken
|
||||
*
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function hasAnalyzer(string $name): bool
|
||||
{
|
||||
return $this->getAnalyzers() instanceof AnalyzableInterface;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get an analyzer by name
|
||||
*
|
||||
* @param string $name
|
||||
* @return \Magdev\Dossier\Analyzer\Base\AnalyzerInterface
|
||||
*/
|
||||
public function getAnalyzer(string $name): ?AnalyzerInterface
|
||||
{
|
||||
foreach ($this->analyzers as $a) {
|
||||
if ($a->getName() == $name) {
|
||||
return $a;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set analyzers
|
||||
*
|
||||
* @param \ArrayObject $analyzers
|
||||
* @return AnalyzerService
|
||||
*/
|
||||
public function setAnalyzers(\ArrayObject $analyzers): AnalyzerService
|
||||
{
|
||||
$this->analyzers = $analyzers;
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
464
src/Service/ConfigService.php
Normal file
464
src/Service/ConfigService.php
Normal file
@@ -0,0 +1,464 @@
|
||||
<?php
|
||||
/**
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 magdev
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author magdev
|
||||
* @copyright 2018 Marco Grätsch
|
||||
* @package magdev/dossier
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
*/
|
||||
|
||||
namespace Magdev\Dossier\Service;
|
||||
|
||||
use Symfony\Component\Config\FileLocator;
|
||||
use Symfony\Component\Config\Resource\FileResource;
|
||||
use Symfony\Component\Config\ConfigCache;
|
||||
use Symfony\Component\Console\Exception\RuntimeException;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
use Symfony\Component\Dotenv\Dotenv;
|
||||
use Symfony\Component\Finder\Finder;
|
||||
use Magdev\Dossier\Config\ConfigLoader;
|
||||
use Magdev\Dossier\Config\Config;
|
||||
use Magdev\Dossier\Style\DossierStyle;
|
||||
use Adbar\Dot;
|
||||
|
||||
/**
|
||||
* Cnfiguration service
|
||||
*
|
||||
* @author magdev
|
||||
*/
|
||||
class ConfigService
|
||||
{
|
||||
const FORMAT_FLAT_ARRAY = 1;
|
||||
const FORMAT_TABLE_ROWS = 2;
|
||||
const FORMAT_PHP_ARRAY = 3;
|
||||
|
||||
const VALUE_SCALAR = 1;
|
||||
const VALUE_INDEXED_ARRAY = 2;
|
||||
|
||||
/**
|
||||
* The config object
|
||||
* @var \Adbar\Dot
|
||||
*/
|
||||
protected $config = null;
|
||||
|
||||
/**
|
||||
* The global config object
|
||||
* @var \Adbar\Dot
|
||||
*/
|
||||
protected $global = null;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
if (file_exists(PROJECT_ROOT.'/.env')) {
|
||||
$dotenv = new Dotenv();
|
||||
$dotenv->load(PROJECT_ROOT.'/.env');
|
||||
}
|
||||
$this->loadConfig();
|
||||
|
||||
mb_internal_encoding(strtoupper($this->config->get('charset')));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the differences between current and global config
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getDiff(array $current = null, array $global = null): array
|
||||
{
|
||||
if (is_null($current)) {
|
||||
$current = $this->config->all();
|
||||
}
|
||||
if (is_null($global)) {
|
||||
$global = $this->global->all();
|
||||
}
|
||||
|
||||
$diff = array();
|
||||
foreach ($current as $key => $value) {
|
||||
if (is_array($value)) {
|
||||
if (!isset($global[$key]) || !is_array($global[$key])) {
|
||||
$diff[$key] = $value;
|
||||
} else {
|
||||
$newDiff = $this->getDiff($value, $global[$key]);
|
||||
if (!empty($newDiff)) {
|
||||
$diff[$key] = $newDiff;
|
||||
}
|
||||
}
|
||||
} else if (!array_key_exists($key, $global) || $global[$key] !== $value) {
|
||||
$diff[$key] = $value;
|
||||
}
|
||||
}
|
||||
return $diff;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the Dot object
|
||||
*
|
||||
* @return \Adbar\Dot
|
||||
*/
|
||||
public function getConfig(): Dot
|
||||
{
|
||||
return $this->config;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the global Dot object
|
||||
*
|
||||
* @return \Adbar\Dot
|
||||
*/
|
||||
public function getGlobalConfig(): Dot
|
||||
{
|
||||
return $this->global;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delegate method calls to Dot
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $args
|
||||
* @throws \BadFunctionCallException
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call(string $method, array $args)
|
||||
{
|
||||
if (!method_exists($this->config, $method)) {
|
||||
throw new \BadFunctionCallException('Unknown method: '.$method);
|
||||
}
|
||||
return call_user_func_array(array($this->config, $method), $args);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get all configuration values
|
||||
*
|
||||
* @param int $format One of FORMAT_* constants
|
||||
* @return array
|
||||
*/
|
||||
public function all(int $format = self::FORMAT_PHP_ARRAY): array
|
||||
{
|
||||
switch ($format) {
|
||||
case self::FORMAT_FLAT_ARRAY:
|
||||
$data = $this->allFlat();
|
||||
break;
|
||||
|
||||
default:
|
||||
case self::FORMAT_PHP_ARRAY:
|
||||
$data = $this->config->all();
|
||||
break;
|
||||
}
|
||||
ksort($data, SORT_NATURAL);
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set a configuration value
|
||||
*
|
||||
* @param array|int|string $keys
|
||||
* @param mixed $value
|
||||
* @param bool $global
|
||||
* @return \Magdev\Dossier\Service\ConfigService
|
||||
*/
|
||||
public function set($keys, $value, bool $global = false): ConfigService
|
||||
{
|
||||
$this->config->set($keys, $value);
|
||||
if ($global) {
|
||||
$this->global->set($keys, $value);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Unset a configuration value
|
||||
*
|
||||
* @param unknown $keys
|
||||
* @return \Magdev\Dossier\Service\ConfigService
|
||||
*/
|
||||
public function unset($keys): ConfigService
|
||||
{
|
||||
if ($this->config->has($keys)) {
|
||||
$this->config->delete($keys);
|
||||
}
|
||||
if ($this->global->has($keys)) {
|
||||
$this->global->delete($keys);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save the global configuration
|
||||
*
|
||||
* @return \Magdev\Dossier\Service\ConfigService
|
||||
*/
|
||||
public function saveGlobalConfig(): ConfigService
|
||||
{
|
||||
$yaml = '';
|
||||
$config = $this->global->all();
|
||||
if (!empty($config)) {
|
||||
$yaml = Yaml::dump($config, 4, 3);
|
||||
}
|
||||
return $this->saveYaml(getenv('HOME').'/.dossier', $yaml);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save the local configuration
|
||||
*
|
||||
* @return \Magdev\Dossier\Service\ConfigService
|
||||
*/
|
||||
public function saveProjectConfig(): ConfigService
|
||||
{
|
||||
$yaml = '';
|
||||
$config = $this->getDiff();
|
||||
if (!empty($config)) {
|
||||
$yaml = Yaml::dump($config, 4, 3);
|
||||
}
|
||||
return $this->saveYaml(PROJECT_ROOT.'/.conf', $yaml);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if a value is stored in global configuration
|
||||
*
|
||||
* @param string $path
|
||||
* @param mixed $value
|
||||
* @return bool
|
||||
*/
|
||||
public function isGlobalConfig(string $path, $value): bool
|
||||
{
|
||||
if ($this->global->has($path) && $this->global->get($path) == $value) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save configuration
|
||||
*
|
||||
* @return \Magdev\Dossier\Service\ConfigService
|
||||
*/
|
||||
public function save(): ConfigService
|
||||
{
|
||||
return $this->saveGlobalConfig()
|
||||
->saveProjectConfig()
|
||||
->loadConfig();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get all config values as flat array
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function allFlat(): array
|
||||
{
|
||||
$iterator = new \RecursiveIteratorIterator(new \RecursiveArrayIterator($this->all()), \RecursiveIteratorIterator::SELF_FIRST);
|
||||
$path = array();
|
||||
$flatArray = array();
|
||||
|
||||
foreach ($iterator as $key => $value) {
|
||||
$path[$iterator->getDepth()] = $key;
|
||||
|
||||
if (!is_array($value)) {
|
||||
$flatArray[implode('.', array_slice($path, 0, $iterator->getDepth() + 1))] = $value;
|
||||
}
|
||||
}
|
||||
return $flatArray;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get all config values as table rows
|
||||
*
|
||||
* @param \Magdev\Dossier\Style\DossierStyle $io
|
||||
* @param int $booleanWidth
|
||||
* @return array
|
||||
*/
|
||||
public function allTable(DossierStyle $io, int $booleanWidth = null): array
|
||||
{
|
||||
$all = $this->allFlat();
|
||||
$rows = array();
|
||||
|
||||
foreach ($all as $path => $value) {
|
||||
$global = $this->isGlobalConfig($path, $value);
|
||||
|
||||
switch (gettype($value)) {
|
||||
case 'string':
|
||||
if ($value !== trim($value)) {
|
||||
$value = "'$value'";
|
||||
}
|
||||
break;
|
||||
|
||||
case 'bool':
|
||||
case 'boolean':
|
||||
$value = $value ? 'true' : 'false';
|
||||
break;
|
||||
}
|
||||
|
||||
$rows[] = array($path, $value, $io->align($io->bool($global), $booleanWidth, DossierStyle::ALIGN_CENTER));
|
||||
}
|
||||
return $rows;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Find all themes in available directories
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function findThemes(bool $all = true): array
|
||||
{
|
||||
$folders = array(
|
||||
PROJECT_ROOT.'/.conf/tpl',
|
||||
getenv('HOME').'/.dossier/tpl',
|
||||
DOSSIER_ROOT.'/app/tpl'
|
||||
);
|
||||
|
||||
$finder = new Finder();
|
||||
$finder->ignoreUnreadableDirs()
|
||||
->directories()
|
||||
->sortByName()
|
||||
->depth('== 0');
|
||||
|
||||
foreach ($folders as $folder) {
|
||||
if (file_exists($folder)) {
|
||||
$finder->in($folder);
|
||||
}
|
||||
}
|
||||
|
||||
$themes = array();
|
||||
foreach ($finder as $file) {
|
||||
/* @var $file \SplFileInfo */
|
||||
$path = str_replace(
|
||||
array(DOSSIER_ROOT, PROJECT_ROOT, getenv('HOME')),
|
||||
array('${DOSSIER}', '${PROJECT}', '${HOME}'),
|
||||
$file->getPathInfo()->getRealpath()
|
||||
);
|
||||
$themes[$file->getFilename()] = $path;
|
||||
}
|
||||
|
||||
ksort($themes);
|
||||
if ($all) {
|
||||
return $themes;
|
||||
}
|
||||
|
||||
$themesSorted = array();
|
||||
foreach ($themes as $name => $path) {
|
||||
$index = array_search($path, $folders);
|
||||
|
||||
if (!array_key_exists($name, $themesSorted)) {
|
||||
$themesSorted[$name] = $path;
|
||||
} else {
|
||||
$existingIndex = array_search($themesSorted[$name], $folders);
|
||||
if ($index < $existingIndex) {
|
||||
$themesSorted[$name] = $path;
|
||||
}
|
||||
}
|
||||
}
|
||||
return $themesSorted;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save YAML to config file
|
||||
*
|
||||
* @param string $targetDir
|
||||
* @param string $yaml
|
||||
* @return \Magdev\Dossier\Service\ConfigService
|
||||
*/
|
||||
protected function saveYaml(string $targetDir, string $yaml): ConfigService
|
||||
{
|
||||
if (!is_dir($targetDir)) {
|
||||
mkdir($targetDir, 0755, true);
|
||||
}
|
||||
file_put_contents($targetDir.'/dossier.yaml', $yaml);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load the configuration
|
||||
*
|
||||
* @return ConfigService
|
||||
*/
|
||||
protected function loadConfig(): ConfigService
|
||||
{
|
||||
clearstatcache();
|
||||
$configDirectories = array(DOSSIER_ROOT.'/app/conf', getenv('HOME').'/.dossier', PROJECT_ROOT.'/.conf');
|
||||
|
||||
$env = getenv('APP_ENV') ?: 'prod';
|
||||
|
||||
$cachePath = DOSSIER_CACHE.'/src/'.strtolower($env).'DossierCachedConfig.php';
|
||||
|
||||
$fileLocator = new FileLocator($configDirectories);
|
||||
$loader = new ConfigLoader($fileLocator);
|
||||
$cache = new ConfigCache($cachePath, getenv('APP_DEBUG'));
|
||||
|
||||
if (!$cache->isFresh()) {
|
||||
$resources = array();
|
||||
$configFiles = $fileLocator->locate('dossier.yaml', null, false);
|
||||
|
||||
$envConfigFiles = $fileLocator->locate('dossier_'.strtolower($env).'.yaml', null, false);
|
||||
if (!is_array($envConfigFiles)) {
|
||||
$envConfigFiles = array($envConfigFiles);
|
||||
}
|
||||
$configFiles = array_merge($configFiles, $envConfigFiles);
|
||||
|
||||
foreach ($configFiles as $configFile) {
|
||||
$loader->load($configFile);
|
||||
$resources[] = new FileResource($configFile);
|
||||
}
|
||||
$code = '<?php'.PHP_EOL.'return '.(string) $loader.';'.PHP_EOL;
|
||||
$cache->write($code, $resources);
|
||||
}
|
||||
|
||||
$config = require $cachePath;
|
||||
$this->config = new Dot($config['config']);
|
||||
$this->global = new Dot($config['global']);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if an array is an index flat array
|
||||
*
|
||||
* @param array $array
|
||||
* @return bool
|
||||
*/
|
||||
protected function isIndexedFlatArray(array $array): bool
|
||||
{
|
||||
return array_key_exists(0, $array) !== false && is_scalar($array[0]) !== false;
|
||||
}
|
||||
}
|
||||
|
||||
39
src/Service/Exceptions/ServiceException.php
Normal file
39
src/Service/Exceptions/ServiceException.php
Normal file
@@ -0,0 +1,39 @@
|
||||
<?php
|
||||
/**
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 magdev
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author magdev
|
||||
* @copyright 2018 Marco Grätsch
|
||||
* @package magdev/dossier
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
*/
|
||||
|
||||
namespace Magdev\Dossier\Service\Exceptions;
|
||||
|
||||
use Symfony\Component\Console\Exception\RuntimeException;
|
||||
|
||||
class ServiceExcepton extends RuntimeException
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
98
src/Service/FormatterService.php
Normal file
98
src/Service/FormatterService.php
Normal file
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
/**
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 magdev
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author magdev
|
||||
* @copyright 2018 Marco Grätsch
|
||||
* @package magdev/dossier
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
*/
|
||||
|
||||
namespace Magdev\Dossier\Service;
|
||||
|
||||
/**
|
||||
* Formatter Service
|
||||
*
|
||||
* @author magdev
|
||||
*/
|
||||
class FormatterService
|
||||
{
|
||||
const YEAR = 31536000;
|
||||
const MONTH = 2635200;
|
||||
const DAY = 86400;
|
||||
|
||||
/**
|
||||
* Translator
|
||||
* @var \Symfony\Component\Translation\Translator
|
||||
*/
|
||||
protected $translator = null;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Magdev\Resume\Service\TranslatorService $translator
|
||||
*/
|
||||
public function __construct(TranslatorService $translator)
|
||||
{
|
||||
$this->translator = $translator->getTranslator();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Format seconds to years, months
|
||||
*
|
||||
* @TODO Implement translation
|
||||
* @param int $seconds
|
||||
* @param string $key
|
||||
* @return string
|
||||
*/
|
||||
public function formatYearMonthDuration(int $seconds): string
|
||||
{
|
||||
$null = new \DateTime('@0');
|
||||
$length = new \DateTime("@$seconds");
|
||||
|
||||
$years = floor($seconds / self::YEAR);
|
||||
$months = floor($seconds - ($seconds * self::YEAR));
|
||||
|
||||
$msg = $this->translator->transChoice('date.format.year', $years);
|
||||
if ($months) {
|
||||
$msg .= ', '.$this->translator->transChoice('date.format.month', $months);
|
||||
}
|
||||
return $null->diff($length)->format($msg);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Wrapper for formatYearMonthDuration()
|
||||
*
|
||||
* @deprecated
|
||||
* @param int $seconds
|
||||
* @return string
|
||||
*/
|
||||
public function formatExperience(int $seconds): string
|
||||
{
|
||||
return $this->formatYearMonthDuration($seconds);
|
||||
}
|
||||
}
|
||||
213
src/Service/MarkdownService.php
Normal file
213
src/Service/MarkdownService.php
Normal file
@@ -0,0 +1,213 @@
|
||||
<?php
|
||||
/**
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 magdev
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author magdev
|
||||
* @copyright 2018 Marco Grätsch
|
||||
* @package magdev/dossier
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
*/
|
||||
|
||||
namespace Magdev\Dossier\Service;
|
||||
|
||||
use Mni\FrontYAML;
|
||||
use Mni\FrontYAML\Bridge\Parsedown\ParsedownParser;
|
||||
use Symfony\Component\Yaml\Yaml;
|
||||
use Magdev\Dossier\Model\Base\ModelInterface;
|
||||
use Magdev\Dossier\Model\Base\ModelExportableInterface;
|
||||
use Magdev\Dossier\Model\CurriculumVitae;
|
||||
use Magdev\Dossier\Model\Person;
|
||||
use Magdev\Dossier\Model\Intro;
|
||||
use Magdev\Dossier\Model\Project;
|
||||
use Magdev\Dossier\Service\Exceptions\ServiceExcepton;
|
||||
use Magdev\Dossier\Util\Base\DataCollectorInterface;
|
||||
use Magdev\Dossier\Util\DataCollector;
|
||||
|
||||
|
||||
/**
|
||||
* Markdown service
|
||||
*
|
||||
* @author magdev
|
||||
*/
|
||||
class MarkdownService
|
||||
{
|
||||
/**
|
||||
* Parser object
|
||||
* @var \Mni\FrontYAML\Parser
|
||||
*/
|
||||
protected $parser = null;
|
||||
|
||||
/**
|
||||
* Monolog service
|
||||
* @var \Magdev\Dossier\Service\MonologService
|
||||
*/
|
||||
protected $logger = null;
|
||||
|
||||
/**
|
||||
* Formatter service
|
||||
* @var \Magdev\Dossier\Service\MonologService
|
||||
*/
|
||||
protected $formatter = null;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct(MonologService $logger, FormatterService $formatter)
|
||||
{
|
||||
$this->parser = new FrontYAML\Parser(null, new ParsedownParser(new \ParsedownExtra()));
|
||||
$this->logger = $logger;
|
||||
$this->formatter = $formatter;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the Markdown parser object
|
||||
*
|
||||
* @return \Mni\FrontYAML\Parser
|
||||
*/
|
||||
public function getParser(): FrontYAML\Parser
|
||||
{
|
||||
return $this->parser;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a dataCollector with models of markdown files
|
||||
*
|
||||
* @param string $sort
|
||||
* @return \Magdev\Dossier\Util\Base\DataCollectorInterface
|
||||
*/
|
||||
public function getFileSet(string $sort = CurriculumVitae::SORT_DESC): DataCollectorInterface
|
||||
{
|
||||
$person = new Person($this->getDocument(PROJECT_ROOT.'/person.md'));
|
||||
$intro = new Intro($this->getDocument(PROJECT_ROOT.'/intro.md'));
|
||||
|
||||
$cv = new CurriculumVitae($this->formatter);
|
||||
$files = new \FilesystemIterator(PROJECT_ROOT.'/cv');
|
||||
foreach ($files as $file) {
|
||||
/* @var $file \SplFileInfo */
|
||||
$document = $this->getDocument($file->getPathname());
|
||||
$cv->append(new CurriculumVitae\Entry($document));
|
||||
}
|
||||
$cv->setSortDirection($sort)->sort();
|
||||
|
||||
$projects = new \ArrayObject();
|
||||
$files = new \FilesystemIterator(PROJECT_ROOT.'/projects');
|
||||
foreach ($files as $file) {
|
||||
/* @var $file \SplFileInfo */
|
||||
$document = $this->getDocument($file->getPathname());
|
||||
$projects->append(new Project($document));
|
||||
}
|
||||
|
||||
|
||||
return new DataCollector(array(
|
||||
'intro' => $intro,
|
||||
'person' => $person,
|
||||
'cv' => $cv,
|
||||
'projects' => $projects,
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse a markdown file
|
||||
*
|
||||
* @param $srcfile string
|
||||
* @return \Mni\FrontYAML\Document
|
||||
*/
|
||||
public function getDocument(string $srcfile, bool $parseMarkdown = true): FrontYAML\Document
|
||||
{
|
||||
$content = '';
|
||||
if (file_exists($srcfile)) {
|
||||
$content = file_get_contents($srcfile);
|
||||
$this->logger->debug(mb_strlen($content).' bytes loaded from file '.$srcfile);
|
||||
}
|
||||
return $this->getParser()->parse($content, $parseMarkdown);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save Markdown data
|
||||
*
|
||||
* @param string $path
|
||||
* @param array $data
|
||||
* @param string $text
|
||||
* @param bool $overwrite
|
||||
* @return \Magdev\Dossier\Service\MarkdownService
|
||||
*/
|
||||
public function save(string $path, array $data, string $text, bool $overwrite = true): MarkdownService
|
||||
{
|
||||
$content = '';
|
||||
|
||||
if (sizeof($data)) {
|
||||
$content .= '---'.PHP_EOL;
|
||||
$content .= Yaml::dump($data, 1, 2);
|
||||
$content .= '---'.PHP_EOL;
|
||||
}
|
||||
|
||||
if ($text) {
|
||||
$content .= $text.PHP_EOL;
|
||||
}
|
||||
|
||||
return $this->saveFile($path, $content, $overwrite);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Save the contents to a file and creates backup copy
|
||||
*
|
||||
* @param string $path
|
||||
* @param string $content
|
||||
* @param bool $overwrite
|
||||
* @return \Magdev\Dossier\Service\MarkdownService
|
||||
*/
|
||||
protected function saveFile(string $path, string $content, bool $overwrite = true): MarkdownService
|
||||
{
|
||||
if (!is_dir(dirname($path))) {
|
||||
mkdir(dirname($path), 0755, true);
|
||||
}
|
||||
|
||||
if ($content) {
|
||||
if ($overwrite) {
|
||||
if (file_exists($path.'~')) {
|
||||
@unlink($path.'~');
|
||||
}
|
||||
@copy($path, $path.'~');
|
||||
|
||||
if (file_put_contents($path, $content) === false) {
|
||||
throw new ServiceExcepton('Error while writing '.$path);
|
||||
}
|
||||
$this->logger->debug(mb_strlen($content).' bytes written to file '.$path);
|
||||
return $this;
|
||||
}
|
||||
if (!file_exists($path)) {
|
||||
if (file_put_contents($path, $content) === false) {
|
||||
throw new ServiceExcepton('Error while writing '.$path);
|
||||
}
|
||||
$this->logger->debug(mb_strlen($content).' bytes written to file '.$path);
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
77
src/Service/MinifierService.php
Normal file
77
src/Service/MinifierService.php
Normal file
@@ -0,0 +1,77 @@
|
||||
<?php
|
||||
/**
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 magdev
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author magdev
|
||||
* @copyright 2018 Marco Grätsch
|
||||
* @package magdev/dossier
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
*/
|
||||
|
||||
namespace Magdev\Dossier\Service;
|
||||
|
||||
use zz\Html\HTMLMinify;
|
||||
|
||||
/**
|
||||
* HTML Minifier Service
|
||||
*
|
||||
* @author magdev
|
||||
*/
|
||||
class MinifierService
|
||||
{
|
||||
/**
|
||||
* Monolog service
|
||||
* @var \Magdev\Dossier\Service\MonologService
|
||||
*/
|
||||
protected $logger = null;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Magdev\Dossier\Service\MonologService $logger
|
||||
*/
|
||||
public function __construct(MonologService $logger)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Minify HTML
|
||||
*
|
||||
* @param string $html
|
||||
* @return string
|
||||
*/
|
||||
public function minify(string $html): string
|
||||
{
|
||||
if (!getenv('APP_DEBUG')) {
|
||||
$html = HTMLMinify::minify($html, array(
|
||||
'optimizationLevel' => HTMLMinify::OPTIMIZATION_ADVANCED,
|
||||
'doctype' => HTMLMinify::DOCTYPE_HTML5,
|
||||
));
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
}
|
||||
|
||||
104
src/Service/MonologService.php
Normal file
104
src/Service/MonologService.php
Normal file
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
/**
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 magdev
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author magdev
|
||||
* @copyright 2018 Marco Grätsch
|
||||
* @package magdev/dossier
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
*/
|
||||
|
||||
namespace Magdev\Dossier\Service;
|
||||
|
||||
use Monolog\Logger;
|
||||
use Monolog\Handler\StreamHandler;
|
||||
use Monolog\Processor\IntrospectionProcessor;
|
||||
|
||||
/**
|
||||
* Log service
|
||||
*
|
||||
* @author magdev
|
||||
*/
|
||||
class MonologService
|
||||
{
|
||||
/**
|
||||
* Configuration service
|
||||
* @var \Magdev\Dossier\Service\ConfigService
|
||||
*/
|
||||
protected $config = null;
|
||||
|
||||
/**
|
||||
* Monolog logger
|
||||
* @var \Monolog\Logger
|
||||
*/
|
||||
protected $logger = null;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Magdev\Dossier\Service\ConfigService $config
|
||||
*/
|
||||
public function __construct(ConfigService $config)
|
||||
{
|
||||
$this->config = $config;
|
||||
|
||||
$logLevel = getenv('APP_DEBUG') ? Logger::DEBUG : $config->get('monolog.log_level', Logger::INFO);
|
||||
|
||||
$this->logger = new Logger('dossier');
|
||||
$this->logger->pushHandler(new StreamHandler(PROJECT_ROOT.'/.dossier.log', $logLevel))
|
||||
->pushProcessor(new IntrospectionProcessor(
|
||||
$logLevel,
|
||||
$config->get('monolog.skip_class_partials', array())
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the Logger object
|
||||
*
|
||||
* @return \Monolog\Logger
|
||||
*/
|
||||
public function getLogger(): Logger
|
||||
{
|
||||
return $this->logger;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Delegate method calls to internal Logger
|
||||
*
|
||||
* @param string $method
|
||||
* @param array $args
|
||||
* @throws \BadFunctionCallException
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call(string $method, array $args)
|
||||
{
|
||||
if (!method_exists($this->logger, $method)) {
|
||||
throw new \BadFunctionCallException('Unknown method: '.$method);
|
||||
}
|
||||
return call_user_func_array(array($this->logger, $method), $args);
|
||||
}
|
||||
}
|
||||
|
||||
178
src/Service/OutputHelperService.php
Normal file
178
src/Service/OutputHelperService.php
Normal file
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
/**
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 magdev
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author magdev
|
||||
* @copyright 2018 Marco Grätsch
|
||||
* @package magdev/dossier
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
*/
|
||||
|
||||
namespace Magdev\Dossier\Service;
|
||||
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
|
||||
use Magdev\Dossier\Style\DossierStyle;
|
||||
|
||||
/**
|
||||
* Output helper
|
||||
*
|
||||
* @author magdev
|
||||
* @deprecated
|
||||
*/
|
||||
class OutputHelperService
|
||||
{
|
||||
/**
|
||||
* Output object
|
||||
* @var \Symfony\Component\Console\Output\OutputInterface
|
||||
*/
|
||||
protected $output = null;
|
||||
|
||||
/**
|
||||
* Translator service
|
||||
* @var \Magdev\Dossier\Service\TranslatorService
|
||||
*/
|
||||
protected $translator = null;
|
||||
|
||||
/**
|
||||
* Output style helper
|
||||
* @var \Magdev\Dossier\Style\DossierStyle
|
||||
*/
|
||||
protected $ioStyle = null;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Magdev\Dossier\Service\TranslatorService $translator
|
||||
*/
|
||||
public function __construct(TranslatorService $translator)
|
||||
{
|
||||
$this->translator = $translator;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the output object
|
||||
*
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||
* @return \Magdev\Dossier\Service\OutputHelperService
|
||||
*/
|
||||
public function setOutput(OutputInterface $output): OutputHelperService
|
||||
{
|
||||
$this->output = $output;
|
||||
return $this->addOutputStyles();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the style helper for dossier
|
||||
*
|
||||
* @param \Symfony\Component\Console\Input\InputInterface $input
|
||||
* @param \Symfony\Component\Console\Output\OutputInterface $output
|
||||
* @return \Magdev\Dossier\Style\DossierStyle
|
||||
*/
|
||||
public function getIoStyle(InputInterface $input, OutputInterface $output): DossierStyle
|
||||
{
|
||||
$this->setOutput($output);
|
||||
if (!$this->ioStyle) {
|
||||
$this->ioStyle = new DossierStyle($input, $output);
|
||||
}
|
||||
return $this->ioStyle;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write the application header
|
||||
*
|
||||
* @return \Magdev\Dossier\Service\OutputHelperService
|
||||
*/
|
||||
public function writeApplicationHeader(): OutputHelperService
|
||||
{
|
||||
$this->output->write('<fg=magenta;options=bold>'.base64_decode(DOSSIER_LOGO).'</>');
|
||||
$this->output->writeln('<fg=magenta;options=bold> '.$this->translator->trans('app.header').'</>');
|
||||
$this->output->writeln('');
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write a configuraton value
|
||||
*
|
||||
* @param string $key
|
||||
* @param unknown $value
|
||||
* @return OutputHelperService
|
||||
*/
|
||||
public function writeConfigValue(string $key, $value): OutputHelperService
|
||||
{
|
||||
$this->output->writeln('<fg=cyan;options=bold> '.$this->padRight($key).'</>: '.'<fg=yellow;options=bold> '.$value.'</>');
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Format a boolean value for output
|
||||
*
|
||||
* @param bool $status
|
||||
* @param int $width
|
||||
* @return string
|
||||
*/
|
||||
public function formatBoolean(bool $status, int $width = null): string
|
||||
{
|
||||
$string = $status ? '<fg=green;options=bold>*</>' : '<fg=red;options=bold>-</>';
|
||||
if (is_int($width)) {
|
||||
$indent = floor(($width - 1) / 2);
|
||||
$string = str_repeat(' ', $indent).$string;
|
||||
}
|
||||
return $string;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add some output styles to the output object
|
||||
*
|
||||
* @return \Magdev\Dossier\Service\OutputHelperService
|
||||
*/
|
||||
protected function addOutputStyles(): OutputHelperService
|
||||
{
|
||||
$formatter = $this->output->getFormatter();
|
||||
$formatter->setStyle('cmd', new OutputFormatterStyle('white', 'blue', array('bold')));
|
||||
$formatter->setStyle('header', new OutputFormatterStyle('magenta', null, array('bold')));
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Pad a string to the right
|
||||
*
|
||||
* @param string $text
|
||||
* @param int $width
|
||||
* @return string
|
||||
*/
|
||||
protected function padRight(string $text, int $width = 50): string
|
||||
{
|
||||
return str_pad($text, $width, ' ', STR_PAD_RIGHT);
|
||||
}
|
||||
}
|
||||
|
||||
176
src/Service/PdfService.php
Normal file
176
src/Service/PdfService.php
Normal file
@@ -0,0 +1,176 @@
|
||||
<?php
|
||||
/**
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 magdev
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author magdev
|
||||
* @copyright 2018 Marco Grätsch
|
||||
* @package magdev/dossier
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
*/
|
||||
|
||||
namespace Magdev\Dossier\Service;
|
||||
|
||||
use PDFShift\PDFShift;
|
||||
use PDFShift\Exceptions\PDFShiftException;
|
||||
use Magdev\Dossier\Service\Exceptions\ServiceExcepton;
|
||||
use Symfony\Component\Console\Exception\RuntimeException;
|
||||
use Magdev\Dossier\Util\DataCollector;
|
||||
|
||||
/**
|
||||
* Service to create PFs with PDFShift API
|
||||
* @author magdev
|
||||
*
|
||||
*/
|
||||
class PdfService
|
||||
{
|
||||
/**
|
||||
* Configuration service
|
||||
* @var \Magdev\Dossier\Service\ConfigService
|
||||
*/
|
||||
protected $config = null;
|
||||
|
||||
/**
|
||||
* Monolog service
|
||||
* @var \Magdev\Dossier\Service\MonologService
|
||||
*/
|
||||
protected $logger = null;
|
||||
|
||||
/**
|
||||
* Template service
|
||||
* @var \Magdev\Dossier\Service\TemplateService
|
||||
*/
|
||||
protected $tpl = null;
|
||||
|
||||
/**
|
||||
* PDFShift API handler
|
||||
* @var \PDFShift\PDFShift
|
||||
*/
|
||||
protected $pdf = null;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Magdev\Dossier\Service\ConfigService $config
|
||||
* @param \Magdev\Dossier\Service\MonologService $logger
|
||||
* @param \Magdev\Dossier\Service\TemplateService $tpl
|
||||
*/
|
||||
public function __construct(ConfigService $config, MonologService $logger, TemplateService $tpl)
|
||||
{
|
||||
$this->config = $config;
|
||||
$this->logger = $logger;
|
||||
$this->tpl = $tpl;
|
||||
|
||||
if (!$this->config->get('pdfshift.apikey')) {
|
||||
throw new ServiceException('PDFShift API-Key not set!');
|
||||
}
|
||||
|
||||
try {
|
||||
PDFShift::setApiKey($this->config->get('pdfshift.apikey'));
|
||||
$this->pdf = new PDFShift(array(
|
||||
'sandbox' => getenv('APP_DEBUG'),
|
||||
'use_print' => $this->config->get('pdfshift.stylesheet.use_print'),
|
||||
'format' => $this->config->get('pdfshift.page.format'),
|
||||
'margin' => $this->config->get('pdfshift.page.margin'),
|
||||
));
|
||||
|
||||
if ($userAgent = $this->config->get('pdfshift.http.user_agent')) {
|
||||
$this->pdf->addHTTPHeader('user-agent', $userAgent);
|
||||
}
|
||||
} catch (PDFShiftException $e) {
|
||||
throw new ServiceExcepton('Error initializing PDFShift client', -1, $e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the internal PDFSift handler
|
||||
* @return \PDFShift\PDFShift
|
||||
*/
|
||||
public function getPdfShift(): PDFShift
|
||||
{
|
||||
return $this->pdf;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the PDF
|
||||
*
|
||||
* @param string $htmlFile
|
||||
* @return string
|
||||
*/
|
||||
public function createPdf(string $htmlFile, bool $addHeader = false, bool $addFooter = false, bool $addSecurity = false): string
|
||||
{
|
||||
$html = file_get_contents($htmlFile);
|
||||
$outputDir = dirname($htmlFile);
|
||||
$outputFilename = basename($htmlFile, '.html').'.pdf';
|
||||
|
||||
if ($addSecurity) {
|
||||
$securityConfig = $this->config->get('pdfshift.security');
|
||||
if (isset($securityConfig['userPassword']) && isset($securityConfig['ownerPassword'])) {
|
||||
$this->pdf->protect($securityConfig);
|
||||
}
|
||||
}
|
||||
|
||||
if ($addHeader) {
|
||||
$this->pdf->setHeader($this->createHeader(new DataCollector()), $this->config->get('pdfshift.header.spacing'));
|
||||
}
|
||||
|
||||
if ($addFooter) {
|
||||
$this->pdf->setFooter($this->createHeader(new DataCollector()), $this->config->get('pdfshift.footer.spacing'));
|
||||
}
|
||||
|
||||
$this->pdf->convert($html);
|
||||
$this->pdf->save($outputDir.'/'.$outputFilename);
|
||||
|
||||
if (!file_exists($outputDir.'/'.$outputFilename)) {
|
||||
throw new RuntimeException('Failed to create PDF file at '.$outputDir.'/'.$outputFilename);
|
||||
}
|
||||
return $outputDir.'/'.$outputFilename;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the header HTML
|
||||
*
|
||||
* @param \Magdev\Dossier\Util\DataCollector $vars
|
||||
* @return string
|
||||
*/
|
||||
public function createHeader(DataCollector $data): string
|
||||
{
|
||||
return $this->tpl->renderDocument('parts/pdf/header.html.twig', $data);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create the footer HTML
|
||||
*
|
||||
* @param \Magdev\Dossier\Util\DataCollector $vars
|
||||
* @return string
|
||||
*/
|
||||
public function createFooter(DataCollector $data): string
|
||||
{
|
||||
return $this->tpl->renderDocument('parts/pdf/footer.html.twig', $data);
|
||||
}
|
||||
}
|
||||
|
||||
186
src/Service/PharHelperService.php
Normal file
186
src/Service/PharHelperService.php
Normal file
@@ -0,0 +1,186 @@
|
||||
<?php
|
||||
/**
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 magdev
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author magdev
|
||||
* @copyright 2018 Marco Grätsch
|
||||
* @package magdev/dossier
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
*/
|
||||
|
||||
namespace Magdev\Dossier\Service;
|
||||
|
||||
|
||||
use Symfony\Component\Console\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* Phar helper
|
||||
*
|
||||
* @author magdev
|
||||
*/
|
||||
class PharHelperService
|
||||
{
|
||||
/**
|
||||
* The Phar URL if inside of an archive
|
||||
* @var string
|
||||
*/
|
||||
private $pharUrl = '';
|
||||
|
||||
/**
|
||||
* Monolog service
|
||||
* @var \Magdev\Dossier\Service\MonologService
|
||||
*/
|
||||
protected $logger = null;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*/
|
||||
public function __construct(MonologService $logger)
|
||||
{
|
||||
$this->pharUrl = \Phar::running(true);
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Check if running inside a phar-archive
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isInPhar(): bool
|
||||
{
|
||||
return $this->pharUrl != '';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the full URL for a file inside a phar-archive
|
||||
*
|
||||
* @param string $append
|
||||
* @return string
|
||||
*/
|
||||
public function getPharUrl(string $append = ''): string
|
||||
{
|
||||
if ($this->isInPhar()) {
|
||||
if (!$append) {
|
||||
return $this->pharUrl;
|
||||
}
|
||||
return $this->pharUrl.'/'.$append;
|
||||
}
|
||||
|
||||
if (!$append) {
|
||||
return DOSSIER_ROOT;
|
||||
}
|
||||
return DOSSIER_ROOT.'/'.$append;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Read a file from phar-archive
|
||||
*
|
||||
* @param string $file
|
||||
*/
|
||||
public function read(string $file)
|
||||
{
|
||||
return file_get_contents($this->getPharUrl($file));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a local temp-path for files in phar-archives
|
||||
*
|
||||
* @param string $file
|
||||
* @return string
|
||||
*/
|
||||
public function createLocalTempFile(string $file): string
|
||||
{
|
||||
$tmpfile = tempnam(sys_get_temp_dir(), 'dossier-');
|
||||
$this->copy($file, $tmpfile);
|
||||
return $tmpfile;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Copy a file from source to local fs
|
||||
*
|
||||
* @param string $source Relative path to DOSSIER_ROOT
|
||||
* @param string $target Path on local fs
|
||||
* @return bool
|
||||
*/
|
||||
public function copy(string $source, string $target): bool
|
||||
{
|
||||
return copy($this->getPharUrl($source), $target);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Copy a directory from phar-archive to local filesystem
|
||||
*
|
||||
* @TODO Fix recursive directory iteration
|
||||
* @param string $source
|
||||
* @param string $target
|
||||
* @return bool
|
||||
*/
|
||||
public function copyDir(string $source, string $target): bool
|
||||
{
|
||||
$rit = new \RecursiveDirectoryIterator(DOSSIER_ROOT.'/'.$source);
|
||||
foreach (new \RecursiveIteratorIterator($rit) as $filename => $current) {
|
||||
if ($current->getFilename() != '.' && $current->getFilename() != '..') {
|
||||
/* @var $current \SplFileInfo */
|
||||
$relpath = str_replace(DOSSIER_ROOT.'/'.$source.'/', '', $current->getRealPath());
|
||||
|
||||
$targetDir = dirname($target.'/'.$relpath);
|
||||
if (!is_dir($targetDir)) {
|
||||
mkdir($targetDir, 0755, true);
|
||||
}
|
||||
|
||||
copy($current->getRealPath(), $target.'/'.$relpath);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Extract the entire Phar archive
|
||||
*
|
||||
* @return \Magdev\Dossier\Service\PharHelperService
|
||||
*/
|
||||
public function extractArchive(string $targetDir): PharHelperService
|
||||
{
|
||||
if ($this->isInPhar()) {
|
||||
if (!is_dir($targetDir)) {
|
||||
mkdir($targetDir, 0755, true);
|
||||
}
|
||||
try {
|
||||
$phar = new \Phar($_SERVER['SCRIPT_FILENAME']);
|
||||
$phar->extractTo($targetDir);
|
||||
} catch (\Exception $e) {
|
||||
throw new RuntimeException('Error while extracting archive', -1, $e);
|
||||
}
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
301
src/Service/StylesheetProcessorService.php
Normal file
301
src/Service/StylesheetProcessorService.php
Normal file
@@ -0,0 +1,301 @@
|
||||
<?php
|
||||
/**
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 magdev
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author magdev
|
||||
* @copyright 2018 Marco Grätsch
|
||||
* @package magdev/dossier
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
*/
|
||||
|
||||
namespace Magdev\Dossier\Service;
|
||||
|
||||
use Leafo\ScssPhp\Compiler;
|
||||
|
||||
/**
|
||||
* LESS CSS processor service
|
||||
*
|
||||
* @author magdev
|
||||
*/
|
||||
class StylesheetProcessorService
|
||||
{
|
||||
const DELIM_MIXINS = 'MIXINS';
|
||||
const DELIM_VARS = 'VARS';
|
||||
|
||||
const TYPE_LESS = 'less';
|
||||
const TYPE_SCSS = 'scss';
|
||||
|
||||
/**
|
||||
* LESS parser
|
||||
* @var \Less_Parser
|
||||
*/
|
||||
protected $lessc = null;
|
||||
|
||||
/**
|
||||
* SCSS compiler
|
||||
* @var \Leafo\ScssPhp\Compiler
|
||||
*/
|
||||
protected $scssc = null;
|
||||
|
||||
/**
|
||||
* Monolog service
|
||||
* @var \Magdev\Dossier\Service\MonologService
|
||||
*/
|
||||
protected $logger = null;
|
||||
|
||||
/**
|
||||
* Template service
|
||||
* @var \Magdev\Dossier\Service\TemplateService
|
||||
*/
|
||||
protected $tpl = null;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $formatter
|
||||
*/
|
||||
public function __construct(MonologService $logger, TemplateService $tpl, $formatter = '\\Leafo\\ScssPhp\\Formatter\\Compressed')
|
||||
{
|
||||
$this->logger = $logger;
|
||||
$this->tpl = $tpl;
|
||||
|
||||
$this->lessc = new \Less_Parser(array(
|
||||
'compress' => !getenv('APP_DEBUG')
|
||||
));
|
||||
|
||||
$this->scssc = new Compiler();
|
||||
if (!getenv('APP_DEBUG')) {
|
||||
$this->scssc->setFormatter($formatter);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the LESS parser object
|
||||
*
|
||||
* @return \Less_Parser
|
||||
*/
|
||||
public function getLessc(): \Less_Parser
|
||||
{
|
||||
return $this->lessc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the SASS parser object
|
||||
*
|
||||
* @return \Leafo\ScssPhp\Compiler
|
||||
*/
|
||||
public function getScssc(): Compiler
|
||||
{
|
||||
return $this->scssc;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse a file and get the CSS
|
||||
*
|
||||
* @param string $file
|
||||
* @return string
|
||||
*/
|
||||
public function parse(string $file): string
|
||||
{
|
||||
if (file_exists($file)) {
|
||||
$this->logger->debug('Pre-Processing stylesheet file: '.$file);
|
||||
|
||||
$type = explode('.', basename($file))[1];
|
||||
if ($type == self::TYPE_LESS) {
|
||||
return $this->lessc->parse(file_get_contents($file))->getCss();
|
||||
}
|
||||
|
||||
if ($type == self::TYPE_SCSS) {
|
||||
return $this->scssc->compile(file_get_contents($file));
|
||||
}
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse theme stylesheets
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function parseThemeStyles(): string
|
||||
{
|
||||
$css = '';
|
||||
$lessFile = $this->tpl->getThemeFile('less/global.less');
|
||||
if (file_exists($lessFile)) {
|
||||
$css .= $this->parse($lessFile);
|
||||
}
|
||||
|
||||
$scssFile = $this->tpl->getThemeFile('scss/global.scss');
|
||||
if (file_exists($scssFile)) {
|
||||
$css .= $this->parse($scssFile);
|
||||
}
|
||||
|
||||
return $css;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Parse user stylesheet
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function parseUserstyles(): string
|
||||
{
|
||||
$css = '';
|
||||
if (file_exists(PROJECT_ROOT.'/'.self::TYPE_LESS.'/userstyles.'.self::TYPE_LESS)) {
|
||||
$this->logger->debug('Pre-Processing user-stylesheet file: '.PROJECT_ROOT.'/'.self::TYPE_LESS.'/userstyles.'.self::TYPE_LESS);
|
||||
$css .= $this->parse(PROJECT_ROOT.'/'.self::TYPE_LESS.'/userstyles.'.self::TYPE_LESS);
|
||||
}
|
||||
if (file_exists(PROJECT_ROOT.'/'.self::TYPE_SCSS.'/userstyles.'.self::TYPE_SCSS)) {
|
||||
$this->logger->debug('Pre-Processing user-stylesheet file: '.PROJECT_ROOT.'/'.self::TYPE_SCSS.'/userstyles.'.self::TYPE_SCSS);
|
||||
$css .= $this->parse(PROJECT_ROOT.'/'.self::TYPE_SCSS.'/userstyles.'.self::TYPE_SCSS);
|
||||
}
|
||||
return $css;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Export LESS variables
|
||||
*
|
||||
* @param string $file
|
||||
* @param string $targetDir
|
||||
* @param string $type
|
||||
* @return \Magdev\Dossier\Service\StylesheetProcessorService
|
||||
*/
|
||||
public function exportVariables(string $file, string $targetDir = PROJECT_ROOT, string $type = self::TYPE_LESS): StylesheetProcessorService
|
||||
{
|
||||
$code = $this->cutFile($file, self::DELIM_VARS);
|
||||
if ($code) {
|
||||
$target = $targetDir.'/'.$type.'/variables.'.$type;
|
||||
file_put_contents($target, $code);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Export LESS Mixins
|
||||
*
|
||||
* @param string $file
|
||||
* @param string $targetDir
|
||||
* @param string $type
|
||||
* @return \Magdev\Dossier\Service\StylesheetProcessorService
|
||||
*/
|
||||
public function exportMixins(string $file, string $targetDir = PROJECT_ROOT, string $type = self::TYPE_LESS): StylesheetProcessorService
|
||||
{
|
||||
$code = $this->cutFile($file, self::DELIM_MIXINS);
|
||||
if ($code) {
|
||||
$target = $targetDir.'/'.$type.'/mixins.'.$type;
|
||||
file_put_contents($target, $code);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Write basic userstyles.less
|
||||
*
|
||||
* @param string $targetDir
|
||||
* @param string $type
|
||||
* @return \Magdev\Dossier\Service\StylesheetProcessorService
|
||||
*/
|
||||
public function writeBasicUserstylesheet(string $targetDir = PROJECT_ROOT, string $type = self::TYPE_LESS): StylesheetProcessorService
|
||||
{
|
||||
if ($type == self::TYPE_LESS) {
|
||||
$code = <<<EOT
|
||||
/**
|
||||
* LESS userstyles for magdev/dossier
|
||||
*/
|
||||
EOT;
|
||||
$path = $targetDir.'/less/userstyles.less';
|
||||
} else if ($type == self::TYPE_SCSS) {
|
||||
$code = <<<EOT
|
||||
/**
|
||||
* SCSS userstyles for magdev/dossier
|
||||
*/
|
||||
EOT;
|
||||
$path = $targetDir.'/scss/userstyles.scss';
|
||||
}
|
||||
$code .= <<<EOT
|
||||
|
||||
@import "mixins";
|
||||
@import "variables";
|
||||
|
||||
// Gobal styles
|
||||
|
||||
@media print {
|
||||
// Print styles
|
||||
}
|
||||
|
||||
@media screen {
|
||||
// Screen styles
|
||||
}
|
||||
EOT;
|
||||
if (!is_dir(dirname($path))) {
|
||||
mkdir(dirname($path), 0755, true);
|
||||
}
|
||||
file_put_contents($path, $code);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Cut parts off a stylesheet file
|
||||
*
|
||||
* @param string $file
|
||||
* @param string $delimiter (MIXINS or VARS)
|
||||
* @return string
|
||||
*/
|
||||
protected function cutFile(string $file, string $delimiter): string
|
||||
{
|
||||
if ($delimiter == self::DELIM_MIXINS || $delimiter == self::DELIM_VARS) {
|
||||
$start = '// '.$delimiter.':START';
|
||||
$end = '// '.$delimiter.':END';
|
||||
|
||||
$fp = fopen($file, 'r');
|
||||
$lines = array();
|
||||
$started = false;
|
||||
|
||||
while ($line = fgets($fp, 1024) !== false) {
|
||||
if ($line == $start) {
|
||||
$started = true;
|
||||
}
|
||||
if ($started) {
|
||||
if ($line == $end) {
|
||||
fclose($fp);
|
||||
return implode(PHP_EOL, $lines);
|
||||
} else {
|
||||
$lines[] = $line;
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose($fp);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
}
|
||||
328
src/Service/TemplateService.php
Normal file
328
src/Service/TemplateService.php
Normal file
@@ -0,0 +1,328 @@
|
||||
<?php
|
||||
/**
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 magdev
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author magdev
|
||||
* @copyright 2018 Marco Grätsch
|
||||
* @package magdev/dossier
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
*/
|
||||
|
||||
namespace Magdev\Dossier\Service;
|
||||
|
||||
use Symfony\Component\Translation\Translator;
|
||||
use Magdev\Dossier\Util\Base\DataCollectorInterface;
|
||||
use Mni\FrontYAML\Parser;
|
||||
|
||||
/**
|
||||
* Template service
|
||||
*
|
||||
* @author magdev
|
||||
*/
|
||||
class TemplateService
|
||||
{
|
||||
/**
|
||||
* Twig object
|
||||
* @var \Twig_Environment
|
||||
*/
|
||||
protected $twig = null;
|
||||
|
||||
/**
|
||||
* Markdown service
|
||||
* @var \Magdev\Dossier\Service\MarkdownService
|
||||
*/
|
||||
protected $markdown = null;
|
||||
|
||||
/**
|
||||
* Translator service
|
||||
* @var \Magdev\Dossier\Service\TranslatorService
|
||||
*/
|
||||
protected $translator = null;
|
||||
|
||||
/**
|
||||
* HTML minifer service
|
||||
* @var \Magdev\Dossier\Service\MinifierService
|
||||
*/
|
||||
protected $minifier = null;
|
||||
|
||||
/**
|
||||
* Configuration service
|
||||
* @var \Magdev\Dossier\Service\ConfigService
|
||||
*/
|
||||
protected $config = null;
|
||||
|
||||
/**
|
||||
* Name of the current theme
|
||||
* @var string
|
||||
*/
|
||||
protected $theme = '';
|
||||
|
||||
/**
|
||||
* Name of the document
|
||||
* @var string
|
||||
*/
|
||||
protected $docname = 'document';
|
||||
|
||||
/**
|
||||
* Monolog service
|
||||
* @var \Magdev\Dossier\Service\MonologService
|
||||
*/
|
||||
protected $logger = null;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Magdev\Dossier\Service\MarkdownService $markdown
|
||||
* @param \Magdev\Dossier\Service\TranslatorService $translator
|
||||
* @param \Magdev\Dossier\Service\MinifierService $minifier
|
||||
* @param \Magdev\Dossier\Service\ConfigService $config
|
||||
* @param \Magdev\Dossier\Service\MonologService $logger
|
||||
*/
|
||||
public function __construct(MarkdownService $markdown, TranslatorService $translator, MinifierService $minifier, ConfigService $config, MonologService $logger)
|
||||
{
|
||||
$this->markdown = $markdown;
|
||||
$this->translator = $translator;
|
||||
$this->minifier = $minifier;
|
||||
$this->config = $config;
|
||||
$this->logger = $logger;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a file from a theme directory
|
||||
*
|
||||
* @param string $file
|
||||
* @param string $theme
|
||||
* @return string
|
||||
*/
|
||||
public function getThemeFile(string $file, string $theme = ''): string
|
||||
{
|
||||
$theme = !$theme ? $this->theme : $theme;
|
||||
|
||||
if (getenv('DOSSIER_THEME_DIR')) {
|
||||
if (is_dir(getenv('DOSSIER_THEME_DIR').'/'.$theme) && file_exists(getenv('DOSSIER_THEME_DIR').'/'.$theme.'/'.$file)) {
|
||||
return getenv('DOSSIER_THEME_DIR').'/'.$theme.'/'.$file;
|
||||
}
|
||||
}
|
||||
if (is_dir(getenv('HOME').'/.dossier/tpl/'.$theme) && file_exists(getenv('HOME').'/.dossier/tpl/'.$theme.'/'.$file)) {
|
||||
return getenv('HOME').'/.dossier/tpl/'.$theme.'/'.$file;
|
||||
}
|
||||
return DOSSIER_ROOT.'/app/tpl/'.$theme.'/'.$file;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the theme
|
||||
*
|
||||
* @param string $theme
|
||||
* @return \Magdev\Dossier\Service\TemplateService
|
||||
*/
|
||||
public function setTheme(string $theme): TemplateService
|
||||
{
|
||||
$this->theme = $theme;
|
||||
|
||||
$loaders = array();
|
||||
if (getenv('DOSSIER_THEME_DIR') && is_dir(getenv('DOSSIER_THEME_DIR').'/'.$theme)) {
|
||||
$loaders[] = new \Twig_Loader_Filesystem(getenv('DOSSIER_THEME_DIR').'/'.$theme);
|
||||
}
|
||||
if (is_dir(getenv('HOME').'/.dossier/tpl/'.$theme)) {
|
||||
$loaders[] = new \Twig_Loader_Filesystem(getenv('HOME').'/.dossier/tpl/'.$theme);
|
||||
}
|
||||
$loaders[] = new \Twig_Loader_Filesystem(DOSSIER_ROOT.'/app/tpl/'.$theme);
|
||||
|
||||
$this->twig = new \Twig_Environment(new \Twig_Loader_Chain($loaders), array(
|
||||
'cache' => new \Twig_Cache_Filesystem(DOSSIER_CACHE, \Twig_Cache_Filesystem::FORCE_BYTECODE_INVALIDATION),
|
||||
'debug' => getenv('APP_DEBUG'),
|
||||
));
|
||||
$this->addTwigExtensions($this->translator->getTranslator(), $this->config);
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the name of the current theme
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getTheme(): string
|
||||
{
|
||||
return $this->theme;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the document name
|
||||
*
|
||||
* @param string $docname
|
||||
* @return \Magdev\Dossier\Service\TemplateService
|
||||
*/
|
||||
public function setDocumentName(string $docname): TemplateService
|
||||
{
|
||||
$this->docname = $docname;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the internal Twig object
|
||||
*
|
||||
* @return \Twig_Environment
|
||||
*/
|
||||
public function getTwig(): \Twig_Environment
|
||||
{
|
||||
return $this->twig;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Render the page
|
||||
*
|
||||
* @param string $template
|
||||
* @param \Magdev\Dossier\Util\Base\DataCollectorInterface $data
|
||||
* @param string $destDir
|
||||
* @return string
|
||||
*/
|
||||
public function render(string $template, DataCollectorInterface $data, string $destDir): string
|
||||
{
|
||||
if (!is_dir($destDir)) {
|
||||
mkdir($destDir, 0755, true);
|
||||
}
|
||||
$vars = $data->getData();
|
||||
$name = isset($vars['name']) ? $vars['name'] : $this->docname;
|
||||
$name .= isset($vars['theme']) ? '.'.$vars['theme'] : '';
|
||||
$path = $destDir.'/'.$name.'.'.$this->translator->getTranslator()->getLocale().'.html';
|
||||
|
||||
$html = $this->twig->render($template, $vars);
|
||||
$html = $this->minifier->minify($html);
|
||||
if (!file_put_contents($path, $html)) {
|
||||
throw new \RuntimeException('Error writing output file: '.$path);
|
||||
}
|
||||
return $path;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Render a template and return the resulted document
|
||||
*
|
||||
* @param string $template
|
||||
* @param \Magdev\Dossier\Util\Base\DataCollectorInterface $data
|
||||
* @return string
|
||||
*/
|
||||
public function renderDocument(string $template, DataCollectorInterface $data): string
|
||||
{
|
||||
$html = $this->twig->render($template, $data->getData());
|
||||
$html = $this->minifier->minify($html);
|
||||
return $html;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Add Twig extensions
|
||||
*
|
||||
* @param $translator \Symfony\Component\Translation\Translator
|
||||
* @param $config \Magdev\Dossier\Service\ConfigService
|
||||
* @return \Magdev\Dossier\Service\TemplateService
|
||||
*/
|
||||
private function addTwigExtensions(Translator $translator, ConfigService $config): TemplateService
|
||||
{
|
||||
$this->twig->addFilter(new \Twig_Filter('trans', function (string $id, array $parameters = array(), string $domain=null, string $locale=null) use ($translator) {
|
||||
return $translator->trans($id, $parameters, $domain, $locale);
|
||||
}));
|
||||
|
||||
$this->twig->addFilter(new \Twig_Filter('transChoice', function (string $id, int $number, array $parameters = array(), string $domain = null, string $locale = null) use ($translator) {
|
||||
return $translator->transChoice($id, $number, $parameters, $domain, $locale);
|
||||
}));
|
||||
|
||||
$this->twig->addFilter(new \Twig_Filter('md', function (string $string) {
|
||||
return \ParsedownExtra::instance('twig')->parse($string);
|
||||
}, array('is_safe' => array('html'))));
|
||||
|
||||
$this->twig->addFilter(new \Twig_Filter('inlinemd', function (string $string) {
|
||||
return \ParsedownExtra::instance('twig')->line($string);
|
||||
}, array('is_safe' => array('html'))));
|
||||
|
||||
$this->twig->addFilter(new \Twig_Filter('unixToDateTime', function (int $unixTime) {
|
||||
return new \DateTime('@'.$unixTime);
|
||||
}));
|
||||
|
||||
$this->twig->addFilter(new \Twig_Filter('filesize', function (int $filesize) {
|
||||
if ($filesize > (1024*1024)) {
|
||||
return round(($filesize/(1024*1024)), 2).' MiB';
|
||||
}
|
||||
if ($filesize > (1024)) {
|
||||
return round(($filesize/1024), 2).' KiB';
|
||||
}
|
||||
return $filesize.' B';
|
||||
}));
|
||||
|
||||
$this->twig->addFilter(new \Twig_Filter('split', function (string $string, string $split = ',') {
|
||||
return explode($split, $string);
|
||||
}));
|
||||
|
||||
$this->twig->addFilter(new \Twig_Filter('merge', function (array $strings, string $glue = ', ') {
|
||||
return implode($glue, $strings);
|
||||
}, array('is_safe' => array('html'))));
|
||||
|
||||
$this->twig->addFilter(new \Twig_Filter('splitmerge', function (string $string, string $split = ',', string $glue = '<br/>') {
|
||||
$parts = explode($split, $string);
|
||||
return $glue ? implode($glue, $parts) : $parts;
|
||||
}, array('is_safe' => array('html'))));
|
||||
|
||||
$this->twig->addFilter(new \Twig_Filter('debug', function ($var) {
|
||||
return getenv('APP_DEBUG') == true ? '<code>'.print_r($var, true).'</code>' : '';
|
||||
}, array('is_safe' => array('html'))));
|
||||
|
||||
$this->twig->addFunction(new \Twig_Function('is_today', function (\DateTime $checkDate) {
|
||||
return (new \DateTime())->diff($checkDate)->days == 0;
|
||||
}));
|
||||
|
||||
$this->twig->addFunction(new \Twig_Function('is_disabled', function (bool $value) {
|
||||
return $value == true;
|
||||
}));
|
||||
|
||||
$this->twig->addFunction(new \Twig_Function('config', function (string $key) use ($config) {
|
||||
if ($config->has($key)) {
|
||||
$value = $config->get($key);
|
||||
if (is_scalar($value)) {
|
||||
return $value;
|
||||
}
|
||||
return json_encode($value, JSON_NUMERIC_CHECK);
|
||||
}
|
||||
return '';
|
||||
}));
|
||||
|
||||
$this->twig->addFunction(new \Twig_Function('parseFilename', function(string $filename) {
|
||||
$parts = explode('.', $filename);
|
||||
return array(
|
||||
'name' => ucfirst($parts[0]),
|
||||
'theme' => ucfirst($parts[1]),
|
||||
'locale' => strtoupper($parts[2]),
|
||||
'type' => strtolower($parts[3]),
|
||||
);
|
||||
}));
|
||||
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
|
||||
154
src/Service/TranslatorService.php
Normal file
154
src/Service/TranslatorService.php
Normal file
@@ -0,0 +1,154 @@
|
||||
<?php
|
||||
/**
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 magdev
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author magdev
|
||||
* @copyright 2018 Marco Grätsch
|
||||
* @package magdev/dossier
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
*/
|
||||
|
||||
namespace Magdev\Dossier\Service;
|
||||
|
||||
use Symfony\Component\Translation\Translator;
|
||||
use Symfony\Component\Translation\Loader\YamlFileLoader;
|
||||
|
||||
/**
|
||||
* Translator Service
|
||||
*
|
||||
* @author magdev
|
||||
*/
|
||||
class TranslatorService
|
||||
{
|
||||
/**
|
||||
* Translator Object
|
||||
* @var \Symfony\Component\Translation\Translator
|
||||
*/
|
||||
protected $translator = null;
|
||||
|
||||
/**
|
||||
* Fallback locales
|
||||
* @var array
|
||||
*/
|
||||
protected $fallbackLocales = array();
|
||||
|
||||
/**
|
||||
* Monolog service
|
||||
* @var \Magdev\Dossier\Service\MonologService
|
||||
*/
|
||||
protected $logger = null;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param string $locale
|
||||
*/
|
||||
public function __construct(ConfigService $config, MonologService $logger)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
$this->fallbackLocales = $config->get('translator.fallback_locales');
|
||||
$this->loadLocale($config->get('translator.locale'));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the locale
|
||||
*
|
||||
* @param string $locale
|
||||
* @return \Magdev\Dossier\Service\TranslatorService
|
||||
*/
|
||||
public function setLocale(string $locale): TranslatorService
|
||||
{
|
||||
return $this->loadLocale($locale);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the internal Translator object
|
||||
*
|
||||
* @return \Symfony\Component\Translation\Translator
|
||||
*/
|
||||
public function getTranslator(): Translator
|
||||
{
|
||||
return $this->translator;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Translate a string
|
||||
*
|
||||
* @param string $id
|
||||
* @param array $parameters
|
||||
* @param string $domain
|
||||
* @param string $locale
|
||||
* @see \Symfony\Component\Translation\Translator::trans()
|
||||
* @return string
|
||||
*/
|
||||
public function trans(string $id, array $parameters = array(), string $domain = null, string $locale = null): string
|
||||
{
|
||||
return $this->getTranslator()->trans($id, $parameters, $domain, $locale);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Translate plural strings
|
||||
*
|
||||
* @param string $id
|
||||
* @param int $number
|
||||
* @param array $parameters
|
||||
* @param string $domain
|
||||
* @param string $locale
|
||||
* @see \Symfony\Component\Translation\Translator::transChoice()
|
||||
* @return string
|
||||
*/
|
||||
public function transChoice(string $id, int $number, array $parameters = array(), string $domain = null, string $locale = null): string
|
||||
{
|
||||
return $this->getTranslator()->transChoice($id, $number, $parameters, $domain, $locale);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Load a locale
|
||||
*
|
||||
* @param string $locale
|
||||
* @return \Magdev\Dossier\Service\TranslatorService
|
||||
*/
|
||||
protected function loadLocale(string $locale): TranslatorService
|
||||
{
|
||||
$this->translator = new Translator($locale);
|
||||
$this->translator->setFallbackLocales($this->fallbackLocales);
|
||||
$this->translator->addLoader('yaml', new YamlFileLoader());
|
||||
|
||||
$this->translator->addResource('yaml', DOSSIER_ROOT.'/app/locale/messages.'.$locale.'.yaml', $locale);
|
||||
|
||||
if (file_exists(getenv('HOME').'/.dossier/locale/messages.'.$locale.'.yaml')) {
|
||||
$this->translator->addResource('yaml', getenv('HOME').'/.dossier/locale/messages.'.$locale.'.yaml', $locale);
|
||||
}
|
||||
|
||||
if (file_exists(PROJECT_ROOT.'/.conf/locale/messages.'.$locale.'.yaml')) {
|
||||
$this->translator->addResource('yaml', PROJECT_ROOT.'/.conf/locale/messages.'.$locale.'.yaml', $locale);
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
174
src/Service/UriHelperService.php
Normal file
174
src/Service/UriHelperService.php
Normal file
@@ -0,0 +1,174 @@
|
||||
<?php
|
||||
/**
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2018 magdev
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*
|
||||
* @author magdev
|
||||
* @copyright 2018 Marco Grätsch
|
||||
* @package magdev/dossier
|
||||
* @license http://opensource.org/licenses/MIT MIT License
|
||||
*/
|
||||
|
||||
namespace Magdev\Dossier\Service;
|
||||
|
||||
use Symfony\Component\Console\Exception\RuntimeException;
|
||||
|
||||
/**
|
||||
* URI helper
|
||||
*
|
||||
* @author magdev
|
||||
*/
|
||||
class UriHelperService
|
||||
{
|
||||
/**
|
||||
* Root directory to strip to generate relative URLs
|
||||
* @var string
|
||||
*/
|
||||
protected $rootDir = '';
|
||||
|
||||
/**
|
||||
* Phar Helper service
|
||||
* @var \Magdev\Dossier\Service\PharHelperService
|
||||
*/
|
||||
protected $pharHelper = null;
|
||||
|
||||
/**
|
||||
* Monolog service
|
||||
* @var \Magdev\Dossier\Service\MonologService
|
||||
*/
|
||||
protected $logger = null;
|
||||
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param \Magdev\Dossier\Service\PharHelperService $helper
|
||||
*/
|
||||
public function __construct(MonologService $logger, PharHelperService $helper)
|
||||
{
|
||||
$this->logger = $logger;
|
||||
$this->pharHelper = $helper;
|
||||
$this->rootDir = PROJECT_ROOT.'/';
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Set the root directory
|
||||
*
|
||||
* @param string $dir
|
||||
* @return \Magdev\Dossier\Service\UrlHelperService
|
||||
*/
|
||||
public function setRootDirectory(string $dir): UrlHelperService
|
||||
{
|
||||
$this->rootDir = $dir;
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get DataURI from file
|
||||
*
|
||||
* @param string $file
|
||||
* @param string $mimetype
|
||||
* @return string
|
||||
*/
|
||||
public function getDataUriFromFile(string $file, $mimetype = null): string
|
||||
{
|
||||
$tmpfile = null;
|
||||
if ($this->pharHelper->isInPhar()) {
|
||||
$tmpfile = $this->pharHelper->createLocalTempFile($file);
|
||||
$f = new \SplFileObject($tmpfile);
|
||||
} else {
|
||||
$f = new \SplFileObject($file);
|
||||
}
|
||||
|
||||
if (!$mimetype) {
|
||||
$fi = new \finfo();
|
||||
$mimetype = $fi->file($f->getRealPath(), FILEINFO_MIME);
|
||||
}
|
||||
$data = file_get_contents($f->getRealPath());
|
||||
|
||||
if ($tmpfile && file_exists($tmpfile)) {
|
||||
@unlink($tmpfile);
|
||||
}
|
||||
|
||||
return $this->toDataUri($data, $mimetype);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get a DataURI from data
|
||||
*
|
||||
* @param mixed $data
|
||||
* @param string $mimetype
|
||||
* @return string
|
||||
*/
|
||||
public function getDataUriFromData($data, $mimetype = 'text/plain'): string
|
||||
{
|
||||
return $this->toDataUri($data, $mimetype);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Open a file in the default editor
|
||||
*
|
||||
* @param string $file
|
||||
* @throws \Symfony\Component\Console\Exception\RuntimeException
|
||||
* @return \Magdev\Dossier\Service\UriHelperService
|
||||
*/
|
||||
public function openFileInEditor(string $file): UriHelperService
|
||||
{
|
||||
if (getenv('XSESSION_IS_UP') == 'yes') {
|
||||
system('xdg-open '.$file);
|
||||
} else if ($editor = getenv('EDITOR')) {
|
||||
system($editor.' '.$file);
|
||||
} else {
|
||||
throw new RuntimeException('Cannot find a responsible editor');
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the relative path for project files
|
||||
*
|
||||
* @param string $realpath
|
||||
* @return string
|
||||
*/
|
||||
public function getRelativePath(string $realpath): string
|
||||
{
|
||||
return str_replace(PROJECT_ROOT.'/', '', $realpath);
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the DataURI
|
||||
*
|
||||
* @param mixed $data
|
||||
* @param string $mimetype
|
||||
* @return string
|
||||
*/
|
||||
protected function toDataUri($data, string $mimetype): string
|
||||
{
|
||||
return 'data:'.$mimetype.'; base64,'.base64_encode($data);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user