2014-11-21 80 views
2

我正在努力解決需要Sonata Media Bundle將圖片上傳到不同文件夾的問題。我試圖達到的是生成一個圖片結構如下: 如果圖片的ID爲1234567原始圖像將被放入文件夾:「/ web/uploads/1234/567/original' 而所有根據生成的大小,生成的縮略圖/大小將類似於:「/ web/uploads/1234/567/100x130」和「/ web/uploads/1234/567/200x100」。 ?在索納塔媒體包,如果是,如何如何獲取Sonata Media Bundle在單獨的文件夾中生成圖片

感謝您的答案 約瑟夫

回答

4

我們制定出了「解決辦法」針對此問題:

基本上我們所做的就是我們創建了我們自己的Generator,Provider和Resizer來滿足我們的需求,並將其注入到Media Bundle中。 生成器實現Generator接口,構造函數只有一個參數($ this-> firstLevel = 1000;)。比:

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); 
} 

這將在「/網絡/上傳/567分之1234」 ID爲「1234567」的形象的首選方式創建子目錄。

我們的供應商擴展ImageProvider和只有1個實例:

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

我們的調整器類將擴展squareResizer。這被改變成能夠通過裁剪圖像來生成確切尺寸(100x100和190x100)的圖片(縮略圖)。爲此,我們創建了一個實現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; 
    } 
} 

這是一個有點挑戰做了依賴注入,但這裏是結果:

服務:

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; 
    } 
} 

and Extension:

<?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:

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>: 

我知道這是不是最清晰的工作,但它現在的工作,好:)

2
//config.yml 
sonata_media: 
    contexts: 
     default: # the default context is mandatory 
      providers: 
       - sonata.media.provider.image 

      formats: 
       small: { width: 100 , quality: 70} 
       big: { width: 500 , quality: 70} 

//Controller action: 
$media = //$entity->getMedia(); Media entity 
$mediaProvider = $this->get('sonata.media.provider.image'); 
$format = $mediaProvider->getFormatName($media, 'big'); 
$imgPath = $mediaProvider->generatePublicUrl($media, $format); 
相關問題