Skip to content

Commit

Permalink
Merge pull request #3 from egeloen/uploaded-file
Browse files Browse the repository at this point in the history
Rewrite bundle in order to support uploaded file
  • Loading branch information
GeLoLabs committed May 24, 2016
2 parents 79d36b8 + c86b0f0 commit 3588f7c
Show file tree
Hide file tree
Showing 23 changed files with 673 additions and 777 deletions.
3 changes: 1 addition & 2 deletions DependencyInjection/Configuration.php
Expand Up @@ -29,8 +29,7 @@ public function getConfigTreeBuilder()

$builder
->children()
->booleanNode('form')->defaultValue(false)->end()
->booleanNode('serializer')->defaultValue(false)->end()
->booleanNode('default')->defaultValue(false)->end()
->end();

return $treeBuilder;
Expand Down
33 changes: 9 additions & 24 deletions DependencyInjection/IvoryBase64FileExtension.php
Expand Up @@ -29,34 +29,19 @@ protected function loadInternal(array $config, ContainerBuilder $container)
{
$loader = new XmlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));

foreach ($this->resolveResources($config) as $resource) {
foreach (['form'] as $resource) {
$loader->load($resource.'.xml');
}

if ($config['form'] && Kernel::VERSION_ID < 20800) {
$container->getDefinition('ivory.base64_file.form.extension')
->clearTag('form.type_extension')
->addTag('form.type_extension', array('alias' => 'file'));
}
}
$container
->getDefinition($formExtension = 'ivory.base64_file.form.extension')
->addArgument($config['default']);

/**
* @param mixed[] $config
*
* @return string[]
*/
private function resolveResources(array $config)
{
$resources = array();

if ($config['form']) {
$resources[] = 'form';
}

if ($config['serializer']) {
$resources[] = 'serializer';
if (Kernel::VERSION_ID < 20800) {
$container
->getDefinition($formExtension)
->clearTag('form.type_extension')
->addTag('form.type_extension', ['alias' => 'file']);
}

return $resources;
}
}
48 changes: 0 additions & 48 deletions Doctrine/Type/Base64FileType.php

This file was deleted.

57 changes: 50 additions & 7 deletions Form/DataTransformer/Base64FileTransformer.php
Expand Up @@ -11,7 +11,8 @@

namespace Ivory\Base64FileBundle\Form\DataTransformer;

use Ivory\Base64FileBundle\Model\Base64File;
use Ivory\Base64FileBundle\Model\Base64FileInterface;
use Ivory\Base64FileBundle\Model\UploadedBase64File;
use Symfony\Component\Form\DataTransformerInterface;
use Symfony\Component\Form\Exception\TransformationFailedException;

