如何让 Sonata Media Bundle 在单独的文件夹中生成图片 [英] How to get Sonata Media Bundle to generate pictures in separate folders

查看:22
本文介绍了如何让 Sonata Media Bundle 在单独的文件夹中生成图片的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了一个问题,我需要 Sonata Media Bundle 才能将图片上传到不同的文件夹.我想要达到的是生成如下的图片结构:如果图片的 ID 为 1234567,则原始图片将放入文件夹:/web/uploads/1234/567/original"并且所有生成的缩略图/大小将类似于:/web/uploads/1234/567/100x130"和/web/uploads/1234/567/200x100",具体取决于生成的大小.

I'm struggling with a problem that I need Sonata Media Bundle to upload pictures to different folders. What I'm trying to reach is to generate a picture structure as the following: if the picture has an ID for 1234567 the original image will be put into folder: "/web/uploads/1234/567/original' And all the generated thumbnails/sizes will be like: "/web/uploads/1234/567/100x130" and "/web/uploads/1234/567/200x100" depending on the generated size.

此文件夹结构是否可以在 Sonata Media Bundle 中生成,如果可以,如何生成?

Is this folder structure generation possible in Sonata Media Bundle and if yes, how?

感谢您的回答.约瑟夫

推荐答案

我们为这个问题制定了一个解决方法":

We worked out a "workaround" for this problem:

基本上我们所做的是我们创建了自己的生成器、提供器和调整器来满足我们的需求,然后将其注入到媒体包中.生成器实现了生成器接口,构造器只有一个参数($this->firstLevel = 1000;).比:

Basically what we have done is that we created our own Generator, Provider and Resizer to match our needs and than injected it back to the Media Bundle. The generator implements Generator Interface, the constructor only has one argument ($this->firstLevel = 1000;). Than:

public function generatePath(MediaInterface $media)
{
    $rep_first_level = (int) ($media->getId() / $this->firstLevel);
    $rep_second_level = (int) ($media->getId() % $this->firstLevel);

    return sprintf('%s/%04s/%03s', $media->getContext(), $rep_first_level, $rep_second_level);
}

这将为 ID 为1234567"的图像以首选方式/web/uploads/1234/567"创建子目录.

This will create the sub directories in the preferred way "/web/uploads/1234/567" for image with ID "1234567".

我们的提供者扩展了 ImageProvider 并且只有 1 个实例:

Our provider extends ImageProvider and has only 1 instances:

protected function generateReferenceName(MediaInterface $media)
{
    $metadata = $media->getProviderMetadata();
    $fileName = $metadata['filename'];
    $temp = explode('.', $fileName);
    $name = $temp[0];
    return '/origos/' . $name . '.' . $media->getBinaryContent()->getExtension();
}

我们的 Resizer 类将扩展 squareResizer.这已更改为能够通过裁剪图像生成精确尺寸(100x100 和 190x100)的图片(缩略图).为此,我们创建了一个新的 resizer,它实现了 ResizerInterface:

Our Resizer class will extend squareResizer. This was changed to be able to generate pictures (thumbnails) the exact size (100x100 and 190x100 also) by cropping the image. For this we created a new resizer which implements ResizerInterface:

<?php

namespace Sita\<YourBundle>\Resizer;

use Imagine\Image\ImagineInterface;
use Imagine\Image\Box;
use Imagine\Image\Point;
use Gaufrette\File;
use Sonata\MediaBundle\Model\MediaInterface;
use Sonata\MediaBundle\Metadata\MetadataBuilderInterface;
use Sonata\MediaBundle\Resizer\ResizerInterface;

class <YourResizer> implements ResizerInterface
{
    /**
     * ImagineInterface
     */
    protected $adapter;

    /**
     * string
     */
    protected $mode;

    /**
     * @param ImagineInterface $adapter
     * @param string $mode
     * @param MetadataBuilderInterface $metadata
     */
    public function __construct(ImagineInterface $adapter, $mode, MetadataBuilderInterface $metadata)
    {
        $this->adapter = $adapter;
        $this->mode    = $mode;
        $this->metadata = $metadata;
    }

