[FEATURE] Registry for adding file rendering classes 25/32925/10
authorFrans Saris <franssaris@gmail.com>
Mon, 22 Sep 2014 19:15:20 +0000 (21:15 +0200)
committerMarkus Klein <klein.t3@reelworx.at>
Tue, 21 Oct 2014 20:33:03 +0000 (22:33 +0200)
To be able to render all kinds of media files a file renderingRegistry
is needed where you can register a "renderer" class that can generate
the needed HTML output.

This patch adds a registry for adding renderer classes and
a AudioTagRenderer + VideoTagRenderer class.

Resolves: #61800
Releases: master
Change-Id: Ied5e16f00e10ac0c78a6508ef42fe585558a2d2c
Reviewed-on: http://review.typo3.org/32925
Reviewed-by: Wouter Wolters <typo3@wouterwolters.nl>
Tested-by: Wouter Wolters <typo3@wouterwolters.nl>
Reviewed-by: Markus Klein <klein.t3@reelworx.at>
Tested-by: Markus Klein <klein.t3@reelworx.at>
typo3/sysext/core/Classes/Resource/Rendering/AudioTagRenderer.php [new file with mode: 0644]
typo3/sysext/core/Classes/Resource/Rendering/FileRendererInterface.php [new file with mode: 0644]
typo3/sysext/core/Classes/Resource/Rendering/RendererRegistry.php [new file with mode: 0644]
typo3/sysext/core/Classes/Resource/Rendering/VideoTagRenderer.php [new file with mode: 0644]
typo3/sysext/core/Documentation/Changelog/master/Feature-61800-FAL-RendererRegistry.rst [new file with mode: 0644]
typo3/sysext/core/Tests/Unit/Resource/Rendering/AudioTagRendererTest.php [new file with mode: 0644]
typo3/sysext/core/Tests/Unit/Resource/Rendering/RendererRegistryTest.php [new file with mode: 0644]
typo3/sysext/core/Tests/Unit/Resource/Rendering/VideoTagRendererTest.php [new file with mode: 0644]
typo3/sysext/core/ext_localconf.php

