Skip to content

Commit

Permalink
Merge pull request #1219 from franmomu/feature-refactor-post-processor
Browse files Browse the repository at this point in the history
[Post-Processors] Add timeout option, refactor processors, add tests for all, add/remove/deprecate options
  • Loading branch information
dbu authored Sep 10, 2019
2 parents b6f5406 + 7673195 commit 539b552
Show file tree
Hide file tree
Showing 22 changed files with 1,488 additions and 263 deletions.
50 changes: 50 additions & 0 deletions Exception/Imagine/Filter/PostProcessor/InvalidOptionException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

/*
* This file is part of the `liip/LiipImagineBundle` project.
*
* (c) https://github.com/liip/LiipImagineBundle/graphs/contributors
*
* For the full copyright and license information, please view the LICENSE.md
* file that was distributed with this source code.
*/

namespace Liip\ImagineBundle\Exception\Imagine\Filter\PostProcessor;

use Liip\ImagineBundle\Exception\ExceptionInterface;

class InvalidOptionException extends \RuntimeException implements ExceptionInterface
{
public function __construct(string $message, array $options = [])
{
parent::__construct(sprintf('Invalid post-processor configuration provided (%s) with options %s.',
$message, $this->stringifyOptions($options)));
}

private function stringifyOptions(array $options = []): string
{
if (0 === count($options)) {
return '[]';
}

$options = array_map([$this, 'stringifyOptionValue'], $options);

array_walk($options, function (&$o, $name) {
$o = sprintf('%s="%s"', $name, $o);
});

return sprintf('[%s]', implode(', ', $options));
}

/**
* @param mixed $value
*/
private function stringifyOptionValue($value): string
{
if (is_scalar($value)) {
return $value;
}

return json_encode($value);
}
}
139 changes: 139 additions & 0 deletions Imagine/Filter/PostProcessor/AbstractPostProcessor.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<?php

/*
* This file is part of the `liip/LiipImagineBundle` project.
*
* (c) https://github.com/liip/LiipImagineBundle/graphs/contributors
*
* For the full copyright and license information, please view the LICENSE.md
* file that was distributed with this source code.
*/

namespace Liip\ImagineBundle\Imagine\Filter\PostProcessor;

use Liip\ImagineBundle\Binary\BinaryInterface;
use Liip\ImagineBundle\Binary\FileBinaryInterface;
use Symfony\Component\Filesystem\Exception\IOException;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Process\Process;

abstract class AbstractPostProcessor implements PostProcessorInterface
{
/**
* @var string
*/
protected $executablePath;

/**
* @var string|null
*/
protected $temporaryRootPath;

/**
* @var Filesystem
*/
private $filesystem;

public function __construct(string $executablePath, string $temporaryRootPath = null)
{
$this->executablePath = $executablePath;
$this->temporaryRootPath = $temporaryRootPath;
$this->filesystem = new Filesystem();
}

protected function createProcess(array $arguments = [], array $options = []): Process
{
$process = new Process($arguments);

if (!isset($options['process'])) {
return $process;
}

if (isset($options['process']['timeout'])) {
$process->setTimeout($options['process']['timeout']);
}

if (isset($options['process']['working_directory'])) {
$process->setWorkingDirectory($options['process']['working_directory']);
}

if (isset($options['process']['environment_variables']) && is_array($options['process']['environment_variables'])) {
$process->setEnv($options['process']['environment_variables']);
}

return $process;
}

protected function isBinaryTypeJpgImage(BinaryInterface $binary): bool
{
return $this->isBinaryTypeMatch($binary, ['image/jpeg', 'image/jpg']);
}

protected function isBinaryTypePngImage(BinaryInterface $binary): bool
{
return $this->isBinaryTypeMatch($binary, ['image/png']);
}

protected function isBinaryTypeMatch(BinaryInterface $binary, array $types): bool
{
return in_array($binary->getMimeType(), $types, true);
}

protected function writeTemporaryFile(BinaryInterface $binary, array $options = [], string $prefix = null): string
{
$temporary = $this->acquireTemporaryFilePath($options, $prefix);

if ($binary instanceof FileBinaryInterface) {
$this->filesystem->copy($binary->getPath(), $temporary, true);
} else {
$this->filesystem->dumpFile($temporary, $binary->getContent());
}

return $temporary;
}

protected function acquireTemporaryFilePath(array $options, string $prefix = null): string
{
$root = $options['temp_dir'] ?? $this->temporaryRootPath ?: sys_get_temp_dir();

if (!is_dir($root)) {
try {
$this->filesystem->mkdir($root);
} catch (IOException $exception) {
// ignore failure as "tempnam" function will revert back to system default tmp path as last resort
}
}

if (false === $file = @tempnam($root, $prefix ?: 'post-processor')) {
throw new \RuntimeException(sprintf('Temporary file cannot be created in "%s"', $root));
}

return $file;
}

/**
* @param int[] $validReturns
* @param string[] $errors
*/
protected function isSuccessfulProcess(Process $process, array $validReturns = [0], array $errors = ['ERROR']): bool
{
if (count($validReturns) > 0 && !in_array($process->getExitCode(), $validReturns, true)) {
return false;
}

foreach ($errors as $string) {
if (false !== strpos($process->getOutput(), $string)) {
return false;
}
}

return true;
}

protected function triggerSetterMethodDeprecation(string $method): void
{
@trigger_error(sprintf('The %s() method was deprecated in 2.2 and will be removed in 3.0. You must '
.'setup the class state via its __construct() method. You can still pass filter-specific options to the '.
'process() method to overwrite behavior.', $method), E_USER_DEPRECATED);
}
}
Loading

0 comments on commit 539b552

Please sign in to comment.