    /**
     * {@inheritdoc}
     */
    public function resize(MediaInterface $media, File $in, File $out, $format, array $settings)
    {
        if (!isset($settings['width'])) {
            throw new \RuntimeException(sprintf('Width parameter is missing in context "%s" for provider "%s"', $media->getContext(), $media->getProviderName()));
        }

        $image = $this->adapter->load($in->getContent());
        $size  = $media->getBox();

        if (null != $settings['height']) {
            $ratioWidth = $size->getWidth() / $settings['width'];
            $ratioHeight = $size->getHeight() / $settings['height'];
            $ratio = $ratioHeight > $ratioWidth ? $ratioWidth : $ratioHeight;

            $point = new Point(($size->getWidth() - $settings['width'] * $ratio) / 2, ($size->getHeight() - $settings['height'] * $ratio) / 2);

            $image->crop($point, new Box($settings['width'] * $ratio, $settings['height'] * $ratio));
            $size = $image->getSize();
        }

        $settings['height'] = (int) ($settings['width'] * $size->getHeight() / $size->getWidth());

        if ($settings['height'] < $size->getHeight() && $settings['width'] < $size->getWidth()) {
            $content = $image
                ->thumbnail(new Box($settings['width'], $settings['height']), $this->mode)
                ->get($format, array('quality' => $settings['quality']));
        } else {
            $content = $image->get($format, array('quality' => $settings['quality']));
        }

        $out->setContent($content, $this->metadata->get($media, $out->getName()));
    }

    /**
     * {@inheritdoc}
     */
    public function getBox(MediaInterface $media, array $settings)
    {
        $size = $media->getBox();

        if (null != $settings['height']) {

            if ($size->getHeight() > $size->getWidth()) {
                $higher = $size->getHeight();
                $lower  = $size->getWidth();
            } else {
                $higher = $size->getWidth();
                $lower  = $size->getHeight();
            }

            if ($higher - $lower > 0) {
                return new Box($lower, $lower);
            }
        }

        $settings['height'] = (int) ($settings['width'] * $size->getHeight() / $size->getWidth());

        if ($settings['height'] < $size->getHeight() && $settings['width'] < $size->getWidth()) {
            return new Box($settings['width'], $settings['height']);
        }

        return $size;
    }
}

进行依赖注入有点挑战,但结果如下:

It was a bit challenge to do the dependency injection, but here is the result:

服务:

    parameters:
    <yourBundle>.generator.<project>_generator.class: Sita\<yourBundle>\Generator\<project>Generator
    <yourBundle>.resizer.<project>_resizer.class: Sita\<yourBundle>\Resizer\<project>Resizer
    <yourBundle>.thumbnail.<project>_thumbnail.class: Sita\<yourBundle>\Thumbnail\<project>Thumbnail
    <yourBundle>.provider.<project>_provider.class: Sita\<yourBundle>\Provider\<project>Provider
services:
    <yourBundle>.generator.<project>_generator:
        class: %<yourBundle>.generator.<project>_generator.class%
        arguments:
            - ~

    <yourBundle>.resizer.<project>_resizer:
        class: %<yourBundle>.resizer.<project>_resizer.class%
        arguments:
            - @sonata.media.adapter.image.gd
            - %sonata.media.resizer.square.adapter.mode%
            - @sonata.media.metadata.proxy

    <yourBundle>.thumbnail.<project>_thumbnail:
        class: %<yourBundle>.thumbnail.<project>_thumbnail.class%
        arguments:
            - %sonata.media.thumbnail.format.default%

    <yourBundle>.provider.<project>:
        class: %<yourBundle>.provider.<project>_provider.class%
        arguments:
            - <yourBundle>.provider.<project>
            - ~
            - ~
            - ~
            - @<yourBundle>.thumbnail.<project>_thumbnail
            - ~
            - ~
            - ~
            - @sonata.media.metadata.proxy
        calls:
            - [setResizer, ["@<yourBundle>.resizer.<project>_resizer"]]
        tags:
            - { name: sonata.media.provider }

配置:

<?php

namespace <yourBundle>\DependencyInjection;

use Symfony\Component\Config\Definition\Builder\TreeBuilder;
use Symfony\Component\Config\Definition\ConfigurationInterface;

/**
 * This is the class that validates and merges configuration from your app/config files
 *
 * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html#cookbook-bundles-extension-config-class}
 */
