SonataMediaBundle - 如何上传图片? [英] SonataMediaBundle - how to upload images?

查看:24
本文介绍了SonataMediaBundle - 如何上传图片?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

标题可能应该是:SonataMediaBundle - 缺少的 howto 在哪里?".

我已经用 sonataAdminBundle 和 SonataDoctrineORMAdminBundle(以及其他一些)制作了一些管理后端,大多数事情都按预期工作,但我将文件上传和处理留待以后处理,因为我想这可能有多难?".

长话短说 - 是否有任何关于最简单事物的文档 - 即,将图像附加到帖子或条目,如何配置奏鸣曲管理类,如何以编辑形式显示图像缩略图等?

文档的第一页 以您可以访问您的管理仪表板"结尾,好像我可以期待那里有一些相关的变化,也许媒体管理器启动并运行,或者其他什么.但事实并非如此.

下一页简要介绍 heplers,然后是另一页,介绍相当复杂的 vimeo 提供商案例研究.

我在整个网络上进行了搜索,我能想到的最好的方法是带有 ajax 弹出窗口的上传字段和上传文件列表.

在我的管理课程中,我有:

受保护的函数 configureFormFields(FormMapper $formMapper){$formMapper->with('一般')->add('title')->add('body')->add('类别')-> 结束()->with('媒体')->add('images', 'sonata_type_model')

在我的新闻类中:

/*** @ORM\ManyToMany(targetEntity="Application\Sonata\MediaBundle\Entity\Media")*/公共 $images;

并且所有 yaml 配置和路由都已实现.

结果是:致命错误:在尝试上传图像时调用[some-entity].php中非对象的成员函数add(),以及可选的图像列表id 带有加"号(我猜是sonata_type_model 字段).

我被卡住了.我能够在一两个小时内在普通的 sf2 中创建媒体管理器",但这是另一个项目,将当前的项目重写为这种模式意味着从头开始".那么 - 为了使 sonataMediaBundle 和 sonataAdminBundle 一起按预期工作,该怎么做?

<小时>

这是我所做的:

我的新闻类(或任何其他需要图片上传的类):

documents = new ArrayCollection();}[...]/*** 添加文件** @param Festus\SiteBundle\Entity\Document $documents*/公共函数 addDocument(\Festus\SiteBundle\Entity\Document $document){$this->documents[] = $document;}/*** 设置文档** @param Festus\SiteBundle\Entity\Document $documents*/公共函数 setDocument(\Festus\SiteBundle\Entity\Document $document){foreach ($this->documents as $doc) {$this->documents->removeElement($doc);}$this->documents[] = $document;}/*** 获取文件** @return Doctrine\Common\Collections\Collection*/公共函数 getDocuments(){返回 $this->documents;}//设置器,获取器...

我的文档类(需要更改表名,因为我在某些服务器上遇到了保留字的问题):

