diff --git a/Form/Type/FileType.php b/Form/Type/FileType.php new file mode 100644 index 0000000..ce67e78 --- /dev/null +++ b/Form/Type/FileType.php @@ -0,0 +1,94 @@ +dataClass = $class; + $this->uploadFileHelper = $uploadFileHelper; + } + + /** + * {@inheritdoc} + */ + public function getParent() + { + return 'file'; + } + + /** + * {@inheritdoc} + */ + public function getName() + { + return 'cmf_media_file'; + } + + /** + * {@inheritdoc} + */ + public function buildForm(FormBuilderInterface $builder, array $options) + { + $transformer = new ModelToFileTransformer($this->uploadFileHelper, $options['data_class']); + $builder->addModelTransformer($transformer); + } + + /** + * {@inheritdoc} + */ + public function setDefaultOptions(OptionsResolverInterface $options) + { + $this->configureOptions($options); + } + + /** + * {@inheritdoc} + */ + public function configureOptions(OptionsResolver $options) + { + $options->setDefaults(array('data_class' => $this->dataClass)); + } +} diff --git a/Form/Type/ImageType.php b/Form/Type/ImageType.php index d019257..5778ea2 100644 --- a/Form/Type/ImageType.php +++ b/Form/Type/ImageType.php @@ -12,19 +12,37 @@ namespace Symfony\Cmf\Bundle\MediaBundle\Form\Type; use Symfony\Cmf\Bundle\MediaBundle\File\UploadFileHelperInterface; -use Symfony\Cmf\Bundle\MediaBundle\Form\DataTransformer\ModelToFileTransformer; -use Symfony\Component\Form\AbstractType; -use Symfony\Component\Form\FormBuilderInterface; use Symfony\Component\Form\FormInterface; use Symfony\Component\Form\FormView; use Symfony\Component\OptionsResolver\OptionsResolver; -use Symfony\Component\OptionsResolver\OptionsResolverInterface; -class ImageType extends AbstractType +/** + * Form type which transforms an uploaded file to an object implementing the + * Symfony\Cmf\Bundle\MediaBundle\ImageInterface + * + * It renders as a file upload button and provides a preview of the uploaded + * image, if any. + * To see the preview you can use the twig template provided by this bundle. + * + * Usage: you need to supply the object class to which the file will be + * transformed (which should implement ImageInterface) and an UploadFileHelper, + * which will handle the UploadedFile and create the transformed object. + * + * If the LiipImagineBundle is used in your project, you can configure the imagine + * filter to use for the preview, as well as additional filters to remove from cache + * when the image is replaced. If the filter is not specified, it defaults to + * image_upload_thumbnail. + */ +class ImageType extends FileType { - private $dataClass; - private $uploadFileHelper; + /** + * @var bool + */ private $useImagine; + + /** + * @var bool + */ private $defaultFilter; /** @@ -35,43 +53,33 @@ class ImageType extends AbstractType */ public function __construct($class, UploadFileHelperInterface $uploadFileHelper, $useImagine = false, $defaultFilter = false) { - $this->dataClass = $class; - $this->uploadFileHelper = $uploadFileHelper; + parent::__construct($class, $uploadFileHelper); $this->useImagine = $useImagine; $this->defaultFilter = $this->useImagine ? $defaultFilter : false; } - public function getParent() - { - return 'file'; - } - + /** + * {@inheritdoc} + */ public function getName() { return 'cmf_media_image'; } - public function buildForm(FormBuilderInterface $builder, array $options) - { - $transformer = new ModelToFileTransformer($this->uploadFileHelper, $options['data_class']); - $builder->addModelTransformer($transformer); - } - + /** + * {@inheritdoc} + */ public function buildView(FormView $view, FormInterface $form, array $options) { $view->vars['imagine_filter'] = $this->useImagine ? $options['imagine_filter'] : false; } - public function setDefaultOptions(OptionsResolverInterface $options) - { - $this->configureOptions($options); - } - + /** + * {@inheritdoc} + */ public function configureOptions(OptionsResolver $options) { - $options->setDefaults(array( - 'data_class' => $this->dataClass, - 'imagine_filter' => $this->defaultFilter, - )); + parent::configureOptions($options); + $options->setDefaults(array('imagine_filter' => $this->defaultFilter)); } } diff --git a/Resources/config/persistence-phpcr.xml b/Resources/config/persistence-phpcr.xml index 59b37cc..6a215f6 100644 --- a/Resources/config/persistence-phpcr.xml +++ b/Resources/config/persistence-phpcr.xml @@ -18,6 +18,7 @@ Symfony\Cmf\Bundle\MediaBundle\Editor\Helper\UploadDefaultHelper Symfony\Cmf\Bundle\MediaBundle\Editor\Helper\UploadCkeditorHelper + Symfony\Cmf\Bundle\MediaBundle\Form\Type\FileType Symfony\Cmf\Bundle\MediaBundle\Form\Type\ImageType Symfony\Cmf\Bundle\MediaBundle\Doctrine\DoctrineStreamRewindSubscriber @@ -120,6 +121,12 @@ + + + %cmf_media.persistence.phpcr.file.class% + + + %cmf_media.persistence.phpcr.image.class% diff --git a/Resources/views/Form/fields.html.twig b/Resources/views/Form/fields.html.twig index a6f897d..c4f562a 100644 --- a/Resources/views/Form/fields.html.twig +++ b/Resources/views/Form/fields.html.twig @@ -6,3 +6,12 @@ {% endif %} {% endblock %} {% endblock %} + +{% block cmf_media_file_widget %} + {{ form_widget(form) }} + {% block cmf_media_file_widget_download %} + {% if form.vars.data and form.vars.data.id is defined and form.vars.data.id %} + {{ form.vars.data.name }} + {% endif %} + {% endblock %} +{% endblock %} diff --git a/Tests/Resources/Controller/PhpcrFileTestController.php b/Tests/Resources/Controller/PhpcrFileTestController.php index ef7124c..d202802 100644 --- a/Tests/Resources/Controller/PhpcrFileTestController.php +++ b/Tests/Resources/Controller/PhpcrFileTestController.php @@ -11,9 +11,13 @@ namespace Symfony\Cmf\Bundle\MediaBundle\Tests\Resources\Controller; +use Doctrine\ODM\PHPCR\Document\Generic; +use PHPCR\Util\PathHelper; use Symfony\Bundle\FrameworkBundle\Controller\Controller; use Symfony\Cmf\Bundle\MediaBundle\File\UploadFileHelperInterface; +use Symfony\Cmf\Bundle\MediaBundle\Tests\Resources\Document\Content; use Symfony\Component\HttpFoundation\Request; +use Symfony\Component\HttpKernel\Exception\NotFoundHttpException; class PhpcrFileTestController extends Controller { @@ -25,6 +29,32 @@ public function getUploadForm() ; } + protected function getContentForm(Content $contentObject = null) + { + $is_new = is_null($contentObject); + if ($is_new) { + $contentObject = new Content(); + } + + return $this->createFormBuilder($contentObject) + ->add('name') + ->add('title') + ->add('file', 'cmf_media_file', array('required' => $is_new)) + ->getForm() + ; + } + + protected function getUrlSafePath($object) + { + return ltrim($object->getId(), '/'); + } + + protected function mapUrlSafePathToId($path) + { + // The path is being the id + return PathHelper::absolutizePath($path, '/'); + } + public function indexAction(Request $request) { $fileClass = 'Symfony\Cmf\Bundle\MediaBundle\Doctrine\Phpcr\File'; @@ -34,13 +64,65 @@ public function indexAction(Request $request) $uploadForm = $this->getUploadForm(); $editorUploadForm = $this->getUploadForm(); + // get a content object + $contentClass = 'Symfony\Cmf\Bundle\MediaBundle\Tests\Resources\Document\Content'; + $contentObject = $dm->getRepository($contentClass)->findOneBy(array()); + + // Form - content object with file embedded + $newContentForm = $this->getContentForm(); + $editContentForm = $this->getContentForm($contentObject); + + // action url for editContentForm + if ($contentObject) { + $editContentFormAction = $this->generateUrl('phpcr_file_test_content_edit', array( + 'path' => $this->getUrlSafePath($contentObject), + )); + } else { + $editContentFormAction = false; + } + return $this->render('::tests/file.html.twig', array( - 'upload_form' => $uploadForm->createView(), - 'editor_form' => $editorUploadForm->createView(), - 'files' => $files, + 'upload_form' => $uploadForm->createView(), + 'editor_form' => $editorUploadForm->createView(), + 'content_form_new' => $newContentForm->createView(), + 'content_form_edit' => $editContentForm->createView(), + 'content_form_edit_action' => $editContentFormAction, + 'files' => $files, )); } + public function newAction(Request $request) + { + $dm = $this->get('doctrine_phpcr')->getManager('default'); + $contentRoot = $dm->find(null, '/test/content'); + + if (!$contentRoot) { + $root = $dm->find(null, '/test'); + $contentRoot = new Generic(); + $contentRoot->setNodename('content'); + $contentRoot->setParent($root); + $dm->persist($contentRoot); + } + + $contentObject = new Content(); + $contentObject->setParent($contentRoot); + + $form = $this->getContentForm($contentObject); + + if ($request->isMethod('POST')) { + $form->bind($request); + + if ($form->isValid()) { + // persist + $dm = $this->get('doctrine_phpcr')->getManager('default'); + $dm->persist($contentObject); + $dm->flush(); + } + } + + return $this->redirect($this->generateUrl('phpcr_file_test')); + } + public function uploadAction(Request $request) { $form = $this->getUploadForm(); @@ -63,4 +145,33 @@ public function uploadAction(Request $request) return $this->redirect($this->generateUrl('phpcr_file_test')); } + + public function editAction(Request $request, $path) + { + $dm = $this->get('doctrine_phpcr')->getManager('default'); + + $contentObject = $dm->find(null, $this->mapUrlSafePathToId($path)); + + if (!$contentObject || !$contentObject instanceof Content) { + throw new NotFoundHttpException(sprintf( + 'Object with identifier %s cannot be resolved to a valid instance of Symfony\Cmf\Bundle\MediaBundle\Tests\Resources\Document\Content', + $path + )); + } + + $form = $this->getContentForm($contentObject); + + if ($request->isMethod('POST')) { + $form->bind($request); + + if ($form->isValid()) { + // persist + $dm = $this->get('doctrine_phpcr')->getManager('default'); + $dm->persist($contentObject); + $dm->flush(); + } + } + + return $this->redirect($this->generateUrl('phpcr_file_test')); + } } diff --git a/Tests/Resources/Controller/PhpcrImageTestController.php b/Tests/Resources/Controller/PhpcrImageTestController.php index e2e5bb4..e47e33f 100644 --- a/Tests/Resources/Controller/PhpcrImageTestController.php +++ b/Tests/Resources/Controller/PhpcrImageTestController.php @@ -14,6 +14,7 @@ use Doctrine\ODM\PHPCR\Document\Generic; use PHPCR\Util\PathHelper; use Symfony\Bundle\FrameworkBundle\Controller\Controller; +use Symfony\Cmf\Bundle\MediaBundle\Doctrine\Phpcr\Image; use Symfony\Cmf\Bundle\MediaBundle\File\UploadFileHelperInterface; use Symfony\Cmf\Bundle\MediaBundle\Tests\Resources\Document\Content; use Symfony\Component\HttpFoundation\Request; @@ -38,7 +39,7 @@ protected function getContentForm(Content $contentObject = null, array $imageOpt return $this->createFormBuilder($contentObject) ->add('name') ->add('title') - ->add('image', 'cmf_media_image', array_merge(array('required' => false), $imageOptions)) + ->add('file', 'cmf_media_image', array_merge(array('required' => false, 'label' => 'Image'), $imageOptions)) ->getForm() ; } @@ -54,6 +55,17 @@ protected function mapUrlSafePathToId($path) return PathHelper::absolutizePath($path, '/'); } + protected function getImageContentObject($contentObjects) { + if (is_null($contentObjects)) return null; + /** @var Content $contentObject */ + foreach($contentObjects as $contentObject) { + if ($contentObject->getFile() instanceof Image) { + return $contentObject; + } + } + return null; + } + public function indexAction(Request $request) { $dm = $this->get('doctrine_phpcr')->getManager('default'); @@ -64,7 +76,7 @@ public function indexAction(Request $request) // get content with image object $contentClass = 'Symfony\Cmf\Bundle\MediaBundle\Tests\Resources\Document\Content'; - $contentObject = $dm->getRepository($contentClass)->findOneBy(array()); + $contentObject = $this->getImageContentObject($dm->getRepository($contentClass)->findAll()); $uploadForm = $this->getUploadForm(); $editorUploadForm = $this->getUploadForm(); diff --git a/Tests/Resources/DataFixtures/Phpcr/LoadMediaData.php b/Tests/Resources/DataFixtures/Phpcr/LoadMediaData.php index aca9271..bc0bf11 100644 --- a/Tests/Resources/DataFixtures/Phpcr/LoadMediaData.php +++ b/Tests/Resources/DataFixtures/Phpcr/LoadMediaData.php @@ -62,7 +62,7 @@ public function load(ObjectManager $manager) $image2->setFileContentFromFilesystem($testDataDir .'/cmf-logo.png'); $manager->persist($image2); - // Content + // Content with image $content = new Content(); $content->setParent($contentRoot); $content->setName('content-with-image'); @@ -71,9 +71,21 @@ public function load(ObjectManager $manager) $contentImage = new Image(); $contentImage->setFileContentFromFilesystem($testDataDir .'/cmf-logo.png'); - $content->setImage($contentImage); + $content->setFile($contentImage); $manager->persist($content); + // Content with file + $content2 = new Content(); + $content2->setParent($contentRoot); + $content2->setName('content-with-file'); + $content2->setTitle('Content document with file attached'); + + $contentFile = new File(); + $contentFile->setFileContentFromFilesystem($testDataDir .'/testfile.txt'); + + $content2->setFile($contentFile); + $manager->persist($content2); + $manager->flush(); } } diff --git a/Tests/Resources/Document/Content.php b/Tests/Resources/Document/Content.php index 8812d59..9861228 100644 --- a/Tests/Resources/Document/Content.php +++ b/Tests/Resources/Document/Content.php @@ -11,8 +11,8 @@ namespace Symfony\Cmf\Bundle\MediaBundle\Tests\Resources\Document; -use Symfony\Cmf\Bundle\MediaBundle\Doctrine\Phpcr\Image; -use Symfony\Cmf\Bundle\MediaBundle\ImageInterface; +use Symfony\Cmf\Bundle\MediaBundle\Doctrine\Phpcr\File; +use Symfony\Cmf\Bundle\MediaBundle\FileInterface; use Symfony\Component\HttpFoundation\File\UploadedFile; use Doctrine\ODM\PHPCR\Mapping\Annotations as PHPCRODM; @@ -25,7 +25,7 @@ class Content /** * @PHPCRODM\Child(cascade="persist") */ - protected $image; + protected $file; /** * @PHPCRODM\Id(strategy="parent") @@ -48,52 +48,53 @@ class Content protected $title; /** - * Set the image for this block. + * Set the file for this block. * * Setting null will do nothing, as this is what happens when you edit this * block in a form without uploading a replacement file. * - * If you need to delete the Image, you can use getImage and delete it with + * If you need to delete the file, you can use getFile and delete it with * the document manager. Note that this block does not make much sense - * without an image, though. + * without a file, though. * - * @param ImageInterface|UploadedFile|null $image optional the image to update + * @param FileInterface|UploadedFile|null $file optional the file to update */ - public function setImage($image = null) + public function setFile($file = null) { - if (!$image) { + if (!$file) { return; } - if (!$image instanceof ImageInterface && !$image instanceof UploadedFile) { - $type = is_object($image) ? get_class($image) : gettype($image); + if (!$file instanceof FileInterface && !$file instanceof UploadedFile) { + $type = is_object($file) ? get_class($file) : gettype($file); throw new \InvalidArgumentException(sprintf( - 'Image is not a valid type, "%s" given.', + 'File is not a valid type, "%s" given.', $type )); } - if ($this->image) { - // existing image, only update content + if ($this->file) { + // existing file, only update content // TODO: https://github.com/doctrine/phpcr-odm/pull/262 - $this->image->copyContentFromFile($image); - } elseif ($image instanceof ImageInterface) { - $this->image = $image; + $this->file->copyContentFromFile($file); + } elseif ($file instanceof FileInterface) { + $file->setName('file'); // Ensure node name matches document mapping + $this->file = $file; } else { - $this->image = new Image(); - $this->image->copyContentFromFile($image); + $this->file = new File(); + $this->file->copyContentFromFile($file); } } /** - * Get image + * Get file * - * @return Image + * @return File */ - public function getImage() + public function getFile() { - return $this->image; + return $this->file; } public function setId($id) diff --git a/Tests/Resources/app/Resources/views/tests/file.html.twig b/Tests/Resources/app/Resources/views/tests/file.html.twig index e08f638..7c8ff83 100644 --- a/Tests/Resources/app/Resources/views/tests/file.html.twig +++ b/Tests/Resources/app/Resources/views/tests/file.html.twig @@ -19,6 +19,24 @@ +

Content object with file embedded (new)

+

This will use the cmf_media_file form type.

+
+ {{ form_widget(content_form_new) }} + + +
+ + {% if content_form_edit_action %} +

Content object with file embedded (edit)

+

This will use the cmf_media_file form type that will show a link to the uploaded file.

+
+ {{ form_widget(content_form_edit) }} + + +
+ {% endif %} +

Download file(s)

{% if files is empty %}

No files found, upload a file first.

diff --git a/Tests/Resources/app/config/cmf_media.yml b/Tests/Resources/app/config/cmf_media.yml index 7f0b555..7f2cce7 100644 --- a/Tests/Resources/app/config/cmf_media.yml +++ b/Tests/Resources/app/config/cmf_media.yml @@ -7,7 +7,7 @@ cmf_media: persistence: phpcr: enabled: true - media_basepath: /test/media + media_basepath: /test # The LiipImagineBundle can be used if you want to convert on demand an image # to a specific format. (ie a controller render the file) diff --git a/Tests/Resources/app/config/routing/cmf_media.yml b/Tests/Resources/app/config/routing/cmf_media.yml index a536a73..9cff85a 100644 --- a/Tests/Resources/app/config/routing/cmf_media.yml +++ b/Tests/Resources/app/config/routing/cmf_media.yml @@ -13,6 +13,18 @@ phpcr_file_test_upload: defaults: _controller: Symfony\Cmf\Bundle\MediaBundle\Tests\Resources\Controller\PhpcrFileTestController::uploadAction +phpcr_file_test_content_new: + path: /phpcr/file-test/content/new + defaults: + _controller: Symfony\Cmf\Bundle\MediaBundle\Tests\Resources\Controller\PhpcrFileTestController::newAction + +phpcr_file_test_content_edit: + path: /phpcr/file-test/content/edit/{path} + defaults: + _controller: Symfony\Cmf\Bundle\MediaBundle\Tests\Resources\Controller\PhpcrFileTestController::editAction + requirements: + path: .* + phpcr_image_test: path: /phpcr/image-test defaults: diff --git a/Tests/WebTest/TestApp/FileTest.php b/Tests/WebTest/TestApp/FileTest.php index a9478f7..85b838b 100644 --- a/Tests/WebTest/TestApp/FileTest.php +++ b/Tests/WebTest/TestApp/FileTest.php @@ -33,8 +33,8 @@ public function testPage() $resp = $client->getResponse(); $this->assertEquals(200, $resp->getStatusCode()); - // 1 file and 1 image - $this->assertGreaterThanOrEqual(2, $crawler->filter('.downloads li a')->count()); + // 2 files and 2 images + $this->assertGreaterThanOrEqual(4, $crawler->filter('.downloads li a')->count()); } public function testUpload()