class Configuration implements ConfigurationInterface
{
    /**
     * {@inheritdoc}
     */
    public function getConfigTreeBuilder()
    {
        $treeBuilder = new TreeBuilder();
        $rootNode = $treeBuilder->root('<yourBundle>');

        $rootNode
            ->children()
                ->arrayNode('providers')
                    ->addDefaultsIfNotSet()
                    ->children()
                        ->arrayNode('<project>')
                            ->addDefaultsIfNotSet()
                            ->children()
                                ->scalarNode('service')->defaultValue('<yourBundle>.provider.<project>')->end()
                                ->scalarNode('resizer')->defaultValue('<yourBundle>.resizer.<project>_resizer')->end()
                                ->scalarNode('filesystem')->defaultValue('sonata.media.filesystem.local')->end()
                                ->scalarNode('cdn')->defaultValue('sonata.media.cdn.server')->end()
                                ->scalarNode('generator')->defaultValue('<yourBundle>.generator.<project>_generator')->end()
                                ->scalarNode('thumbnail')->defaultValue('<yourBundle>.thumbnail.<project>_thumbnail')->end()
                                ->scalarNode('adapter')->defaultValue('sonata.media.adapter.image.gd')->end()
                                ->arrayNode('allowed_extensions')
                                    ->prototype('scalar')->end()
                                    ->defaultValue(array('jpg', 'png', 'jpeg'))
                                ->end()
                                ->arrayNode('allowed_mime_types')
                                    ->prototype('scalar')->end()
                                    ->defaultValue(array(
                                        'image/pjpeg',
                                        'image/jpeg',
                                        'image/png',
                                        'image/x-png',
                                    ))
                                ->end()
                            ->end()
                        ->end()
                    ->end()
                ->end()
            ->end();

        return $treeBuilder;
    }
}

和扩展:

<?php

namespace <yourBundle>\DependencyInjection;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
use Symfony\Component\DependencyInjection\Loader;

/**
 * This is the class that loads and manages your bundle configuration
 *
 * To learn more see {@link http://symfony.com/doc/current/cookbook/bundles/extension.html}
 */
class <yourBundle>Extension extends Extension
{
    /**
     * {@inheritdoc}
     */
    public function load(array $configs, ContainerBuilder $container)
    {
        $configuration = new Configuration();
        $config = $this->processConfiguration($configuration, $configs);

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

        $container->getDefinition('<yourBundle>.provider.<project>')
            ->replaceArgument(1, new Reference($config['providers']['<project>']['filesystem']))
            ->replaceArgument(2, new Reference($config['providers']['<project>']['cdn']))
            ->replaceArgument(3, new Reference($config['providers']['<project>']['generator']))
            ->replaceArgument(4, new Reference($config['providers']['<project>']['thumbnail']))
            ->replaceArgument(5, array_map('strtolower', $config['providers']['<project>']['allowed_extensions']))
            ->replaceArgument(6, $config['providers']['<project>']['allowed_mime_types'])
            ->replaceArgument(7, new Reference($config['providers']['<project>']['adapter']))
        ;

    }
}

最后是来自 symfony 配置文件的 config.yml:

And finally the config.yml from the symfony config file:

sonata_media:
    # if you don't use default namespace configuration
    #class:
    #    media: MyVendor\MediaBundle\Entity\Media
    #    gallery: MyVendor\MediaBundle\Entity\Gallery
    #    gallery_has_media: MyVendor\MediaBundle\Entity\GalleryHasMedia
    default_context: default
    db_driver: doctrine_orm # or doctrine_mongodb, doctrine_phpcr
    contexts:
        default:  # the default context is mandatory
            providers:
                - <yourBundle>.provider.<project>

            formats:
                small: { width: 100 , quality: 70}
                big:   { width: 500 , quality: 70}
                100x100: { width: 100 , height: 100 , quality: 100 }
                126x190: { width: 126 , height: 190 , quality: 100 }
                190x126: { width: 190 , height: 126 , quality: 100 }
                190x56: { width: 190 , height: 56 , quality: 100 }

    cdn:
        server:
            path: /uploads/media # http://media.sonata-project.org/

    filesystem:
        local:
            directory:  %kernel.root_dir%/../web/uploads/media
            create:     true

<yourBundle>:

我知道这不是最清晰的工作,但它确实有效,现在很好:)

I know this is not the clearest work, but it does the job, good for now :)

这篇关于如何让 Sonata Media Bundle 在单独的文件夹中生成图片的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