Vichuploaderbundle: how to use custom namer

Created on 4 Apr 2012  路  15Comments  路  Source: dustin10/VichUploaderBundle

hi, i'm try your bundle, but i don't understand how to use custom namer.

Can you explain how to implement a custom namer , or show an example for a custom namer.

thanks for help.

Sorry for my english,

Most helpful comment

Hi, you can do something like this:

in MySite\MyBundle\Entity\Entity.php:

/**
 * @Assert\File(maxSize="20000000")
 * @Vich\UploadableField(mapping="media_file", fileNameProperty="filename")
 *
 * @var File $file
 */
public $file;

in app/config/config.yml:

vich_uploader:
    mappings:
        media_file:
            upload_dir: %kernel.root_dir%/../uploads/media
            delete_on_remove: true
            namer: namer.media_file

in MySite\MyBundle\Resources\config\services.yml:

services:
    namer.media_file:
        class: MySite\MyBundle\Namer\Namer
        tags:
            - { name: namer }

notice that if you want to use MySite\MyBundle\Resources\config\services.yml instead of MySite\MyBundle\Resources\config\services.xml, you have to edit MySite\MyBundle\DependencyInjectionMySiteMyExtension.php in this way:

$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');

in MySite\MyBundle\Namer\Namer.php:

<?php

namespace MySite\MyBundle\Namer;

use Vich\UploaderBundle\Naming\NamerInterface;

/**
 * Namer class.
 */
class Namer implements NamerInterface
{
    /**
     * Creates a name for the file being uploaded.
     *
     * @param object $obj The object the upload is attached to.
     * @param string $field The name of the uploadable field to generate a name for.
     * @return string The file name.
     */
    function name($obj, $field)
    {
        $file = $obj->file;
        $extension = $file->getExtension();

        return uniqid('', true).'.'.$extension;
    }
}

got it!

All 15 comments

Hi, you can do something like this:

in MySite\MyBundle\Entity\Entity.php:

/**
 * @Assert\File(maxSize="20000000")
 * @Vich\UploadableField(mapping="media_file", fileNameProperty="filename")
 *
 * @var File $file
 */
public $file;

in app/config/config.yml:

vich_uploader:
    mappings:
        media_file:
            upload_dir: %kernel.root_dir%/../uploads/media
            delete_on_remove: true
            namer: namer.media_file

in MySite\MyBundle\Resources\config\services.yml:

services:
    namer.media_file:
        class: MySite\MyBundle\Namer\Namer
        tags:
            - { name: namer }

notice that if you want to use MySite\MyBundle\Resources\config\services.yml instead of MySite\MyBundle\Resources\config\services.xml, you have to edit MySite\MyBundle\DependencyInjectionMySiteMyExtension.php in this way:

$loader = new Loader\YamlFileLoader($container, new FileLocator(__DIR__.'/../Resources/config'));
$loader->load('services.yml');

in MySite\MyBundle\Namer\Namer.php:

<?php

namespace MySite\MyBundle\Namer;

use Vich\UploaderBundle\Naming\NamerInterface;

/**
 * Namer class.
 */
class Namer implements NamerInterface
{
    /**
     * Creates a name for the file being uploaded.
     *
     * @param object $obj The object the upload is attached to.
     * @param string $field The name of the uploadable field to generate a name for.
     * @return string The file name.
     */
    function name($obj, $field)
    {
        $file = $obj->file;
        $extension = $file->getExtension();

        return uniqid('', true).'.'.$extension;
    }
}

got it!

@doncandid did you solved ?

yes it's solved. thanks

I've been trying to repeat the Namer example on Symfony 2.0.16 with no success. My code is exactly the same as inmarelibero's but I get this notice message:

Notice: Undefined property: Acme\DemoBundle\Entity\Product::$file in /home/sfprojects/vichuploader/src/Acme/DemoBundle/Namer/Namer.php line 21

making reference to the line

$file = $obj->file;

so the logical movement is inspect the $obj object to see what it has, using print_r($obj). This is what I get:

Acme\DemoBundle\Entity\Product Object
(
    [id:protected] => 
    [image:protected] => Symfony\Component\HttpFoundation\File\UploadedFile Object
        (
            [test:Symfony\Component\HttpFoundation\File\UploadedFile:private] => 
            [originalName:Symfony\Component\HttpFoundation\File\UploadedFile:private] => 7794932098_10a55dc4ea_b.jpg
            [mimeType:Symfony\Component\HttpFoundation\File\UploadedFile:private] => image/jpeg
            [size:Symfony\Component\HttpFoundation\File\UploadedFile:private] => 269071
            [error:Symfony\Component\HttpFoundation\File\UploadedFile:private] => 0
            [pathName:SplFileInfo:private] => /tmp/phpNRJRuk
            [fileName:SplFileInfo:private] => phpNRJRuk
        )

    [imageName:protected] => pop-rocker
)

No file property in the $obj object. Now if I use the image property (which is a property is my entity class), obviously it will lead to an error message because is a protected property.

Fatal error: Cannot access protected property Acme\DemoBundle\Entity\Product::$image in /home/sfprojects/vichuploader/src/Acme/DemoBundle/Namer/Namer.php on line 21

