Get Valid Filenames V5


#1

Hi all

In Pimcore Version 4.6 works this for Valid filenamens in startup.php

\Pimcore::getEventManager()->attach(“system.service.preGetValidKey”, function (\Zend_EventManager_Event $event) {
$key = $event->getParam(“key”);
$key = \Pimcore\File::getValidFilename($key);
return $key;
});

How can i Use this in Pimcore Version V5?

Best greetings,

Markus


#2

read this
and event you’re looking for is \Pimcore\Event\SystemEvents::SERVICE_PRE_GET_VALID_KEY


#3

I have made a KeyListener that fixes the keys of documents and objects and the filenames of assets. I use a white list of approved characters.

src/AppBundle/EventListener/Keylistener.php

<?php

namespace AppBundle\EventListener;

use Doctrine\ORM\Event\LifecycleEventArgs;
use AppBundle\Entity\Product;

use Pimcore\Event\Model\ElementEventInterface;
use Pimcore\Event\Model\DataObjectEvent;
use Pimcore\Event\Model\AssetEvent;
use Pimcore\Event\Model\DocumentEvent;

use Symfony\Component\EventDispatcher\GenericEvent;

/**
 * This listener hooks into the saving of documents/assets/objects.
 * It is called before creating/saving an item.
 * The key of the item is sanitized so that it can safely be used as part of a human/robot friendly public URL.
*/
class KeyListener {

    public function onPreAdd(ElementEventInterface $e) {
        $this->updateKey($e);
    }

    public function onPreUpdate(ElementEventInterface $e) {
        $this->updateKey($e);
    } 

    public function onPostUpdate(ElementEventInterface $e) {
        $this->updateKey($e);
    } 

    /**
     * Called before key/filename is changed in the Admin interface. The request returns a JSON with a valid key.
     * This method updates the SUGGESTED key of an asset to a more restricted variant.
    */
    public function onPreGetValidKey(GenericEvent $e) {
        $type = $e->getArgument('type');
        if($type == 'asset') {
            $e->setArgument('key', $this->sanitizeKey($e->getArgument('key'), 'abcdefghijklmnopqrstuwvxyz01234567890-._'));
        } else if($type == 'document') {
            $e->setArgument('key', $this->sanitizeKey($e->getArgument('key')));
        } else if($type == 'object') {
            $e->setArgument('key', $this->sanitizeKey($e->getArgument('key')));
        }
    }

    /**
     * Updates the actual key of documents/assets/objects.
     * Is called when the key is changed though the API and admin interface.
     * @param ElementEventInterface $e Object provided by framework.
    */
    public function updateKey(ElementEventInterface $e) {

        if($e instanceof AssetEvent) {
            $asset = $e->getAsset();
            $asset->setFilename($this->sanitizeKey($asset->getKey(), 'abcdefghijklmnopqrstuwvxyz01234567890-._'));
        } else if ($e instanceof DocumentEvent) {
            $document = $e->getDocument();
            $document->setKey($this->sanitizeKey($document->getKey()));
        } else if ($e instanceof DataObjectEvent) {
            $object = $e->getObject(); 
            $object->setKey($this->sanitizeKey($object->getKey()));
        }
    }

    /**
     * Remove any charachters that are not lowercase letters, numbers or dashes.
     * Also remove any dashes at the start and end. Double and triple dashes are converted to singles.
     * @param string $str Key
     * @param string $chars Optional list of whitelisted characters.
     */
    public function sanitizeKey($str, $chars = 'abcdefghijklmnopqrstuwvxyz01234567890-') {
        $str = trim(strtolower($str));
        $out = '';
        for($i = 0; $i < strlen($str); $i++) {
            if(strpos($chars, $str[$i]) !== false) {
                $out .= $str[$i];
            }
        }
        return str_replace(['----', '---', '--'], ['-', '-', '-'], $out);
    }
}

In app/config/services.yml add the following lines:

AppBundle\EventListener\KeyListener:
    tags:
        - { name: kernel.event_listener, event: pimcore.asset.preAdd, method: onPreAdd }
        - { name: kernel.event_listener, event: pimcore.document.preAdd, method: onPreAdd }
        - { name: kernel.event_listener, event: pimcore.dataobject.preAdd, method: onPreAdd }
        - { name: kernel.event_listener, event: pimcore.asset.preUpdate, method: onPreUpdate }
        - { name: kernel.event_listener, event: pimcore.asset.postUpdate, method: onPostUpdate }
        - { name: kernel.event_listener, event: pimcore.document.preUpdate, method: onPreUpdate }
        - { name: kernel.event_listener, event: pimcore.dataobject.preUpdate, method: onPreUpdate }
        - { name: kernel.event_listener, event: pimcore.system.service.preGetValidKey, method: onPreGetValidKey }

#4

Hi John5

Thanks it works perfect for me.

Best Regards
Markus


#5

Hi John5,

Your code is great and works very well. But there is a problem: if I upload an asset with the same name, I get this error:

{"success":false,"message":"An exception occurred while executing \u0027INSERT INTO assets (`filename`, `path`, `parentId`) VALUES (?, ?, ?)\u0027 with params [\u0022capture-d-e-cran-2018-11-07-a-21-20-43.png\u0022, \u0022\\\/\u0022, 1]:\n\nSQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry \u0027\/-capture-d-e-cran-2018-11-07-a-21-20-43.png\u0027 for key \u0027fullpath\u0027"}

Same problem with DataObject:

Unable to paste item
<b>unique constraint violation</b>

So you code does not seem to avoid name collision.

How can we fix that ?


#6

Any idea guys?..

I can not find a way to solve this problem…