TYPO3 Flow中的多个文件上传

时间:2014-12-05 09:58:44

标签: php doctrine-orm many-to-many relationship typo3-flow

我需要支持TYPO3 Flow中文件上传的multiple属性(<input type="file" multiple />)。所以这就是我到目前为止所做的。

我是一个拥有资源集合的实体:

/**
 * @var \Doctrine\Common\Collections\Collection<\TYPO3\Flow\Resource\Resource>
 * @ORM\ManyToMany(cascade={"all"})
 * @ORM\JoinTable(inverseJoinColumns={@ORM\JoinColumn(unique=true,onDelete="cascade")})
 */
 protected $resources;

因此我增强了f:form.upload视图助手:

/**
 * Overrides upload view helper.
 */
class UploadViewHelper extends \TYPO3\Fluid\ViewHelpers\Form\UploadViewHelper {

    /**
     * Initialize the arguments.
     *
     * @return void
     * @api
     */
    public function initializeArguments() {
        parent::initializeArguments();

        $this->registerArgument('multiple', 'boolean', 'Specifies that the user is allowed to enter more than one value in the <input> element.', FALSE, FALSE);
    }

    /**
     * Renders the upload field.
     *
     * @return string
     * @api
     */
    public function render() {
        $name = $this->getName();
        $multiple = $this->arguments['multiple'];
        $this->registerFieldNameForFormTokenGeneration($name);

        $output = '';

        if ($multiple) {
            $collectionObject = $this->getUploadedResources();
            if ($collectionObject !== NULL) {
                foreach($collectionObject as $resourceObjectIndex => $resourceObject) {
                    $output .= $this->renderUploadedResource($resourceObject, $resourceObjectIndex);
                }
            }
            $this->tag->addAttribute('multiple', 'multiple');
        } else {
            $resourceObject = $this->getUploadedResource();
            if ($resourceObject !== NULL) {
                $output .= $this->renderUploadedResource($resourceObject);
            }
        }
        $this->tag->addAttribute('type', 'file');
        $this->tag->addAttribute('name', $name);

        $this->setErrorClassAttribute();

        $output .= $this->tag->render();
        return $output;
    }

    protected function renderUploadedResource($resourceObject, $resourceObjectIndex = NULL) {
        $output = '';
        $resourceObjectIndex = $resourceObjectIndex === NULL ? '' : '[' . $resourceObjectIndex . ']';

        $filenameIdAttribute = $resourcePointerIdAttribute = '';
        if ($this->hasArgument('id')) {
            $filenameIdAttribute = ' id="' . htmlspecialchars($this->arguments['id']) . '-filename"';
            $resourcePointerIdAttribute = ' id="' . htmlspecialchars($this->arguments['id']) . '-resourcePointer"';
        }
        $filenameValue = $resourceObject->getFilename();
        $resourcePointerValue = $resourceObject->getResourcePointer();
        $output .= '<input type="hidden" name="' . parent::getName() . $resourceObjectIndex . '[submittedFile][filename]" value="' . htmlspecialchars($filenameValue) . '"' . $filenameIdAttribute . ' />';
        $output .= '<input type="hidden" name="' . parent::getName() . $resourceObjectIndex . '[submittedFile][resourcePointer]" value="' . htmlspecialchars($resourcePointerValue) . '"' . $resourcePointerIdAttribute . ' />';

        return $output;
    }

    /**
     * Returns a previously uploaded resources.
     * If errors occurred during property mapping for this property, NULL is returned
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    protected function getUploadedResources() {
        if ($this->getMappingResultsForProperty()->hasErrors()) {
            return NULL;
        }
        $collectionObject = $this->getValue(FALSE);
        if ($collectionObject instanceof Collection) {
            return $collectionObject;
        }
        return $this->propertyMapper->convert($collectionObject, 'Doctrine\Common\Collections\Collection<\TYPO3\Flow\Resource\Resource>');
    }

    /**
     * Override `getName()`.
     *
     * @return string Name
     */
    protected function getName() {
        $name = parent::getName();
        return $this->postfixFieldName($name);
    }

    /**
     * Append `[]` to the field name when the argument `multiple` is set.
     *
     * @param string $name 
     * @return string Name
     */
    protected function postfixFieldName($name) {
        return $this->hasArgument('multiple') && $this->arguments['multiple'] ? $name . '[]' : $name;
    }
}

因此视图帮助器<my:form.upload property="resources" multiple="1" />将为多个文件创建一个数组字段:

<input multiple="multiple" name="entity[resources][]" type="file">

如果已经上传,则显示如下:

<input name="entity[resources][0][submittedFile][filename]" value="Foo.jpg" type="hidden">
<input name="entity[resources][0][submittedFile][resourcePointer]" value="7c94c0200e9f25b1ccb48c2853147f52286328d0" type="hidden">
<input multiple="multiple" name="entity[resources][]" type="file">

为了使其正常工作,我将其添加到控制器中:

protected function initializeAction() {
    parent::initializeAction();

    switch($this->actionMethodName) {
        case 'createAction':
        case 'updateAction':
            $this->arguments
                ->getArgument('resource')
                ->getPropertyMappingConfiguration()
                ->forProperty('resources.*')
                ->setTypeConverterOption(
                    'TYPO3\Flow\Property\TypeConverter\PersistentObjectConverter',
                    \TYPO3\Flow\Property\TypeConverter\PersistentObjectConverter::CONFIGURATION_MODIFICATION_ALLOWED,
                    TRUE
                );
            break;
    }
}

问题是,每次调用更新操作时,只要上传已经存在,就会重新添加现有上传,并且表typo3_flow_resource_resource会增长和增长。有人知道如何解决这个问题吗?

通知 此解决方案应仅允许替换上传的文件。

0 个答案:

没有答案