SonataMediaBundle - 如何上传图片?
Posted
技术标签:
【中文标题】SonataMediaBundle - 如何上传图片?【英文标题】:SonataMediaBundle - how to upload images? 【发布时间】:2012-07-16 14:35:39 【问题描述】:可能应该标题为:“SonataMediaBundle - 缺少的方法在哪里?”。
我已经使用 sonataAdminBundle 和 sonataDoctrineORMAdminBundle(以及其他一些)创建了一些管理后端,大多数事情都按预期工作,但我将文件上传和处理留到以后,因为我想“这可能有多难?” .
长话短说 - 是否有任何关于最简单事物的文档 - 即在帖子或条目上附加图像、如何配置奏鸣曲管理类、如何在编辑表单中显示图像缩略图等?
documentation 的第一页以“您可以访问您的管理仪表板”结尾,好像我可以预期那里会发生一些相关的变化,可能是媒体管理器启动并运行,或者其他什么。但事实并非如此。
下一页简要介绍了 heplers,然后是另一页包含相当复杂的 vimeo 提供程序案例研究。
我已经在整个网络上进行了搜索,我能想到的最好的方法是带有 ajax 弹出窗口的上传字段和上传文件的列表。
在我的管理课上我有:
protected function configureFormFields(FormMapper $formMapper)
$formMapper
->with('general')
->add('title')
->add('body')
->add('categories')
->end()
->with('media')
->add('images', 'sonata_type_model')
在我的新闻类中:
/**
* @ORM\ManyToMany(targetEntity="Application\Sonata\MediaBundle\Entity\Media")
*/
public $images;
所有的 yaml 配置和路由都已实现。
结果是:Fatal error: Call to a member function add() on a non-object in [some-entity].php
在尝试上传图像时,以及带有“加号”符号的可选图像 ID 列表(我猜是 sonata_type_model 字段)。
我被困住了。我能够在一两个小时内在普通的 sf2 中创建媒体“管理器”,但这是另一个项目,将当前项目重写为这种模式意味着“从头开始”。那么 - 为了让 sonataMediaBundle 和 sonataAdminBundle 按预期工作,该怎么做?
编辑:这就是我所做的:
我的新闻类(或任何其他需要上传图片的):
<?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...
我的文档类(需要更改表的名称,因为我在某些服务器上遇到了保留字的问题):
<?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;
如您所见,大部分内容是从 symfony2 教程中复制而来的。
现在,对于控制器:
<?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);
我的基础包类扩展了管理包类,因为我可以覆盖模板:
<?php
namespace Some\SiteBundle;
use Symfony\Component\HttpKernel\Bundle\Bundle;
class SomeSiteBundle extends Bundle
public function getParent()
return 'SonataAdminBundle';
在SomeSiteBundle/resources/views/CRUD/base_edit.html.twig
中,我稍微更改了模板以让用户看到当前设置的图片:
<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>
现在我每条新闻只使用一张图片(“特色图片”),无论如何这有点矫枉过正,因为我使用的是带有 jbimages 插件的 tinyMCE,所以无论如何我都可以将图片放入新闻正文中。要使 jbimages 插件正常工作,您必须设置一些 tinyMCE 选项:
-----这部分涉及tinymce和tinymce bundle和tinymce插件:---------
$config['img_path'] = '/web/uploads/documents';
(或任何其他适合您的路径)在web/bundles/stfalcontinymce/vendor/tiny_mce/plugins/jbimages/config.php
。 (当然,您需要先安装 stfalcon tinymce bundle)。然后我编辑了一点web/bundles/stfalcontinymce/js/init.jquery.js
以允许阅读来自config.yml
的更多选项:
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;
最后在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:
[...]
就是这样,AFAIR。希望这会有所帮助;-)
【问题讨论】:
好的,我现在决定完全放弃 mediabundle 并实现纯 sf2/doctrine 文件上传方案。如果有人感兴趣,我可以为我的课程发布相关的源代码。 我有兴趣,请发代码。谢谢。 【参考方案1】:也许您可以在以下位置找到问题的答案: /admin/sonata/media/media/create?provider=sonata.media.provider.image&context=default
我对您的其他解决方案感兴趣,请发布代码。谢谢
【讨论】:
【参考方案2】:考虑了在单独的服务器上强制执行文件存储的最佳做法。它会发送什么文件或文件的链接,您可以使用 Symfony byundle https://packagist.org/packages/avtonom/media-storage-client-bundle
if($file instanceof UploadedFile)
$this->get('avtonom.media_storage_client.manager')->sendFile($file, $clientName, $context);
【讨论】:
以上是关于SonataMediaBundle - 如何上传图片?的主要内容,如果未能解决你的问题,请参考以下文章
SonataMediaBundle 的公共和私人媒体上传到不同的文件夹(网络和私人)
SonataMediaBundle - 如何使用自定义文件输入