Expand All @@ -26,17 +27,29 @@ class Base64FileTransformer implements DataTransformerInterface
public function transform($value)
{
if ($value === null) {
return;
return [
'value' => null,
'name' => null,
'mimeType' => null,
'size' => null,
];
}

if (!$value instanceof Base64File) {
if (!$value instanceof Base64FileInterface) {
throw new TransformationFailedException(sprintf(
'Expected an "Ivory\Base64Bundle\Model\Base64File", got "%s".',
is_object($value) ? get_class($value) : gettype($value)
'Expected an "Ivory\Base64Bundle\Model\Base64FileInterface", got "%s".',
$this->getVariableType($value)
));
}

return $value->getData(true, false);
$uploadedFile = $value instanceof UploadedBase64File;

return [
'value' => $value->getData(true, false),
'name' => $uploadedFile ? $value->getClientOriginalName() : null,
'mimeType' => $uploadedFile ? $value->getClientMimeType() : $value->getMimeType(),
'size' => $uploadedFile ? $value->getClientSize() : $value->getSize(),
];
}

/**
Expand All @@ -48,10 +61,40 @@ public function reverseTransform($value)
return;
}

if (!is_array($value)) {
throw new TransformationFailedException(sprintf(
'Expected an array, got "%s".',
$this->getVariableType($value)
));
}

if (!isset($value['name'])) {
throw new TransformationFailedException('Missing base 64 file name.');
}

if (!isset($value['value'])) {
throw new TransformationFailedException('Missing base 64 file value.');
}

try {
return new Base64File($value);
return new UploadedBase64File(
$value['value'],
$value['name'],
isset($value['mimeType']) ? $value['mimeType'] : null,
isset($value['size']) ? $value['size'] : null
);
} catch (\Exception $e) {
throw new TransformationFailedException($e->getMessage());
}
}

/**
* @param mixed $variable
*
* @return string
*/
private function getVariableType($variable)
{
return is_object($variable) ? get_class($variable) : gettype($variable);
}
}
17 changes: 15 additions & 2 deletions Form/Extension/Base64FileExtension.php
Expand Up @@ -23,13 +23,26 @@
*/
class Base64FileExtension extends AbstractTypeExtension
{
/**
* @var bool
*/
private $base64;

/**
* @param bool $base64
*/
public function __construct($base64)
{
$this->base64 = $base64;
}

/**
* {@inheritdoc}
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
if ($options['base64']) {
$builder->addModelTransformer(new Base64FileTransformer());
$builder->addViewTransformer(new Base64FileTransformer());
}
}

Expand All @@ -47,7 +60,7 @@ public function setDefaultOptions(OptionsResolverInterface $resolver)
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'base64' => false,
'base64' => $this->base64,
'data_class' => function (Options $options, $value) {
return !$options['base64'] ? $value : null;
},
Expand Down
121 changes: 5 additions & 116 deletions Model/Base64File.php
Expand Up @@ -16,132 +16,21 @@
/**
* @author GeLo <geloen.eric@gmail.com>
*/
class Base64File extends File
class Base64File extends File implements Base64FileInterface
{
/**
* @var resource
*/
private $resource;
use Base64FileTrait {
__construct as private constructTrait;
}

/**
* @param string|resource $value
* @param bool $encoded
*/
public function __construct($value, $encoded = true)
{
$this->resource = tmpfile();

if ($encoded) {
$filter = stream_filter_append($this->resource, 'convert.base64-decode', STREAM_FILTER_WRITE);
}

try {
if (is_string($value)) {
$this->copyStringToStream($value, $this->resource);
} elseif (is_resource($value)) {
$this->copyStreamToStream($value, $this->resource);
} else {
throw new \InvalidArgumentException(sprintf(
'The base64 file value must be a string or a resource, got "%s".',
gettype($value)
));
}
} catch (\Exception $e) {
fclose($this->resource);

throw $e;
}

if (isset($filter)) {
stream_filter_remove($filter);
}

fflush($this->resource);
$this->constructTrait($value, $encoded);
$metadata = stream_get_meta_data($this->resource);

parent::__construct($metadata['uri']);
}

/**
* {@inheritdoc}
*/
public function __destruct()
{
if (is_resource($this->resource)) {
fclose($this->resource);
}
}

/**
* @param bool $encoded
* @param bool $asResource
*
* @return resource|string
*/
public function getData($encoded = true, $asResource = true)
{
$resource = fopen('php://temp', 'rb+');

if ($encoded) {
$filter = stream_filter_append($resource, 'convert.base64-encode', STREAM_FILTER_WRITE);
}

$this->copyStreamToStream($this->resource, $resource);

if (isset($filter)) {
stream_filter_remove($filter);
}

if ($asResource) {
return $resource;
}

$content = stream_get_contents($resource);
fclose($resource);

return $content;
}

/**
* @param string $from
* @param resource $to
*/
private function copyStringToStream($from, $to)
{
$toPosition = ftell($to);
$success = @fwrite($to, $from);
fseek($to, $toPosition);

if (!$success) {
$error = error_get_last();

throw new \RuntimeException(sprintf(
'An error occurred while copying the value (%s).',
$error['message']
));
}
}

/**
* @param resource $from
* @param resource $to
*/
private function copyStreamToStream($from, $to)
{
$fromPosition = ftell($from);
$toPosition = ftell($to);
rewind($from);
$success = @stream_copy_to_stream($from, $to);
fseek($from, $fromPosition);
fseek($to, $toPosition);

if (!$success) {
$error = error_get_last();

throw new \RuntimeException(sprintf(
'An error occurred while copying the value (%s).',
$error['message']
));
}
}
}

0 comments on commit 3588f7c

Please sign in to comment.