Commit e7bb5656 authored by Ludwig Ruderstaller's avatar Ludwig Ruderstaller

media bundle initial import

parents
Pipeline #1981 skipped
<?php
namespace Cwd\MediaBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
/**
* Class CwdMediaBundle
*
* @package Cwd\MediaBundle
* @author Ludwig Ruderstaller <lr@cwd.at>
*/
class CwdMediaBundle extends Bundle
{
}
<?php
namespace Cwd\MediaBundle\DependencyInjection;
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;
/**
* This is the class that validates and merges configuration from your app/config files
*
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html#cookbook-bundles-extension-config-class}
*/
class Configuration implements ConfigurationInterface
{
/**
* {@inheritdoc}
*/
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$treeBuilder->root('cwd_media')->children()
->booleanNode('throw_exception')->defaultFalse()->end()
->scalarNode('entity_class')->defaultValue('Model:Media')->end()
->arrayNode('storage')->addDefaultsIfNotSet()->children()
->scalarNode('path')->defaultValue('%kernel.root_dir%/../mediastore')->end()
->scalarNode('depth')->defaultValue(4)->end()
->end()->end()
->arrayNode('cache')->addDefaultsIfNotSet()->children()
->scalarNode('dirname')->defaultValue('imagecache')->end()
->scalarNode('path')->defaultValue('%kernel.root_dir%/../web')->end()
->end()->end()
->arrayNode('converter')->addDefaultsIfNotSet()->children()
->scalarNode('quality')->defaultValue(90)->end()
->arrayNode('size')->addDefaultsIfNotSet()->children()
->scalarNode('max_width')->defaultValue(2000)->end()
->scalarNode('max_height')->defaultValue(2000)->end()
->end()->end()
->end()->end();
return $treeBuilder;
}
}
<?php
namespace Cwd\MediaBundle\DependencyInjection;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;
/**
* This is the class that loads and manages your bundle configuration
*
* To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
*/
class CwdMediaExtension extends Extension
{
/**
* {@inheritdoc}
*/
public function load(array $configs, ContainerBuilder $container)
{
$configuration = new Configuration();
$config = $this->processConfiguration($configuration, $configs);
$container->setParameter('cwd.media.config', $config);
$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');
}
}
<?php
/*
* This file is part of cwd media bundle.
*
* (c)2015 Ludwig Ruderstaller <lr@cwd.at>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Cwd\MediaBundle\Form\Type;
use Cwd\MediaBundle\Form\Transformer\MediaTransformer;
use Cwd\MediaBundle\Model\Entity\Media;
use Cwd\MediaBundle\Service\MediaService;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\HttpFoundation\File\UploadedFile;
use Symfony\Component\OptionsResolver\OptionsResolver;
/**
* Class ImageType
*
* @package Cwd\MediaBundle\Form\Type
* @author Ludwig Ruderstaller <lr@cwd.at>
*/
class ImageType extends AbstractType
{
/**
* @var MediaService
*/
private $mediaService;
/**
* @param MediaService $mediaService
*/
public function __construct(MediaService $mediaService)
{
$this->mediaService = $mediaService;
}
/**
* @param FormBuilderInterface $builder
* @param array $options
*/
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->addEventListener(
FormEvents::PRE_SUBMIT,
function (FormEvent $event) {
$media = $event->getData();
if ($media instanceof Media) {
return $media;
} elseif (is_numeric($media)) {
$event->setData($this->mediaService->find($media));
} elseif ($media instanceof UploadedFile) {
$event->setData($this->mediaService->create($media->getPathname(), true));
}
}
);
parent::buildForm($builder, $options);
}
/**
* @param OptionsResolver $resolver
*/
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults(
array(
'validation_groups' => array('default'),
'data_class' => 'Cwd\MediaBundle\Model\Entity\Media',
'cascade_validation' => true,
)
);
}
/**
*
* @return string
*/
public function getParent()
{
return 'file';
}
/**
*
* @return string
*/
public function getName()
{
return 'cwd_image_type';
}
}
<?php
/*
* This file is part of aspetos.
*
* (c)2015 Ludwig Ruderstaller <lr@cwd.at>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Cwd\MediaBundle;
/**
* Class MediaException
*
* @package Cwd\MediaBundle\MediaException
* @author Ludwig Ruderstaller <lr@cwd.at>
*/
class MediaException extends \Exception
{
}
<?php
namespace Cwd\MediaBundle\Model\Entity;
use Doctrine\ORM\Mapping as ORM;
use Gedmo\Mapping\Annotation as Gedmo;
/**
* @ORM\MappedSuperclass
*/
class Media
{
/**
* @ORM\Id
* @ORM\Column(type="integer")
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @ORM\Column(type="string", length=200, nullable=false)
*/
protected $mediatype;
/**
* @ORM\Column(type="string", length=64, nullable=false)
*/
protected $filehash;
/**
* @ORM\Column(type="string", length=250, nullable=true)
*/
protected $filename;
/**
* @ORM\Column(type="datetime", nullable=true)
*/
protected $createdAt;
/**
* @ORM\Column(type="datetime", nullable=true)
*/
protected $updatedAt;
/**
* @ORM\Column(type="string", nullable=true)
*/
private $originalFile;
/**
* @ORM\Column(type="datetime", nullable=true)
*/
protected $deletedAt;
/**
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* @param mixed $id
*
* @return $this
*/
public function setId($id)
{
$this->id = $id;
return $this;
}
/**
* @return string
*/
public function getMediatype()
{
return $this->mediatype;
}
/**
* @param mixed $mediatype
*
* @return $this
*/
public function setMediatype($mediatype)
{
$this->mediatype = $mediatype;
return $this;
}
/**
* @return string
*/
public function getFilehash()
{
return $this->filehash;
}
/**
* @param mixed $filehash
*
* @return $this
*/
public function setFilehash($filehash)
{
$this->filehash = $filehash;
return $this;
}
/**
* @return string
*/
public function getFilename()
{
return $this->filename;
}
/**
* @param mixed $filename
*
* @return $this
*/
public function setFilename($filename)
{
$this->filename = $filename;
return $this;
}
/**
* @return \DateTime
*/
public function getCreatedAt()
{
return $this->createdAt;
}
/**
* @param mixed $createdAt
*
* @return $this
*/
public function setCreatedAt($createdAt)
{
$this->createdAt = $createdAt;
return $this;
}
/**
* @return \DateTime
*/
public function getUpdatedAt()
{
return $this->updatedAt;
}
/**
* @param mixed $updatedAt
*
* @return $this
*/
public function setUpdatedAt($updatedAt)
{
$this->updatedAt = $updatedAt;
return $this;
}
/**
* @return \DateTime
*/
public function getDeletedAt()
{
return $this->deletedAt;
}
/**
* @param mixed $deletedAt
*
* @return $this
*/
public function setDeletedAt($deletedAt)
{
$this->deletedAt = $deletedAt;
return $this;
}
/**
* @return string
*/
public function getOriginalFile()
{
return $this->originalFile;
}
/**
* @param string $originalFile
*
* @return $this
*/
public function setOriginalFile($originalFile)
{
$this->originalFile = $originalFile;
return $this;
}
}
<?php
/*
* This file is part of aspetos
*
* (c)2015 Ludwig Ruderstaller <lr@cwd.at>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Cwd\MediaBundle\Model\Repository;
use Cwd\GenericBundle\Doctrine\EntityRepository;
/**
* Media Repository
*
* @author Ludwig Ruderstaller <lr@cwd.at>
* @SuppressWarnings("ShortVariable")
*/
abstract class MediaRepository extends EntityRepository
{
}
services:
cwd.media.service:
class: Cwd\MediaBundle\Service\MediaService
arguments:
- "@entity_manager"
- "@logger"
- "%cwd.media.config%"
cwd.media.twig.image:
class: Cwd\MediaBundle\Twig\ImageExtension
arguments: [@cwd.media.service]
tags:
- { name: twig.extension }
cwd_image_type:
class: Cwd\MediaBundle\Form\Type\ImageType
arguments: [@cwd.media.service]
tags:
- { name: form.type }
{% block cwd_image_type_widget %}
{% set imageSrc = form.vars.data %}
<div class="row">
<div class="col-md-{{ form.vars.attr.imagecols|default(2) }}">
<div class="fileinput fileinput-{% if imageSrc is not null %}exists{% else %}new{% endif %}" data-provides="fileinput" data-name="{{ form.vars.full_name }}">
<div class="fileinput-new thumbnail">
<img src="http://www.placehold.it/200x200/EFEFEF/AAAAAA&amp;text={{ "no image"|trans }}" alt="" />
</div>
<div class="fileinput-preview fileinput-exists thumbnail">
{% if imageSrc is not null and imageSrc.id is defined %}
<img src="{{ imageSrc|cwdImage.cropResize(200,200) }}" />
<input type="hidden" name="{{ form.vars.full_name }}" id="{{ form.vars.id }}" value="{{ imageSrc.id }}" />
{% endif %}
</div>
<div>
<span class="btn default btn-file">
<span class="fileinput-new"> {{ "Select image"|trans }} </span>
<span class="fileinput-exists"> {{ "Change"|trans }} </span>
<input type="file">
</span>
<a href="javascript:;" class="btn red fileinput-exists" data-dismiss="fileinput"> {{ "Reset"|trans }} </a>
</div>
</div>
</div>
<div class="col-md-{{ form.vars.attr.buttoncols|default(2) }} editArea">
</div>
</div>
{% endblock %}
This diff is collapsed.
<?php
/*
* This file is part of Aspetos
*
* (c)2014 Ludwig Ruderstaller <lr@cwd.at>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace CwdMediaBundle\Tests\Service;
use Cwd\GenericBundle\Tests\Repository\DoctrineTestCase;
use Cwd\MediaBundle\Model\Entity\Media;
use Gregwar\Image\Image;
/**
* Class MediaTest
*
* @package CwdMediaBundle\Tests\Service
* @author Ludwig Ruderstaller <lr@cwd.at>
*/
class MediaTest extends DoctrineTestCase
{
/**
* @var \Cwd\MediaBundle\Service\MediaService
*/
protected $service;
/**
* @var string
*/
protected $tmpDir;
public function setUp()
{
parent::setUp();
$this->service = $this->container->get('cwd.media.service');
$config = $this->service->getConfig();
if (!is_dir('./tmp')) {
mkdir('./tmp');
}
$config['storage']['path'] = './tmp/unitest-mediastore-'.date("U");
$config['cache']['path'] = './tmp/unitest-cache-'.date("U");
if (!is_dir($config['cache']['path'])) {
mkdir($config['cache']['path']);
}
$this->service->setConfig($config);
$this->tmpDir = './tmp';
}
public function tearDown()
{
parent::tearDown();
$this->getEntityManager()->clear();
$repository = $this->getEntityManager()->getRepository($this->service->getConfig('entity_class'));
$result = $repository->findBy(array());
foreach ($result as $row) {
$this->getEntityManager()->remove($row);
}
$this->getEntityManager()->flush();
}
public function testSetup()
{
$this->assertFalse(is_dir($this->service->getConfig('storage')['path']));
$this->assertTrue(is_dir($this->service->getConfig('cache')['path']));
$this->assertTrue(is_writeable($this->service->getConfig('cache')['path']));
try {
$repository = $this->getEntityManager()->getRepository($this->service->getConfig('entity_class'));
$this->assertInstanceOf('Cwd\MediaBundle\Model\Repository\MediaRepository', $repository);
} catch (\Exception $e) {
$this->assertTrue(false, $this->service->getConfig('entity_class').' is not a valid Repository');
}
}
public function testConfig()
{
$this->assertNotNull($this->service->getConfig('throw_exception'));
$this->assertTrue(is_array($this->service->getConfig()));
$this->assertGreaterThanOrEqual(5, count($this->service->getConfig()));
$this->setExpectedException('Exception');
$this->service->getConfig('foobar');
}
public function testStoreImage()
{
$result = $this->service->storeImage(__DIR__.'/../data/demo.jpg');
$this->assertArrayHasKey('path', $result);
$this->assertArrayHasKey('md5', $result);
$this->assertArrayHasKey('width', $result);
$this->assertArrayHasKey('height', $result);
$this->assertArrayHasKey('type', $result);
$this->assertContains($result['md5'], $result['path'], 'MD5 is not part of path');
$this->assertLessThanOrEqual($this->service->getConfig('converter')['size']['max_width'], $result['width']);
$this->assertLessThanOrEqual($this->service->getConfig('converter')['size']['max_height'], $result['height']);
$this->assertTrue(is_dir($this->service->getConfig('storage')['path']));
$this->setExpectedException('Exception');
$this->service->storeImage('not-exisisting');
}
public function testCreate()
{
$media = $this->service->create(__DIR__.'/../data/demo.jpg');
$this->assertEquals(get_class($media), $this->getEntityManager()->getRepository($this->service->getConfig('entity_class'))->getClassName());
$this->assertNull($media->getId());
$this->getEntityManager()->flush($media);
$this->assertNotNull($media->getId());
$this->assertGreaterThan(0, $media->getId());
$id = $media->getId();
$media = $this->service->create(__DIR__.'/../data/demo.jpg', true);
$this->assertGreaterThan(0, $media->getId());
$this->assertEquals($id, $media->getId());
$this->getEntityManager()->flush($media);
return $media;
}
/**
* @depends testCreate
*/
public function testCreateFail(Media $media)
{
$media = $this->service->create(__DIR__.'/../data/demo.jpg', true);
$this->assertNull($media->getId());
$this->getEntityManager()->flush($media);
$this->setExpectedException('Exception');
$this->service->create(__DIR__.'/../data/demo.jpg', false);
}
/**
* @depends testCreate
*/
public function testCreateInstance(Media $media)