createdAt = new \DateTime();}公共函数 getAbsolutePath(){返回 null === $this->path ?null : $this->getUploadRootDir().'/'.$this->path;}公共函数 getWebPath(){返回 null === $this->path ?null : $this->getUploadDir().'/'.$this->path;}受保护的函数 getUploadRootDir(){//上传文档保存的绝对目录路径返回 __DIR__.'/../../../../web/'.$this->getUploadDir();}受保护的函数 getUploadDir(){//去掉 __DIR__ 以便在视图中显示上传的文档/图像时不会出错.返回上传/文件";}/*** @ORM\PrePersist()* @ORM\PreUpdate()*/公共函数 preUpload(){if (null !== $this->theFile) {//var_dump($this);//做任何你想做的事情来生成一个唯一的名字$this->path = uniqid().'.'.$this->theFile->guessExtension();}}/*** @ORM\PostPersist()* @ORM\PostUpdate()*/公共函数上传(){if (null === $this->theFile) {返回;}//如果移动文件时出现错误,则会出现异常//被 move() 自动抛出.这将适当地防止//实体在出错时被持久化到数据库$this->theFile->move($this->getUploadRootDir(), $this->path);取消设置($this->theFile);}/*** @ORM\PostRemove()*/公共函数 removeUpload(){if ($file = $this->getAbsolutePath()) {取消链接($文件);}}公共函数 __toString(){返回文档";}/*** 获取身份证** @return 整数*/公共函数 getId(){返回 $this->id;}/*** 设置名称** @param 字符串 $name*/公共函数 setName($name){$this->name = $name;}/*** 获取名称** @return 字符串*/公共函数 getName(){返回 $this->name;}/*** 设置文件** @param 字符串 $file*/公共函数 setTheFile($file){$this->theFile = $file;}/*** 获取文件** @return 字符串*/公共函数 getTheFile(){返回 $this->theFile;}/*** 设置路径** @param 字符串 $path*/公共函数 setPath($path){$this->path = $path;}/*** 获取路径** @return 字符串*/公共函数 getPath(){返回 $this->path;}/*** 设置类型** @param 字符串 $type*/公共函数 setType($type){$this->type = $type;}/*** 获取类型** @return 字符串*/公共函数 getType(){返回 $this->type;}/*** 获取一个表示用户创建日期和时间的对象.** @return DateTime 一个 DateTime 对象*/公共函数 getCreatedAt(){返回 $this->createdAt;}/*** 获取一个表示用户创建日期和时间的对象.** @return DateTime 一个 DateTime 对象*/公共函数 getCreatedAtString(){return date_format($this->createdAt, "Y-m-d");}/*** 设置 createdAt** @param datetime $createdAt*/公共函数 setCreatedAt($createdAt){$this->createdAt = $createdAt;}}

如您所见,大部分内容都是从 symfony2 教程中复制而来的.

现在,对于控制器:

setFormTheme(array_merge($this->getFormTheme(),数组('FestusSiteBundle:Form:image_form.html.twig')));}受保护的函数 configureFormFields(FormMapper $formMapper){$formMapper->with('ogólne')->add('title', NULL, array('label' => 'tytuł:'))->add('body', NULL, array('label' => 'treść:', 'attr' => array('类' =>'tinymce', '数据主题' =>'简单的')))->add('categories', NULL, array('label' => 'kategorie:'))-> 结束()->with('媒体')->add('文件名', '文本', 数组(标签" =>'tytuł orazka:','property_path' =>错误的,'必需' =>错误的))->add('theFile', 'file', array(标签" =>'wybierz plik','property_path' =>错误的,'必需' =>错误的))-> 结束();}受保护的函数 configureDatagridFilters(DatagridMapper $datagridMapper){$datagridMapper->add('title')->add('body');}受保护的函数 configureListFields(ListMapper $listMapper){$listMapper->addIdentifier('title')->add('类别')->add('_action', 'actions', array('动作' =>大批('视图' =>大批(),'编辑' =>大批(),)));}受保护的函数 configureShowFields(ShowMapper $showMapper){$showMapper->add('title')->add('body');}公共函数验证(ErrorElement $errorElement, $object){$错误元素->with('title')->assertMinLength(array('limit' => 2))-> 结束();}公共函数 prePersist($news) {$this->saveFile($news);}公共函数 preUpdate($news) {$this->saveFile($news);}公共函数 saveFile($news) {$request = Request::createFromGlobals();$requestData = current($request->request->all());$filesData = current($request->files->all());$document = new Document();$theFile = $filesData['theFile'];$name = $requestData['fileName'];if($theFile != NULL){$document->setName($name);$document->setTheFile($theFile);$news->setDocument($document);}}}

我的基础包类扩展了管理包类,我可以覆盖模板:

SomeSiteBundle/resources/views/CRUD/base_edit.html.twig 中,我稍微改变了模板,让用户看到当前设置的图片:

{% for field_name in form_group.fields %}{% 如果定义了 admin.formfielddescriptions[field_name] %}{% if field_name == 'fileName' %}<h5 style="margin-left: 40px">Obecny obrazek:</h5>{% 如果定义了 object.documents[0] %}<img style="margin: 0 0 0 40px; border: 1px dotted #ccc" src="{{ asset(object.documents[0].webPath) }}"/>{% 别的 %}<div style="margin-left: 40px">brak</div>{% 万一 %}<hr><h5 style="margin-left: 40px">Wczytaj nowy:</h5>{% 万一 %}{{ form_row(form[field_name])}}{% 万一 %}{% 结束为 %}

现在我每条新闻只使用一张图片(特色图片"),无论如何这有点矫枉过正,因为我使用的是带有 jbimages 插件的 tinyMCE,所以无论如何我都可以将图片放入新闻正文中.要使 jbimages 插件正常工作,您必须设置一些 tinyMCE 选项:

------ 这部分处理tinymce和tinymce bundle和tinymce plugin: ---------

$config['img_path'] = '/web/uploads/documents';(或任何其他适合您的路径)在 web/bundles/stfalcontinymce/vendor/tiny_mce/插件/jbimages/config.php.(当然,您需要先安装 stfalcon tinymce 包).然后我编辑了一些 web/bundles/stfalcontinymce/js/init.jquery.js 以允许读取 config.yml 中的更多选项:

themeOptions.script_url = options.jquery_script_url;//矿:themeOptions.convert_urls = options.convert_urls;themeOptions.relative_urls = options.relative_urls;themeOptions.remove_script_host = options.remove_script_host;themeOptions.document_base_url = options.document_base_url;

最后在 config.yml 中:

<代码>[...]stfalcon_tinymce:include_jquery: 真tinymce_jquery: 真textarea_class: "tinymce"relative_urls : 假convert_urls : 假remove_script_host : 假document_base_url : "http://somesite.home.pl/web/"主题:[...]

仅此而已,AFAIR.希望这会有所帮助;-)