I know I''m missing something quite obvious here, but I don't know what it is. Do I have to extend my entity class in the Namer? It doesn't make sense (and it doesn't works anyway).

I knew I was missing something from the very beggining: I was declaring $image as protected instead public in the entity class, that's why it could not be accessed from the Namer class:

/**
 * @Assert\File(
 *     maxSize="1M",
 *     mimeTypes={"image/png", "image/jpeg", "image/pjpeg"}
 * )
 * @Vich\UploadableField(mapping="product_image", fileNameProperty="imageName")
 *
 * @var File $image
 */
protected $image; // WRONG! this attribute could not be accessed from non-child classes

But I got into another unsuspected error (no reported, by the way). the method getExtension() doesn't work at all. Diving into the Symfony code, looking for that method, I found this:

/**
 * Returns the extension of the file.
 *
 * \SplFileInfo::getExtension() is not available before PHP 5.3.6
 *
 * @return string The extension
 *
 * @api
 */
public function getExtension()
{
    return pathinfo($this->getBasename(), PATHINFO_EXTENSION);
}

And it just happend that libapache2-mod-php5 is in the 5.3.5-1ubuntu7.10 version, so getExtension() is available but it won't work. But wait a minute! I still have the guessExtension() method!

function name($obj, $field)
{
    $file = $obj->image;
    $extension = $file->guessExtension();

    return uniqid('', true).'.'.$extension;
}

And voil脿, finally it works!

Hope be useful for someone.

grat thx all now work

only not understand how to use namer for folder...

now i have this error...
You have requested a non-existent service "namer.property_image".
?

You have requested a non-existent service

That's because you're missing some DIC configuration. I can't debug this without reading looking at all your code but you should be able to fix this reading again the documentation and having a double check on your config.

only not understand how to use namer for folder...

For directory you should implement a DirectoryNamer, the login is similar to the FileNamer. The doc explains how to do that, have a look at it and let me know which parts aren't clear.

hi.. I follow @doncandid said and get this error.. any suggestion? thanks
Compile Error: Declaration of AdminBundle\Service\Namer\Namer::name() must be compatible with Vich\UploaderBundle\Naming\NamerInterface::name($object, Vich\UploaderBundle\Mapping\PropertyMapping $mapping)

@sokphea-chea. I think what you're missing is the propertymapping.

use Vich\UploaderBundle\Naming\NamerInterface;
use Vich\UploaderBundle\Mapping\PropertyMapping;

class FileNamer implements NamerInterface
{
    /**
     * Creates a name for the file being uploaded
     *
     * @param object $obj The object the upload is attached to
     * @param string $field The name of the uploadable field to generate a name for
     *
     * @return string The file name
     */
    public function name($object, PropertyMapping $mapping)
    {
        $file = $object->file;
        $extension = $file->getExtension();

        return uniqid('', true).'.'.$extension;
    }

You guys should put all this useful info into the documentation. It took me through many posts to get here and find proper configuration.

@jesusmartinez feel free to propose a PR to integrate documentation

Have spent a few hours on this - I'm guessing I'm missing something obvious. Happened when I went from 1.7.1 to 1.8.3. I'm getting same error as above, but the fix is eluding me:

Compile Error: Declaration of RC\RosterBundle\File\UserPhotoNamer::name($user, Vich\UploaderBundle\Mapping\PropertyMapping $mapping) must be compatible with Vich\UploaderBu ndle\Naming\NamerInterface::name($object, Vich\UploaderBundle\Mapping\PropertyMapping $mapping): string

In my bundle, the config code is:

    rc.user_photo.namer:
        class: RC\RosterBundle\File\UserPhotoNamer

In the app config.yml, I have:

vich_uploader:
    db_driver: orm
    mappings:
        user_photo:
            uri_prefix: /uploads/user_photos
            upload_destination: %kernel.root_dir%/../web/uploads/user_photos
            namer: 
                service: vich_uploader.namer_origname
            inject_on_load: false
            delete_on_remove: false

Finally, the class that is the cause of all this:

<?php

namespace RC\RosterBundle\File;

use Vich\UploaderBundle\Mapping\PropertyMapping;
use Vich\UploaderBundle\Naming\NamerInterface;

class UserPhotoNamer implements NamerInterface
{
    /**
     * Creates a name for the file being uploaded.
     *
     * @param  object          $obj     The object the upload is attached to.
     * @param  PropertyMapping $mapping The mapping to use to manipulate the given object.
     * @return string          The file name.
     */
    public function name($user, PropertyMapping $mapping)
    {
        $name = '';

        $name .= $user->getClient()->getId().'_';

        $name .= $user->getId().'_';

        $name .= date('YmdHi');

        $name .= '.'.$user->getPhoto()->guessExtension();

        return $name;
    }
}

Any ideas? This is the only thing stopping me from pulling this app from 2.8 up to 3.4...

OK - solved the previous one by looking at the existing code - I was missing the ': string' after the function definition.... hope this helps someone else.

This saved me

class FileNamer implements NamerInterface
{
public function name($object, PropertyMapping $mapping): string
{
$fileType = ucfirst($mapping->getFilePropertyName());
$functionName = 'get' . $fileType;
list($type, $extension) = explode('/', $object->{$functionName}()->getMimeType());
return uniqid('', true).'.'.$extension;
}
}

Was this page helpful?
0 / 5 - 0 ratings

Related issues

ngilain picture ngilain  路  5Comments

eved42 picture eved42  路  7Comments

andrea-daru picture andrea-daru  路  3Comments

fleskalebas picture fleskalebas  路  6Comments

jcg678 picture jcg678  路  6Comments