diff --git a/typo3/sysext/core/Classes/Resource/Rendering/AudioTagRenderer.php b/typo3/sysext/core/Classes/Resource/Rendering/AudioTagRenderer.php
new file mode 100644 (file)
index 0000000..43baec2
--- /dev/null
@@ -0,0 +1,83 @@
+<?php
+namespace TYPO3\CMS\Core\Resource\Rendering;
+
+/**
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Resource\FileInterface;
+
+/**
+ * Class AudioTagRenderer
+ */
+class AudioTagRenderer implements FileRendererInterface {
+
+       /**
+        * Mime types that can be used in the HTML Video tag
+        *
+        * @var array
+        */
+       protected $possibleMimeTypes = array('audio/mpeg', 'audio/wav', 'audio/ogg');
+
+       /**
+        * Returns the priority of the renderer
+        * This way it is possible to define/overrule a renderer
+        * for a specific file type/context.
+        * For example create a video renderer for a certain storage/driver type.
+        * Should be between 1 and 100, 100 is more important than 1
+        *
+        * @return int
+        */
+       public function getPriority() {
+               return 1;
+       }
+
+       /**
+        * Check if given File(Reference) can be rendered
+        *
+        * @param FileInterface $file File or FileReference to render
+        * @return bool
+        */
+       public function canRender(FileInterface $file) {
+               return in_array($file->getMimeType(), $this->possibleMimeTypes, TRUE);
+       }
+
+       /**
+        * Render for given File(Reference) HTML output
+        *
+        * @param FileInterface $file
+        * @param int|string $width TYPO3 known format; examples: 220, 200m or 200c
+        * @param int|string $height TYPO3 known format; examples: 220, 200m or 200c
+        * @param array $options controls = TRUE/FALSE (default TRUE), autoplay = TRUE/FALSE (default FALSE), loop = TRUE/FALSE (default FALSE)
+        * @param bool $usedPathsRelativeToCurrentScript See $file->getPublicUrl()
+        * @return string
+        */
+       public function render(FileInterface $file, $width, $height, array $options = array(), $usedPathsRelativeToCurrentScript = FALSE) {
+               $additionalAttributes = array();
+               if (!isset($options['controls']) || !empty($options['controls'])) {
+                       $additionalAttributes[] = 'controls';
+               }
+               if (!empty($options['autoplay'])) {
+                       $additionalAttributes[] = 'autoplay';
+               }
+               if (!empty($options['loop'])) {
+                       $additionalAttributes[] = 'loop';
+               }
+
+               return sprintf(
+                       '<audio%s><source src="%s" type="%s"></audio>',
+                       empty($additionalAttributes) ? '' : ' ' . implode(' ', $additionalAttributes),
+                       $file->getPublicUrl($usedPathsRelativeToCurrentScript),
+                       $file->getMimeType()
+               );
+       }
+}
diff --git a/typo3/sysext/core/Classes/Resource/Rendering/FileRendererInterface.php b/typo3/sysext/core/Classes/Resource/Rendering/FileRendererInterface.php
new file mode 100644 (file)
index 0000000..1933326
--- /dev/null
@@ -0,0 +1,56 @@
+<?php
+namespace TYPO3\CMS\Core\Resource\Rendering;
+
+/**
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Resource\FileInterface;
+
+/**
+ * Class FileRendererInterface
+ */
+interface FileRendererInterface extends \TYPO3\CMS\Core\SingletonInterface {
+
+       /**
+        * Returns the priority of the renderer
+        * This way it is possible to define/overrule a renderer
+        * for a specific file type/context.
+        *
+        * For example create a video renderer for a certain storage/driver type.
+        *
+        * Should be between 1 and 100, 100 is more important than 1
+        *
+        * @return int
+        */
+       public function getPriority();
+
+       /**
+        * Check if given File(Reference) can be rendered
+        *
+        * @param FileInterface $file File or FileReference to render
+        * @return bool
+        */
+       public function canRender(FileInterface $file);
+
+       /**
+        * Render for given File(Reference) HTML output
+        *
+        * @param FileInterface $file
+        * @param int|string $width TYPO3 known format; examples: 220, 200m or 200c
+        * @param int|string $height TYPO3 known format; examples: 220, 200m or 200c
+        * @param array $options
+        * @param bool $usedPathsRelativeToCurrentScript See $file->getPublicUrl()
+        * @return string
+        */
+       public function render(FileInterface $file, $width, $height, array $options = array(), $usedPathsRelativeToCurrentScript = FALSE);
+}
\ No newline at end of file
diff --git a/typo3/sysext/core/Classes/Resource/Rendering/RendererRegistry.php b/typo3/sysext/core/Classes/Resource/Rendering/RendererRegistry.php
new file mode 100644 (file)
index 0000000..dffaa49
--- /dev/null
@@ -0,0 +1,132 @@
+<?php
+namespace TYPO3\CMS\Core\Resource\Rendering;
+
+/**
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Resource\FileInterface;
+use TYPO3\CMS\Core\Utility\GeneralUtility;
+
+/**
+ * Class RendererRegistry
+ */
+class RendererRegistry implements \TYPO3\CMS\Core\SingletonInterface {
+
+       /**
+        * Registered class names
+        *
+        * @var array
+        */
+       protected $classNames = array();
+
+       /**
+        * Instance cache for renderer classes
+        *
+        * @var FileRendererInterface[]
+        */
+       protected $instances = NULL;
+
+       /**
+        * Returns an instance of this class
+        *
+        * @return RendererRegistry
+        */
+       static public function getInstance() {
+               return GeneralUtility::makeInstance('TYPO3\\CMS\\Core\\Resource\\Rendering\\RendererRegistry');
+       }
+
+       /**
+        * Allows to register a Renderer class
+        *
+        * @param string $className
+        * @throws \InvalidArgumentException
+        */
+       public function registerRendererClass($className) {
+               if (!class_exists($className)) {
+                       throw new \InvalidArgumentException('The class you are registering is not available', 1411840171);
+               } elseif (!in_array('TYPO3\\CMS\\Core\\Resource\\Rendering\\FileRendererInterface', class_implements($className), TRUE)) {
+                       throw new \InvalidArgumentException('The renderer needs to implement the FileRendererInterface', 1411840172);
+               } else {
+                       $this->classNames[] = $className;
+               }
+       }
+
+       /**
+        * Get all registered renderer instances
+        *
+        * @return FileRendererInterface[]
+        */
+       public function getRendererInstances() {
+               if ($this->instances === NULL) {
+                       $this->instances = array();
+
+                       // As the result is in reverse order we need to reverse
+                       // the array before processing to keep the items with same
+                       // priority in the same order as they were added to the registry.
+                       $classNames = array_reverse($this->classNames);
+                       foreach ($classNames as $className) {
+                               /** @var FileRendererInterface $object */
+                               $object = $this->createRendererInstance($className);
+                               $this->instances[] = $object;
+                       }
+
+                       if (count($this->instances) > 1) {
+                               usort($this->instances, array($this, 'compareRendererPriority'));
+                       }
+               }
+               return $this->instances;
+       }
+
+       /**
+        * Create an instance of a certain renderer class
+        *
+        * @param string $className
+        * @return FileRendererInterface
+        */
+       protected function createRendererInstance($className) {
+               return GeneralUtility::makeInstance($className);
+       }
+
+       /**
+        * Compare the priority of two renderer classes
+        * Is used for sorting array of Renderer instances by priority
+        * We want the result to be ordered from high to low so a higher
+        * priority comes before a lower.
+        *
+        * @param FileRendererInterface $rendererA
+        * @param FileRendererInterface $rendererB
+        * @return int -1 a > b, 0 a == b, 1 a < b
+        */
+       protected function compareRendererPriority(FileRendererInterface $rendererA, FileRendererInterface $rendererB) {
+               return $rendererB->getPriority() - $rendererA->getPriority();
+       }
+
+       /**
+        * Get matching renderer with highest priority
+        *
+        * @param FileInterface $file
+        * @return NULL|FileRendererInterface
+        */
+       public function getRenderer(FileInterface $file) {
+               $matchingFileRenderer = NULL;
+
+               /** @var FileRendererInterface $fileRenderer */
+               foreach ($this->getRendererInstances() as $fileRenderer) {
+                       if ($fileRenderer->canRender($file)) {
+                               $matchingFileRenderer = $fileRenderer;
+                               break;
+                       }
+               }
+               return $matchingFileRenderer;
+       }
+}
\ No newline at end of file
diff --git a/typo3/sysext/core/Classes/Resource/Rendering/VideoTagRenderer.php b/typo3/sysext/core/Classes/Resource/Rendering/VideoTagRenderer.php
new file mode 100644 (file)
index 0000000..b6d5298
--- /dev/null
@@ -0,0 +1,85 @@
+<?php
+namespace TYPO3\CMS\Core\Resource\Rendering;
+
+/**
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+use TYPO3\CMS\Core\Resource\FileInterface;
+
+/**
+ * Class VideoTagRenderer
+ */
+class VideoTagRenderer implements FileRendererInterface {
+
+       /**
+        * Mime types that can be used in the HTML Video tag
+        *
+        * @var array
+        */
+       protected $possibleMimeTypes = array('video/mp4', 'video/webm', 'video/ogg', 'application/ogg');
+
+       /**
+        * Returns the priority of the renderer
+        * This way it is possible to define/overrule a renderer
+        * for a specific file type/context.
+        * For example create a video renderer for a certain storage/driver type.
+        * Should be between 1 and 100, 100 is more important than 1
+        *
+        * @return int
+        */
+       public function getPriority() {
+               return 1;
+       }
+
+       /**
+        * Check if given File(Reference) can be rendered
+        *
+        * @param FileInterface $file File or FileReference to render
+        * @return bool
+        */
+       public function canRender(FileInterface $file) {
+               return in_array($file->getMimeType(), $this->possibleMimeTypes, TRUE);
+       }
+
+       /**
+        * Render for given File(Reference) HTML output
+        *
+        * @param FileInterface $file
+        * @param int|string $width TYPO3 known format; examples: 220, 200m or 200c
+        * @param int|string $height TYPO3 known format; examples: 220, 200m or 200c
+        * @param array $options controls = TRUE/FALSE (default TRUE), autoplay = TRUE/FALSE (default FALSE), loop = TRUE/FALSE (default FALSE)
+        * @param bool $usedPathsRelativeToCurrentScript See $file->getPublicUrl()
+        * @return string
+        */
+       public function render(FileInterface $file, $width, $height, array $options = array(), $usedPathsRelativeToCurrentScript = FALSE) {
+               $additionalAttributes = array();
+               if (!isset($options['controls']) || !empty($options['controls'])) {
+                       $additionalAttributes[] = 'controls';
+               }
+               if (!empty($options['autoplay'])) {
+                       $additionalAttributes[] = 'autoplay';
+               }
+               if (!empty($options['loop'])) {
+                       $additionalAttributes[] = 'loop';
+               }
+
+               return sprintf(
+                       '<video width="%d" height="%d"%s><source src="%s" type="%s"></video>',
+                       (int)$width,
+                       (int)$height,
+                       empty($additionalAttributes) ? '' : ' ' . implode(' ', $additionalAttributes),
+                       $file->getPublicUrl($usedPathsRelativeToCurrentScript),
+                       $file->getMimeType()
+               );
+       }
+}
diff --git a/typo3/sysext/core/Documentation/Changelog/master/Feature-61800-FAL-RendererRegistry.rst b/typo3/sysext/core/Documentation/Changelog/master/Feature-61800-FAL-RendererRegistry.rst
new file mode 100644 (file)
index 0000000..c87c74a
--- /dev/null
@@ -0,0 +1,43 @@
+============================================================
+Feature: #61800 - Registry for adding file rendering classes
+============================================================
+
+Description
+===========
+
+To be able to render all kinds of media files a file rendering registry is needed where you can register
+a "renderer" class that can generate the needed HTML output.
+
+Every renderer has a priority between 1 and 100, 100 is more important than 1.
+When the rendererRegistry is asked for a renderer that fits a given file all registered renderer classes are "asked",
+in order of priority, if they are able to render the file. The first renderer class that can render the file an
+instance is returned by the rendererRegistry.
+
+Every registered renderer class needs to implement the FileRendererInterface. This makes sure the class has a
+getPriority(), canRender() and render() method.
+
+- getPriority() returns integer between 1 and 100
+- canRender() gets a file(Reference) object as parameter and returns TRUE if the class is able to render the file
+  It checks on mime-type but also storage type etc can be performed to determine if creating the correct output
+  is possible
+- render() get also the file(Reference) object as parameter together with width, height and an optional options array
+  the return value is the HTML output
+
+A AudioTagRenderer and VideoTagRenderer are already added.
+
+It is possible to register your own renderer classes in the ext_localconf.php of an extension.
+
+Example:
+::
+
+$rendererRegistry = \TYPO3\CMS\Core\Resource\Rendering\RendererRegistry::getInstance();
+$rendererRegistry->registerRendererClass(
+       'MyCompany\\MySpecialMediaFile\\Rendering\\MySpecialMediaFileRenderer'
+);
+..
+
+Impact
+======
+
+The registry on its own doesn't do anything. Some followup patches are needed to use this registry
+to find the correct renderer class for rendering videos and other media files in BE preview and FE.
\ No newline at end of file
diff --git a/typo3/sysext/core/Tests/Unit/Resource/Rendering/AudioTagRendererTest.php b/typo3/sysext/core/Tests/Unit/Resource/Rendering/AudioTagRendererTest.php
new file mode 100644 (file)
index 0000000..3fbada0
--- /dev/null
@@ -0,0 +1,124 @@
+<?php
+namespace TYPO3\CMS\Core\Tests\Unit\Resource\Rendering;
+
+/**
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Class AudioTagRendererTest
+ */
+class AudioTagRendererTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
+
+       /**
+        * @test
+        */
+       public function getPriorityReturnsCorrectValue() {
+               $audioTagRenderer = new \TYPO3\CMS\Core\Resource\Rendering\AudioTagRenderer();
+
+               $this->assertSame(1, $audioTagRenderer->getPriority());
+       }
+
+       /**
+        * @test
+        */
+       public function canRenderReturnsTrueOnCorrectFile() {
+               $audioTagRenderer = new \TYPO3\CMS\Core\Resource\Rendering\AudioTagRenderer();
+
+               $fileResourceMock1 = $this->getMock('TYPO3\\CMS\\Core\\Resource\\File', array(), array(), '', FALSE);
+               $fileResourceMock1->expects($this->any())->method('getMimeType')->will($this->returnValue('audio/mpeg'));
+               $fileResourceMock2 = $this->getMock('TYPO3\\CMS\\Core\\Resource\\File', array(), array(), '', FALSE);
+               $fileResourceMock2->expects($this->any())->method('getMimeType')->will($this->returnValue('audio/wav'));
+               $fileResourceMock3 = $this->getMock('TYPO3\\CMS\\Core\\Resource\\File', array(), array(), '', FALSE);
+               $fileResourceMock3->expects($this->any())->method('getMimeType')->will($this->returnValue('audio/ogg'));
+
+               $this->assertTrue($audioTagRenderer->canRender($fileResourceMock1));
+               $this->assertTrue($audioTagRenderer->canRender($fileResourceMock2));
+               $this->assertTrue($audioTagRenderer->canRender($fileResourceMock3));
+       }
+
+       /**
+        * @test
+        */
+       public function canRenderReturnsFalseOnCorrectFile() {
+               $audioTagRenderer = new \TYPO3\CMS\Core\Resource\Rendering\AudioTagRenderer();
+
+               $fileResourceMock = $this->getMock('TYPO3\\CMS\\Core\\Resource\\File', array(), array(), '', FALSE);
+               $fileResourceMock->expects($this->any())->method('getMimeType')->will($this->returnValue('video/mp4'));
+
+               $this->assertFalse($audioTagRenderer->canRender($fileResourceMock));
+       }
+
+       /**
+        * @test
+        */
+       public function renderOutputIsCorrect() {
+               $audioTagRenderer = new \TYPO3\CMS\Core\Resource\Rendering\AudioTagRenderer();
+
+               $fileResourceMock = $this->getMock('TYPO3\\CMS\\Core\\Resource\\File', array(), array(), '', FALSE);
+               $fileResourceMock->expects($this->any())->method('getMimeType')->will($this->returnValue('audio/mpeg'));
+               $fileResourceMock->expects($this->any())->method('getPublicUrl')->will($this->returnValue('//:path/myAudioFile'));
+
+               $this->assertSame(
+                       '<audio controls><source src="//:path/myAudioFile" type="audio/mpeg"></audio>',
+                       $audioTagRenderer->render($fileResourceMock, '300m', '200')
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function renderOutputWithLoopIsCorrect() {
+               $audioTagRenderer = new \TYPO3\CMS\Core\Resource\Rendering\AudioTagRenderer();
+
+               $fileResourceMock = $this->getMock('TYPO3\\CMS\\Core\\Resource\\File', array(), array(), '', FALSE);
+               $fileResourceMock->expects($this->any())->method('getMimeType')->will($this->returnValue('audio/mpeg'));
+               $fileResourceMock->expects($this->any())->method('getPublicUrl')->will($this->returnValue('//:path/myAudioFile'));
+
+               $this->assertSame(
+                       '<audio controls loop><source src="//:path/myAudioFile" type="audio/mpeg"></audio>',
+                       $audioTagRenderer->render($fileResourceMock, '300m', '200', array('loop' => 1))
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function renderOutputWithAutoplayIsCorrect() {
+               $audioTagRenderer = new \TYPO3\CMS\Core\Resource\Rendering\AudioTagRenderer();
+
+               $fileResourceMock = $this->getMock('TYPO3\\CMS\\Core\\Resource\\File', array(), array(), '', FALSE);
+               $fileResourceMock->expects($this->any())->method('getMimeType')->will($this->returnValue('audio/mpeg'));
+               $fileResourceMock->expects($this->any())->method('getPublicUrl')->will($this->returnValue('//:path/myAudioFile'));
+
+               $this->assertSame(
+                       '<audio controls autoplay><source src="//:path/myAudioFile" type="audio/mpeg"></audio>',
+                       $audioTagRenderer->render($fileResourceMock, '300m', '200', array('autoplay' => 1))
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function renderOutputWithAutoplayAndWithoutControllsIsCorrect() {
+               $audioTagRenderer = new \TYPO3\CMS\Core\Resource\Rendering\AudioTagRenderer();
+
+               $fileResourceMock = $this->getMock('TYPO3\\CMS\\Core\\Resource\\File', array(), array(), '', FALSE);
+               $fileResourceMock->expects($this->any())->method('getMimeType')->will($this->returnValue('audio/mpeg'));
+               $fileResourceMock->expects($this->any())->method('getPublicUrl')->will($this->returnValue('//:path/myAudioFile'));
+
+               $this->assertSame(
+                       '<audio autoplay><source src="//:path/myAudioFile" type="audio/mpeg"></audio>',
+                       $audioTagRenderer->render($fileResourceMock, '300m', '200', array('controls' => 0, 'autoplay' => 1))
+               );
+       }
+}
\ No newline at end of file
diff --git a/typo3/sysext/core/Tests/Unit/Resource/Rendering/RendererRegistryTest.php b/typo3/sysext/core/Tests/Unit/Resource/Rendering/RendererRegistryTest.php
new file mode 100644 (file)
index 0000000..bfc78b4
--- /dev/null
@@ -0,0 +1,191 @@
+<?php
+namespace TYPO3\CMS\Core\Tests\Unit\Resource\Rendering;
+
+/**
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Test cases for RendererRegistry
+ */
+class RendererRegistryTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
+
+       /**
+        * Initialize an RendererRegistry and mock createRendererInstance()
+        *
+        * @param array $createsRendererInstances
+        * @return \PHPUnit_Framework_MockObject_MockObject|\TYPO3\CMS\Core\Resource\Rendering\RendererRegistry
+        */
+       protected function getTestRendererRegistry(array $createsRendererInstances = array()) {
+               $rendererRegistry = $this->getMockBuilder('TYPO3\\CMS\\Core\\Resource\\Rendering\\RendererRegistry')
+                       ->setMethods(array('createRendererInstance'))
+                       ->getMock();
+
+               if (count($createsRendererInstances)) {
+                       $rendererRegistry->expects($this->any())
+                               ->method('createRendererInstance')
+                               ->will($this->returnValueMap($createsRendererInstances));
+               }
+
+               return $rendererRegistry;
+       }
+
+       /**
+        * @test
+        */
+       public function registeredFileRenderClassCanBeRetrieved() {
+               $rendererClass = uniqid('myRenderer');
+               $rendererObject = $this->getMock('TYPO3\\CMS\\Core\\Resource\\Rendering\\FileRendererInterface', array(), array(), $rendererClass);
+
+               $rendererRegistry = $this->getTestRendererRegistry(array(array($rendererClass, $rendererObject)));
+
+               $rendererRegistry->registerRendererClass($rendererClass);
+               $this->assertContains($rendererObject, $rendererRegistry->getRendererInstances(), '', FALSE, FALSE);
+       }
+
+       /**
+        * @test
+        * @expectedException \InvalidArgumentException
+        * @expectedExceptionCode 1411840171
+        */
+       public function registerRendererClassThrowsExceptionIfClassDoesNotExist() {
+               $rendererRegistry = $this->getTestRendererRegistry();
+               $rendererRegistry->registerRendererClass(uniqid());
+       }
+
+       /**
+        * @test
+        * @expectedException \InvalidArgumentException
+        * @expectedExceptionCode 1411840172
+        */
+       public function registerRendererClassThrowsExceptionIfClassDoesNotImplementRightInterface() {
+               $className = __CLASS__;
+               $rendererRegistry = $this->getTestRendererRegistry();
+               $rendererRegistry->registerRendererClass($className);
+       }
+
+       /**
+        * @test
+        */
+       public function registerRendererClassWithHighestPriorityIsFirstInResult() {
+               $rendererClass1 = uniqid('myRenderer1');
+               $rendererObject1 = $this->getMock('TYPO3\\CMS\\Core\\Resource\\Rendering\\FileRendererInterface', array(), array(), $rendererClass1);
+               $rendererObject1->expects($this->any())->method('getPriority')->will($this->returnValue(1));
+
+               $rendererClass2 = uniqid('myRenderer2');
+               $rendererObject2 = $this->getMock('TYPO3\\CMS\\Core\\Resource\\Rendering\\FileRendererInterface', array(), array(), $rendererClass2);
+               $rendererObject2->expects($this->any())->method('getPriority')->will($this->returnValue(10));
+
+               $rendererClass3 = uniqid('myRenderer3');
+               $rendererObject3 = $this->getMock('TYPO3\\CMS\\Core\\Resource\\Rendering\\FileRendererInterface', array(), array(), $rendererClass3);
+               $rendererObject3->expects($this->any())->method('getPriority')->will($this->returnValue(2));
+
+               $createdRendererInstances = array(
+                       array($rendererClass1, $rendererObject1),
+                       array($rendererClass2, $rendererObject2),
+                       array($rendererClass3, $rendererObject3),
+               );
+
+               $rendererRegistry = $this->getTestRendererRegistry($createdRendererInstances);
+               $rendererRegistry->registerRendererClass($rendererClass1);
+               $rendererRegistry->registerRendererClass($rendererClass2);
+               $rendererRegistry->registerRendererClass($rendererClass3);
+
+               $rendererInstances = $rendererRegistry->getRendererInstances();
+               $this->assertTrue($rendererInstances[0] instanceof $rendererClass2);
+               $this->assertTrue($rendererInstances[1] instanceof $rendererClass3);
+               $this->assertTrue($rendererInstances[2] instanceof $rendererClass1);
+       }
+
+       /**
+        * @test
+        */
+       public function registeredFileRendererClassWithSamePriorityAreReturnedInSameOrderAsTheyWereAdded() {
+               $rendererClass1 = uniqid('myRenderer1');
+               $rendererObject1 = $this->getMock('TYPO3\\CMS\\Core\\Resource\\Rendering\\FileRendererInterface', array(), array(), $rendererClass1);
+               $rendererObject1->expects($this->any())->method('getPriority')->will($this->returnValue(1));
+
+               $rendererClass2 = uniqid('myRenderer2');
+               $rendererObject2 = $this->getMock('TYPO3\\CMS\\Core\\Resource\\Rendering\\FileRendererInterface', array(), array(), $rendererClass2);
+               $rendererObject2->expects($this->any())->method('getPriority')->will($this->returnValue(1));
+
+               $createdRendererInstances = array(
+                       array($rendererClass1, $rendererObject1),
+                       array($rendererClass2, $rendererObject2),
+               );
+
+               $rendererRegistry = $this->getTestRendererRegistry($createdRendererInstances);
+               $rendererRegistry->registerRendererClass($rendererClass1);
+               $rendererRegistry->registerRendererClass($rendererClass2);
+
+               $rendererInstances = $rendererRegistry->getRendererInstances();
+               $this->assertTrue($rendererInstances[0] instanceof $rendererClass1);
+               $this->assertTrue($rendererInstances[1] instanceof $rendererClass2);
+       }
+
+       /**
+        * @test
+        */
+       public function getRendererReturnsCorrectInstance() {
+
+               $this->markTestSkipped('Test triggers a error this is known PHP bug - http://stackoverflow.com/questions/3235387/usort-array-was-modified-by-the-user-comparison-function)');
+
+               $rendererClass1 = uniqid('myVideoRenderer');
+               $rendererObject1 = $this->getMock('TYPO3\\CMS\\Core\\Resource\\Rendering\\FileRendererInterface', array('getPriority', 'canRender', 'render'), array(), $rendererClass1);
+               $rendererObject1->expects($this->any())->method('getPriority')->will($this->returnValue(1));
+               $rendererObject1->expects($this->once())->method('canRender')->will($this->returnValue(TRUE));
+
+               $rendererClass2 = uniqid('myAudioRenderer');
+               $rendererObject2 = $this->getMock('TYPO3\\CMS\\Core\\Resource\\Rendering\\FileRendererInterface', array('getPriority', 'canRender', 'render'), array(), $rendererClass2);
+               $rendererObject2->expects($this->any())->method('getPriority')->will($this->returnValue(10));
+               $rendererObject2->expects($this->once())->method('canRender')->will($this->returnValue(FALSE));
+
+               $fileResourceMock = $this->getMock('TYPO3\\CMS\\Core\\Resource\\File', array(), array(), '', FALSE);
+
+               $createdRendererInstances = array(
+                       array($rendererClass1, $rendererObject1),
+                       array($rendererClass2, $rendererObject2),
+               );
+
+               $rendererRegistry = $this->getTestRendererRegistry($createdRendererInstances);
+               $rendererRegistry->registerRendererClass($rendererClass1);
+               $rendererRegistry->registerRendererClass($rendererClass2);
+
+               $rendererRegistry->getRendererInstances();
+
+               $renderer = $rendererRegistry->getRenderer($fileResourceMock);
+
+               $this->assertTrue($renderer instanceof $rendererClass1);
+
+       }
+
+       /**
+        * @test
+        */
+       public function getRendererReturnsCorrectInstance2() {
+
+               $rendererRegistry = \TYPO3\CMS\Core\Resource\Rendering\RendererRegistry::getInstance();
+               $rendererRegistry->registerRendererClass('TYPO3\\CMS\\Core\\Resource\\Rendering\\AudioTagRenderer');
+               $rendererRegistry->registerRendererClass('TYPO3\\CMS\\Core\\Resource\\Rendering\\VideoTagRenderer');
+
+               $fileResourceMock = $this->getMock('TYPO3\\CMS\\Core\\Resource\\File', array(), array(), '', FALSE);
+               $fileResourceMock->expects($this->any())->method('getMimeType')->will($this->returnValue('video/mp4'));
+
+
+               $rendererRegistry->getRendererInstances();
+
+               $renderer = $rendererRegistry->getRenderer($fileResourceMock);
+
+               $this->assertInstanceOf('TYPO3\\CMS\\Core\\Resource\\Rendering\\VideoTagRenderer', $renderer);
+       }
+}
+
diff --git a/typo3/sysext/core/Tests/Unit/Resource/Rendering/VideoTagRendererTest.php b/typo3/sysext/core/Tests/Unit/Resource/Rendering/VideoTagRendererTest.php
new file mode 100644 (file)
index 0000000..8a077f8
--- /dev/null
@@ -0,0 +1,127 @@
+<?php
+namespace TYPO3\CMS\Core\Tests\Unit\Resource\Rendering;
+
+/**
+ * This file is part of the TYPO3 CMS project.
+ *
+ * It is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU General Public License, either version 2
+ * of the License, or any later version.
+ *
+ * For the full copyright and license information, please read the
+ * LICENSE.txt file that was distributed with this source code.
+ *
+ * The TYPO3 project - inspiring people to share!
+ */
+
+/**
+ * Class VideoTagRendererTest
+ */
+class VideoTagRendererTest extends \TYPO3\CMS\Core\Tests\UnitTestCase {
+
+       /**
+        * @test
+        */
+       public function getPriorityReturnsCorrectValue() {
+               $VideoTagRenderer = new \TYPO3\CMS\Core\Resource\Rendering\VideoTagRenderer();
+
+               $this->assertSame(1, $VideoTagRenderer->getPriority());
+       }
+
+       /**
+        * @test
+        */
+       public function canRenderReturnsTrueOnCorrectFile() {
+               $VideoTagRenderer = new \TYPO3\CMS\Core\Resource\Rendering\VideoTagRenderer();
+
+               $fileResourceMock1 = $this->getMock('TYPO3\\CMS\\Core\\Resource\\File', array(), array(), '', FALSE);
+               $fileResourceMock1->expects($this->any())->method('getMimeType')->will($this->returnValue('video/mp4'));
+               $fileResourceMock2 = $this->getMock('TYPO3\\CMS\\Core\\Resource\\File', array(), array(), '', FALSE);
+               $fileResourceMock2->expects($this->any())->method('getMimeType')->will($this->returnValue('video/webm'));
+               $fileResourceMock3 = $this->getMock('TYPO3\\CMS\\Core\\Resource\\File', array(), array(), '', FALSE);
+               $fileResourceMock3->expects($this->any())->method('getMimeType')->will($this->returnValue('video/ogg'));
+               $fileResourceMock4 = $this->getMock('TYPO3\\CMS\\Core\\Resource\\File', array(), array(), '', FALSE);
+               $fileResourceMock4->expects($this->any())->method('getMimeType')->will($this->returnValue('application/ogg'));
+
+               $this->assertTrue($VideoTagRenderer->canRender($fileResourceMock1));
+               $this->assertTrue($VideoTagRenderer->canRender($fileResourceMock2));
+               $this->assertTrue($VideoTagRenderer->canRender($fileResourceMock3));
+               $this->assertTrue($VideoTagRenderer->canRender($fileResourceMock4));
+       }
+
+       /**
+        * @test
+        */
+       public function canRenderReturnsFalseOnCorrectFile() {
+               $VideoTagRenderer = new \TYPO3\CMS\Core\Resource\Rendering\VideoTagRenderer();
+
+               $fileResourceMock = $this->getMock('TYPO3\\CMS\\Core\\Resource\\File', array(), array(), '', FALSE);
+               $fileResourceMock->expects($this->any())->method('getMimeType')->will($this->returnValue('audio/mpeg'));
+
+               $this->assertFalse($VideoTagRenderer->canRender($fileResourceMock));
+       }
+
+       /**
+        * @test
+        */
+       public function renderOutputIsCorrect() {
+               $VideoTagRenderer = new \TYPO3\CMS\Core\Resource\Rendering\VideoTagRenderer();
+
+               $fileResourceMock = $this->getMock('TYPO3\\CMS\\Core\\Resource\\File', array(), array(), '', FALSE);
+               $fileResourceMock->expects($this->any())->method('getMimeType')->will($this->returnValue('video/mp4'));
+               $fileResourceMock->expects($this->any())->method('getPublicUrl')->will($this->returnValue('//:path/myVideoFile'));
+
+               $this->assertSame(
+                       '<video width="300" height="200" controls><source src="//:path/myVideoFile" type="video/mp4"></video>',
+                       $VideoTagRenderer->render($fileResourceMock, '300m', '200')
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function renderOutputWithLoopIsCorrect() {
+               $VideoTagRenderer = new \TYPO3\CMS\Core\Resource\Rendering\VideoTagRenderer();
+
+               $fileResourceMock = $this->getMock('TYPO3\\CMS\\Core\\Resource\\File', array(), array(), '', FALSE);
+               $fileResourceMock->expects($this->any())->method('getMimeType')->will($this->returnValue('video/mp4'));
+               $fileResourceMock->expects($this->any())->method('getPublicUrl')->will($this->returnValue('//:path/myVideoFile'));
+
+               $this->assertSame(
+                       '<video width="300" height="200" controls loop><source src="//:path/myVideoFile" type="video/mp4"></video>',
+                       $VideoTagRenderer->render($fileResourceMock, '300m', '200', array('loop' => 1))
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function renderOutputWithAutoplayIsCorrect() {
+               $VideoTagRenderer = new \TYPO3\CMS\Core\Resource\Rendering\VideoTagRenderer();
+
+               $fileResourceMock = $this->getMock('TYPO3\\CMS\\Core\\Resource\\File', array(), array(), '', FALSE);
+               $fileResourceMock->expects($this->any())->method('getMimeType')->will($this->returnValue('video/mp4'));
+               $fileResourceMock->expects($this->any())->method('getPublicUrl')->will($this->returnValue('//:path/myVideoFile'));
+
+               $this->assertSame(
+                       '<video width="300" height="200" controls autoplay><source src="//:path/myVideoFile" type="video/mp4"></video>',
+                       $VideoTagRenderer->render($fileResourceMock, '300m', '200', array('autoplay' => 1))
+               );
+       }
+
+       /**
+        * @test
+        */
+       public function renderOutputWithAutoplayAndWithoutControllsIsCorrect() {
+               $VideoTagRenderer = new \TYPO3\CMS\Core\Resource\Rendering\VideoTagRenderer();
+
+               $fileResourceMock = $this->getMock('TYPO3\\CMS\\Core\\Resource\\File', array(), array(), '', FALSE);
+               $fileResourceMock->expects($this->any())->method('getMimeType')->will($this->returnValue('video/mp4'));
+               $fileResourceMock->expects($this->any())->method('getPublicUrl')->will($this->returnValue('//:path/myVideoFile'));
+
+               $this->assertSame(
+                       '<video width="300" height="200" autoplay><source src="//:path/myVideoFile" type="video/mp4"></video>',
+                       $VideoTagRenderer->render($fileResourceMock, '300m', '200', array('controls' => 0, 'autoplay' => 1))
+               );
+       }
+}
\ No newline at end of file
index 0b83bc4..78e62f4 100644 (file)
@@ -29,3 +29,8 @@ $signalSlotDispatcher->connect(
 unset($signalSlotDispatcher);
 
 $GLOBALS['TYPO3_CONF_VARS']['FE']['eID_include']['dumpFile'] = 'EXT:core/Resources/PHP/FileDumpEID.php';
+
+/** @var \TYPO3\CMS\Core\Resource\Rendering\RendererRegistry $rendererRegistry */
+$rendererRegistry = \TYPO3\CMS\Core\Resource\Rendering\RendererRegistry::getInstance();
+$rendererRegistry->registerRendererClass('TYPO3\\CMS\\Core\\Resource\\Rendering\\AudioTagRenderer');
+$rendererRegistry->registerRendererClass('TYPO3\\CMS\\Core\\Resource\\Rendering\\VideoTagRenderer');