解决方案

也许您可以在以下位置找到问题的答案:/admin/sonata/media/media/create?provider=sonata.media.provider.image&context=default

我对您的其他解决方案感兴趣,请发布代码.谢谢

Probably should be titled: "SonataMediaBundle - where's the missing howto?".

I've made some admin backend with sonataAdminBundle and sonataDoctrineORMAdminBundle (and some other), most of the things worked as expected, but I left file upload and handling for later, because I thought "how hard that possibly can be?".

To make long story short - is there ANY documentation about simplest of things - i.e. having images attached to a post or entry, how to configure sonata admin class, how to display image thumbs in edit form, etc.?

First page of documentation ends with "you can visit your admin dashboard" as if I could expect some relevant changes there, maybe media manager up and running, or something. But this is not the case.

Next page deals with heplers briefly, and then another page with fairly complicated vimeo provider case study.

I've searched all over the web and best I could come up with, was upload field with ajax popup, and list of uploaded files.

In my admin class I've got:

protected function configureFormFields(FormMapper $formMapper)
{
    $formMapper
    ->with('general')
        ->add('title')
        ->add('body')
        ->add('categories')
        ->end()
    ->with('media')
        ->add('images', 'sonata_type_model')

in my News class:

/**
 * @ORM\ManyToMany(targetEntity="Application\Sonata\MediaBundle\Entity\Media")
 */
public $images; 

and all the yaml configs and routings are implemented.

The result is: Fatal error: Call to a member function add() on a non-object in [some-entity].php when trying to upload an image, and selectable list of image id's with "plus" sign (sonata_type_model field I guess).

I'm stuck. I was able to create media "manager" just in plain sf2 in an hour or two, but it was another project and rewriting current one to this pattern means starting "from scratch". So - what to do in order to make sonataMediaBundle together with sonataAdminBundle work as expected?


EDIT: here's what I did instead:

My news class (or any other which needs image upload):

<?php

namespace Some\SiteBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;


/**
 * Some\SiteBundle\Entity\News
 *
 * @ORM\Table(name="news")
 */
class News
{
    /**
     * @var integer $id
     *
     * @ORM\Column(name="id", type="integer")
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;      


    //some stuff...

  /**
    * @var Document documents
     * @ORM\ManyToMany(targetEntity="Document", cascade={"persist", "remove", "delete"} )
     **/
    protected $documents;


    public function __construct()
  {
    $this->documents = new ArrayCollection();

  }

[...]

    /**
     * Add documents
     *
     * @param Festus\SiteBundle\Entity\Document $documents
     */
    public function addDocument(\Festus\SiteBundle\Entity\Document $document)
    {
        $this->documents[] = $document;
    }

    /**
     * set document
     *
     * @param Festus\SiteBundle\Entity\Document $documents
     */
    public function setDocument(\Festus\SiteBundle\Entity\Document $document)
    {
        foreach ($this->documents as $doc) {
            $this->documents->removeElement($doc);
        }
        $this->documents[] = $document;
    }

    /**
     * Get documents
     *
     * @return Doctrine\Common\Collections\Collection 
     */
    public function getDocuments()
    {
        return $this->documents;
    }



    // setters, getters...

My document class (needed to change the name of the table, because I ran into issues with reserved words on some servers):

<?php  

namespace Some\SiteBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
use Symfony\Component\Validator\Constraints as Assert;

/**
 * Some\SiteBundle\Entity\Document
 *
 * @ORM\Table(name="docs")
 * @ORM\Entity
 * @ORM\HasLifecycleCallbacks
 */
class Document
{
    /**
     * @ORM\Id
     * @ORM\Column(type="integer")
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    private $id;

    /**
     * @ORM\Column(type="string", length=255)
     * @Assert\NotBlank
     */
    private $name;

    /**
     * @ORM\Column(type="string", length=255, nullable=true)
     */
    private $path;

    /**
     * @Assert\File(maxSize="6000000")
     */
    private $theFile;


    /**
     * @ORM\Column(type="datetime", name="created_at")
     * 
     * @var DateTime $createdAt
     */
    protected $createdAt;


    /**
     * @ORM\Column(type="integer")
     */
    private $type = 1;


    public function __construct()
      {
        $this->createdAt = new \DateTime();
      }

    public function getAbsolutePath()
    {
        return null === $this->path ? null : $this->getUploadRootDir().'/'.$this->path;
    }

    public function getWebPath()
    {
        return null === $this->path ? null : $this->getUploadDir().'/'.$this->path;
    }

    protected function getUploadRootDir()
    {
        // the absolute directory path where uploaded documents should be saved
        return __DIR__.'/../../../../web/'.$this->getUploadDir();
    }

    protected function getUploadDir()
    {
        // get rid of the __DIR__ so it doesn't screw when displaying uploaded doc/image in the view.
        return 'uploads/documents';
    }   

    /**
     * @ORM\PrePersist()
     * @ORM\PreUpdate()
     */
    public function preUpload()
    {
        if (null !== $this->theFile) {
            //var_dump($this);
            // do whatever you want to generate a unique name
            $this->path = uniqid().'.'.$this->theFile->guessExtension();
        }
    }

    /**
     * @ORM\PostPersist()
     * @ORM\PostUpdate()
     */
    public function upload()
    {
        if (null === $this->theFile) {
            return;
        }

        // if there is an error when moving the file, an exception will
        // be automatically thrown by move(). This will properly prevent
        // the entity from being persisted to the database on error
        $this->theFile->move($this->getUploadRootDir(), $this->path);

        unset($this->theFile);
    }

    /**
     * @ORM\PostRemove()
     */
    public function removeUpload()
    {
        if ($file = $this->getAbsolutePath()) {
            unlink($file);
        }
    }

    public function __toString()
      {
        return 'Document';
      }


    /**
     * Get id
     *
     * @return integer 
     */
    public function getId()
    {
        return $this->id;
    }

    /**
     * Set name
     *
     * @param string $name
     */
    public function setName($name)
    {
        $this->name = $name;
    }

    /**
     * Get name
     *
     * @return string 
     */
    public function getName()
    {
        return $this->name;
    }

    /**
     * Set file
     *
     * @param string $file
     */
    public function setTheFile($file)
    {
        $this->theFile = $file;
    }

        /**
     * Get file
     *
     * @return string 
     */
    public function getTheFile()
    {
        return $this->theFile;
    }

    /**
     * Set path
     *
     * @param string $path
     */
    public function setPath($path)
    {
        $this->path = $path;
    }

    /**
     * Get path
     *
     * @return string 
     */
    public function getPath()
    {
        return $this->path;
    }


    /**
     * Set type
     *
     * @param string $type
     */
    public function setType($type)
    {
        $this->type = $type;
    }

    /**
     * Get type
     *
     * @return string 
     */
    public function getType()
    {
        return $this->type;
    }


    /**
     * Gets an object representing the date and time the user was created.
     * 
     * @return DateTime A DateTime object
     */
    public function getCreatedAt()
    {
        return $this->createdAt;
    }


     /**
     * Gets an object representing the date and time the user was created.
     * 
     * @return DateTime A DateTime object
     */
    public function getCreatedAtString()
    {
        return date_format($this->createdAt, "Y-m-d");
    }


    /**
     * Set createdAt
     *
     * @param datetime $createdAt
     */
    public function setCreatedAt($createdAt)
    {
        $this->createdAt = $createdAt;
    }


}

As You can see, most of it is copied from symfony2 tutorial.

Now, for the controller:

<?php 

namespace Some\SiteBundle;

use Some\SiteBundle\Form\Type\ImageShowType;
use Some\SiteBundle\Entity\Document;
use Sonata\AdminBundle\Admin\Admin;
use Sonata\AdminBundle\Datagrid\ListMapper;
use Sonata\AdminBundle\Datagrid\DatagridMapper;
use Sonata\AdminBundle\Validator\ErrorElement;
use Sonata\AdminBundle\Form\FormMapper;
use Sonata\AdminBundle\Show\ShowMapper;
use Symfony\Component\HttpFoundation\File\File;
use Symfony\Component\HttpFoundation\Request;


class NewsAdmin extends Admin
{

    public function __construct($code, $class, $baseControllerName) {
        parent::__construct($code, $class, $baseControllerName);

        $this->setFormTheme(array_merge($this->getFormTheme(),
            array('FestusSiteBundle:Form:image_form.html.twig')
        ));
    }


    protected function configureFormFields(FormMapper $formMapper)
    {
        $formMapper
        ->with('ogólne')
            ->add('title', NULL, array('label' => 'tytuł:'))
                ->add('body', NULL, array('label' => 'treść:', 'attr' => array(
                    'class' => 'tinymce', 'data-theme' => 'simple')))
                ->add('categories', NULL, array('label' => 'kategorie:'))
        ->end()
        ->with('media')
            ->add('fileName', 'text', array(
                    "label" => 'tytuł obrazka:',
                    'property_path' => false,
                        'required' => false
                ))
            ->add('theFile', 'file', array(
                    "label" => 'wybierz plik',
                    'property_path' => false,
                        'required' => false
                ))
            ->end()
        ;
    }

    protected function configureDatagridFilters(DatagridMapper $datagridMapper)
    {
        $datagridMapper
            ->add('title')
            ->add('body')
        ;
    }

    protected function configureListFields(ListMapper $listMapper)
    {
        $listMapper
            ->addIdentifier('title')
            ->add('categories')

            ->add('_action', 'actions', array(
                'actions' => array(
                    'view' => array(),
                    'edit' => array(),
                )
            ))
        ;
    }

    protected function configureShowFields(ShowMapper $showMapper)
    {
        $showMapper->add('title')
            ->add('body');

    }

    public function validate(ErrorElement $errorElement, $object)
    {
        $errorElement
            ->with('title')
                ->assertMinLength(array('limit' => 2))
            ->end()
        ;
    }

    public function prePersist($news) {
        $this->saveFile($news);
      }

      public function preUpdate($news) {
        $this->saveFile($news);
      }

      public function saveFile($news) {
        $request = Request::createFromGlobals();
        $requestData = current($request->request->all());
        $filesData = current($request->files->all());
        $document = new Document();
        $theFile = $filesData['theFile'];
        $name = $requestData['fileName'];

        if($theFile != NULL){
            $document->setName($name);
            $document->setTheFile($theFile);
            $news->setDocument($document);
        }
      }
}

My base bundle class extends admin bundle class, co I could overwrite templates:

<?php

namespace Some\SiteBundle;

use Symfony\Component\HttpKernel\Bundle\Bundle;

class SomeSiteBundle extends Bundle
{

    public function getParent()
    {
        return 'SonataAdminBundle';
    }

}

And in SomeSiteBundle/resources/views/CRUD/base_edit.html.twig I've changed template a little bit to let user see currently set picture:

<div class="sonata-ba-collapsed-fields">                    
                    {% for field_name in form_group.fields %}
                        {% if admin.formfielddescriptions[field_name] is defined %}
                            {% if field_name == 'fileName' %}

                            <h5 style="margin-left: 40px">Obecny obrazek:</h5>
                            {% if object.documents[0] is defined %}
                                <img style="margin: 0 0 0 40px; border: 1px dotted #ccc" src="{{ asset(object.documents[0].webPath) }}" />
                                {% else %}
                                <div style="margin-left: 40px">brak</div>
                                {% endif %}
                                <hr><h5 style="margin-left: 40px">Wczytaj nowy:</h5>
                            {% endif %}
                            {{ form_row(form[field_name])}}
                        {% endif %}
                    {% endfor %}
                </div>

Right now I'm using only one picture per news ("featured picture") and it's a bit overkill anyway, because I'm using tinyMCE with jbimages plugin, so I can put images into news body anyway. To make jbimages plugin work right You've got to set some tinyMCE options though:

------ this part deals with tinymce and tinymce bundle and tinymce plugin: ---------

$config['img_path'] = '/web/uploads/documents'; (or any other path that suits You) in web/bundles/stfalcontinymce/vendor/tiny_mce/plugins/jbimages/config.php. (You need to install stfalcon tinymce bundle first, of course). Then I edited a bit web/bundles/stfalcontinymce/js/init.jquery.js to allow more options from config.yml to be read:

themeOptions.script_url = options.jquery_script_url;
            //mine:
            themeOptions.convert_urls = options.convert_urls;
            themeOptions.relative_urls = options.relative_urls;
            themeOptions.remove_script_host = options.remove_script_host;
            themeOptions.document_base_url = options.document_base_url;

And finally in config.yml:

[...]
stfalcon_tinymce:
    include_jquery: true
    tinymce_jquery: true
    textarea_class: "tinymce"
    relative_urls : false
    convert_urls : false
    remove_script_host : false
    document_base_url : "http://somesite.home.pl/web/"
    theme:
[...]

And that's all, AFAIR. Hope this helps ;-)

解决方案

Maybe you can find the answer to your question in the: /admin/sonata/media/media/create?provider=sonata.media.provider.image&context=default

I am interested to your other solution, please post code. Thanks

这篇关于SonataMediaBundle - 如何上传图片?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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