问题描述
我有这个别名实体:
使用Gedmo\ Timestampable\Traits\TimestampableEntity;
class Alias
{
use IdentifierAutogeneratedTrait;
使用TimestampableEntity;
使用ActiveTrait;
/ **
* @var string
* @ ORM\Column(type =string,length = 150)
* /
私人$名称;
/ **
*与别名关联的命令。
*
* @var Command []
* @ ORM\ManyToMany(targetEntity =Command,mappedBy =aliases,cascade = {persist})
* /
private $ commands;
...
}
我有这个管理员控制器:
class AliasAdmin extends Admin
{
protected function configureFormFields(FormMapper $ formMapper)
{
$ formMapper
- > add('name',null,array('required'=> true))
- > add('active',null,array ('required'=> false));
}
...
public function prePersist($ alias)
{
//删除额外的空格
$ noWhiteSpaces = str_replace('','',$ alias-> getName());
//分成几个名字
$ aliasArr = explode(',',$ noWhiteSpaces);
}
public function preUpdate($ alias)
{
...
}
}
当我在视图上添加一个新的别名 - 表示本身 - 我可以在名称中输入一个值,例如: value1 或者我可以写多个逗号分隔的值: value1,value2,value3,value4 。如果在提交表单时,我在名称中只有一个值,那么将不会有任何问题,但如果我有多个逗号分隔,那么我应该检查对于他们在 prePersist / preUpdate 方法中,以分割它们,并为每个名称创建一个别名 ,我该怎么办?如果你看看 prePersist 方法,你会看到我在说的更清楚如何在新的中创建一个新的别名, $ aliasArr ,任何帮助?
更新:不处理TimestampableEntity,为什么?
$ b
在@ m-khalid-junaid尝试解决方案后,由于 NOT NULL 约束,我以下错误结束,但我不知道为什么。看看代码:
class AliasAdminController extends Controller
{
/ **
* {@inheritdoc}
* /
public function createAction(Request $ request = null)
{
//用于查找模板的键
$ templateKey ='编辑'
if(false === $ this-> admin-> isGranted('CREATE')){
throw new AccessDeniedException();
}
$ object = $ this-> admin-> getNewInstance();
$ this-> admin-> setSubject($ object);
/ ** @var $ form \Symfony\Component\Form\Form * /
$ form = $ this-> admin-> getForm();
$ form-> setData($ object);
if($ this-> getRestMethod()=='POST'){
$ form-> submit($ this-> get('request'));
$ isFormValid = $ form-> isValid();
//如果表单有效,并且如果在预览模式下预览已被批准
if($ isFormValid&&(!!this-> isInPreviewMode()|| $ this-> isPreviewApproved())){
if(false === $ this-> admin-> isGranted('CREATE',$ object)){
throw new AccessDeniedException();
}
try {
$ aliasArr = $ this-> toStrings($ object-> getName());
if(count($ aliasArr)> 1){
$ object-> setName($ aliasArr [0]);
$ object = $ this-> admin-> create($ object);
unset($ aliasArr [0]);
$ entityManager = $ this-> getDoctrine() - > getManager();
foreach($ aliasArr as $ alias){
$ newAlias = new Alias();
$ newAlias-> setName($ alias);
$ entityManager-> persist($ newAlias);
}
$ entityManager-> flush();
} else {
$ object = $ this-> admin-> create($ object);
}
if($ this-> isXmlHttpRequest()){
return $ this-> renderJson(array(
'result'=> OK',
'objectId'=> $ this-> admin-> getNormalizedIdentifier($ object),
));
}
$ this-> addFlash(
'sonata_flash_success',
$ this-> admin-> trans(
'flash_create_success' ,
array('%name%'=> $ this-> escapeHtml($ this-> admin-> toString($ object))),
'SonataAdminBundle'
)
);
//重定向到编辑模式
return $ this-> redirectTo($ object);
} catch(ModelManagerException $ e){
$ this-> logModelManagerException($ e);
$ isFormValid = false;
}
}
//如果表单验证失败,显示错误消息
if(!$ isFormValid){
if(!$ this- > isXmlHttpRequest()){
$ this-> addFlash(
'sonata_flash_error',
$ this-> admin-> trans(
'flash_create_error',
数组('%name%'=> $ this-> escapeHtml($ this-> admin-> toString($ object))),
'SonataAdminBundle'
)
);
}
} elseif($ this-> isPreviewRequested()){
//如果表单有效并且请求预览,则选择预览模板
$ templateKey ='preview ;
$ this-> admin-> getShow();
}
}
$ view = $ form-> createView();
//设置当前管理窗体的主题
$ this-> get('twig') - > getExtension('form') - > renderer-> setTheme ($ view,$ this-> admin-> getFormTheme());
return $ this-> render($ this-> admin-> getTemplate($ templateKey),array(
'action'=>'create',
'form'=> $ view,
'object'=> $ object,
));
}
/ **
* {@inheritdoc}
* /
public function editAction($ id = null)
{
//用于查找模板的键
$ templateKey ='edit';
$ id = $ this-> get('request') - > get($ this-> admin-> getIdParameter());
$ object = $ this-> admin-> getObject($ id);
如果(!$ object){
抛出新的NotFoundHttpException(sprintf('找不到id为%s'的对象,$ id));
}
if(false === $ this-> admin-> isGranted('EDIT',$ object)){
throw new AccessDeniedException();
}
$ this-> admin-> setSubject($ object);
/ ** @var $ form \Symfony\Component\Form\Form * /
$ form = $ this-> admin-> getForm();
$ form-> setData($ object);
if($ this-> getRestMethod()=='POST'){
$ form-> submit($ this-> get('request'));
$ isFormValid = $ form-> isValid();
//如果表单有效,并且如果在预览模式下预览已被批准
if($ isFormValid&&(!!this-> isInPreviewMode()|| $ this-> isPreviewApproved())){
try {
$ aliasArr = $ this-> toStrings($ object-> getName());
if(count($ aliasArr)> 1){
$ object-> setName($ aliasArr [0]);
$ object = $ this-> admin-> update($ object);
unset($ aliasArr [0]);
$ entityManager = $ this-> getDoctrine() - > getManager();
foreach($ aliasArr as $ alias){
$ newAlias = new Alias();
$ newAlias-> setName($ alias);
$ entityManager-> persist($ newAlias);
}
$ entityManager-> flush();
} else {
$ object = $ this-> admin-> update($ object);
}
if($ this-> isXmlHttpRequest()){
return $ this-> renderJson(array(
'result'=> OK',
'objectId'=> $ this-> admin-> getNormalizedIdentifier($ object),
));
}
$ this-> addFlash(
'sonata_flash_success',
$ this-> admin-> trans(
'flash_edit_success' ,
array('%name%'=> $ this-> escapeHtml($ this-> admin-> toString($ object))),
'SonataAdminBundle'
)
);
//重定向到编辑模式
return $ this-> redirectTo($ object);
} catch(ModelManagerException $ e){
$ this-> logModelManagerException($ e);
$ isFormValid = false;
}
}
//如果表单验证失败,显示错误消息
if(!$ isFormValid){
if(!$ this- > isXmlHttpRequest()){
$ this-> addFlash(
'sonata_flash_error',
$ this-> admin-> trans(
'flash_edit_error',
数组('%name%'=> $ this-> escapeHtml($ this-> admin-> toString($ object))),
'SonataAdminBundle'
)
);
}
} elseif($ this-> isPreviewRequested()){
//如果表单有效并且请求预览,则启用预览模板
$ templateKey ='预览;
$ this-> admin-> getShow();
}
}
$ view = $ form-> createView();
//设置当前管理窗体的主题
$ this-> get('twig') - > getExtension('form') - > renderer-> setTheme ($ view,$ this-> admin-> getFormTheme());
return $ this-> render($ this-> admin-> getTemplate($ templateKey),array(
'action'=>'edit',
'form'=> $ view,
'object'=> $ object,
));
}
私有函数logModelManagerException($ e)
{
$ context = array('exception'=> $ e);
if($ e-> getPrevious()){
$ context ['previous_exception_message'] = $ e-> getPrevious() - > getMessage();
}
$ this-> getLogger() - > error($ e-> getMessage(),$ context);
}
私有函数toStrings($ string)
{
$ noWhiteSpaces = str_replace('','',$ string);
return explode(',',$ noWhiteSpaces);
}
}
这是错误:
[2016-02-28 11:10:36] doctrine.DEBUG:START TRANSACTION[] []
[2016- 02-28 11:10:36] doctrine.DEBUG:INSERT INTO cm_alias(name,created_at,updated_at,active)VALUES(?,?,?,?){1:alias1,2 3:null,4:true} []
[2016-02-28 11:10:36] doctrine.DEBUG:ROLLBACK[] []
[ 28 11:10:36] app.ERROR:无法创建对象:PlatformAdminBundle\Entity\Alias {exception:[object](Sonata\\AdminBundle\\Exception\\\ModelManagerException(代码:0):无法创建对象:PlatformAdminBundle\\\Entity\\Alias at /var/www/html/platform.sonata/vendor/sonata-project/doctrine-orm-admin-bundle/Model/ModelManager .php:142,Doctrine\\\\\\\Exception\\NotNullConstraintViolationException(code:0):执行'INSERT INTO cm_alias(name,created_at,updated_a t,active)VALUES(?,?,?,?)'与params [\alias1\,null,null,1]:\\\
\\\
SQLSTATE [23000]:违反完整性约束: created_at'在/var/www/html/platform.sonata/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php:112,Doctrine\\\DBAL\\Driver\不能为空\PDOException(代码:23000):SQLSTATE [23000]:完整性约束违规:1048列'created_at'在/var/www/html/platform.sonata/vendor/doctrine/dbal/lib/Doctrine/DBAL/中不能为空驱动程序/ PDOStatement.php:93,PDOException(代码:23000):SQLSTATE [23000]:完整性约束违规:1048列'created_at'在/var/www/html/platform.sonata/vendor/doctrine/dbal/不能为空lib / Doctrine / DBAL / Driver / PDOStatement.php:91),previous_exception_message:执行时发生异常INSERT INTO cm_alias(name,created_at,updated_at,active)VALUES(?,?,?,?使用params [\alias1\,null,null,1]: \\ n\\\
SQLSTATE [23000]:违反完整性限制:1048列'created_at'不能为空} []
为什么 TimestampableEntity trait不会被新的管理控制器处理?我在这里缺少什么?
如果要添加不同别名的同一个对象,最好创建一个 CRUDController 控制器为您的管理员类,一旦你有你的CRUDController,你可以覆盖 createAction &基础类的 editAction ,并在此处执行您的逻辑prePresist / preUpdate事件,以便您当前的对象使用不同的信息使用控制器为您的对象创建副本。我只提到了下面的必要代码,你可以从sonata的CRUDController复制并在 editAction
public function createAction(Request $ request = null)
{
// ..这里的一些代码从基类复制
try {
$ noWhiteSpaces = str_replace('','',$ object-> getName());
//分成几个名字
$ aliases = explode(',',$ noWhiteSpaces);
if(count($ aliases)> 1){
$ object-> setName($ aliases [0]);
$ object = $ this-> admin-> create($ object);
unset($ aliases [0]);
$ DM = $ this-> getDoctrine() - > getManager();
foreach($ aliases as $ alias){
$ newAlias = new Alias();
$ newAlias-> setName($ alias);
$ DM-> persist($ newAlias);
}
$ DM-> flush();
} else {
$ object = $ this-> admin-> create($ object);
}
} catch(ModelManagerException $ e){
$ this-> handleModelManagerException($ e);
$ isFormValid = false;
}
// ..这里的一些代码从基类
复制
编辑 created_at not null error
您需要在别名实体中定义一个构造函数,在 createdAt 属性初始化 DateTime 对象
/ **
*构造函数
* /
public function __construct()
{
$ this-> createdAt = new \\ \\DateTime( '现在');
}
I have this Alias entity:
use Gedmo\Timestampable\Traits\TimestampableEntity; class Alias { use IdentifierAutogeneratedTrait; use TimestampableEntity; use ActiveTrait; /** * @var string * @ORM\Column(type="string", length=150) */ private $name; /** * Command associated to the alias. * * @var Command[] * @ORM\ManyToMany(targetEntity="Command", mappedBy="aliases", cascade={"persist"}) */ private $commands; ... }
And I have this Admin controller:
class AliasAdmin extends Admin { protected function configureFormFields(FormMapper $formMapper) { $formMapper ->add('name', null, array('required' => true)) ->add('active', null, array('required' => false)); } ... public function prePersist($alias) { // remove extra white spaces $noWhiteSpaces = str_replace(' ', '', $alias->getName()); // split into several names $aliasArr = explode(',', $noWhiteSpaces); } public function preUpdate($alias) { ... } }
When I am adding a new Alias on the view - meaning the form itself - I can write one value on the name input field as for example: value1 or I can write multiple values comma separated: value1, value2, value3, value4. If I have only one value on the name field when I submit the form then will be no problems but if I have more than one comma separated as the second example then I should check for them on prePersist/preUpdate method in order to split them and create one Alias per name, how I can do this? If you take a look to the prePersist method you will see what I am talking about more clear about how to create a new Alias per name in the new $aliasArr, any help?
Update: TimestampableEntity is not processed, why?
After tried the solution by @m-khalid-junaid I end with the error below due to NOT NULL constraint but I don't know why. Take a look to the code:
class AliasAdminController extends Controller { /** * {@inheritdoc} */ public function createAction(Request $request = null) { // the key used to lookup the template $templateKey = 'edit'; if (false === $this->admin->isGranted('CREATE')) { throw new AccessDeniedException(); } $object = $this->admin->getNewInstance(); $this->admin->setSubject($object); /** @var $form \Symfony\Component\Form\Form */ $form = $this->admin->getForm(); $form->setData($object); if ($this->getRestMethod() == 'POST') { $form->submit($this->get('request')); $isFormValid = $form->isValid(); // persist if the form was valid and if in preview mode the preview was approved if ($isFormValid && (!$this->isInPreviewMode() || $this->isPreviewApproved())) { if (false === $this->admin->isGranted('CREATE', $object)) { throw new AccessDeniedException(); } try { $aliasArr = $this->toStrings($object->getName()); if (count($aliasArr) > 1) { $object->setName($aliasArr[0]); $object = $this->admin->create($object); unset($aliasArr[0]); $entityManager = $this->getDoctrine()->getManager(); foreach ($aliasArr as $alias) { $newAlias = new Alias(); $newAlias->setName($alias); $entityManager->persist($newAlias); } $entityManager->flush(); } else { $object = $this->admin->create($object); } if ($this->isXmlHttpRequest()) { return $this->renderJson(array( 'result' => 'ok', 'objectId' => $this->admin->getNormalizedIdentifier($object), )); } $this->addFlash( 'sonata_flash_success', $this->admin->trans( 'flash_create_success', array('%name%' => $this->escapeHtml($this->admin->toString($object))), 'SonataAdminBundle' ) ); // redirect to edit mode return $this->redirectTo($object); } catch (ModelManagerException $e) { $this->logModelManagerException($e); $isFormValid = false; } } // show an error message if the form failed validation if (!$isFormValid) { if (!$this->isXmlHttpRequest()) { $this->addFlash( 'sonata_flash_error', $this->admin->trans( 'flash_create_error', array('%name%' => $this->escapeHtml($this->admin->toString($object))), 'SonataAdminBundle' ) ); } } elseif ($this->isPreviewRequested()) { // pick the preview template if the form was valid and preview was requested $templateKey = 'preview'; $this->admin->getShow(); } } $view = $form->createView(); // set the theme for the current Admin Form $this->get('twig')->getExtension('form')->renderer->setTheme($view, $this->admin->getFormTheme()); return $this->render($this->admin->getTemplate($templateKey), array( 'action' => 'create', 'form' => $view, 'object' => $object, )); } /** * {@inheritdoc} */ public function editAction($id = null) { // the key used to lookup the template $templateKey = 'edit'; $id = $this->get('request')->get($this->admin->getIdParameter()); $object = $this->admin->getObject($id); if (!$object) { throw new NotFoundHttpException(sprintf('unable to find the object with id : %s', $id)); } if (false === $this->admin->isGranted('EDIT', $object)) { throw new AccessDeniedException(); } $this->admin->setSubject($object); /** @var $form \Symfony\Component\Form\Form */ $form = $this->admin->getForm(); $form->setData($object); if ($this->getRestMethod() == 'POST') { $form->submit($this->get('request')); $isFormValid = $form->isValid(); // persist if the form was valid and if in preview mode the preview was approved if ($isFormValid && (!$this->isInPreviewMode() || $this->isPreviewApproved())) { try { $aliasArr = $this->toStrings($object->getName()); if (count($aliasArr) > 1) { $object->setName($aliasArr[0]); $object = $this->admin->update($object); unset($aliasArr[0]); $entityManager = $this->getDoctrine()->getManager(); foreach ($aliasArr as $alias) { $newAlias = new Alias(); $newAlias->setName($alias); $entityManager->persist($newAlias); } $entityManager->flush(); } else { $object = $this->admin->update($object); } if ($this->isXmlHttpRequest()) { return $this->renderJson(array( 'result' => 'ok', 'objectId' => $this->admin->getNormalizedIdentifier($object), )); } $this->addFlash( 'sonata_flash_success', $this->admin->trans( 'flash_edit_success', array('%name%' => $this->escapeHtml($this->admin->toString($object))), 'SonataAdminBundle' ) ); // redirect to edit mode return $this->redirectTo($object); } catch (ModelManagerException $e) { $this->logModelManagerException($e); $isFormValid = false; } } // show an error message if the form failed validation if (!$isFormValid) { if (!$this->isXmlHttpRequest()) { $this->addFlash( 'sonata_flash_error', $this->admin->trans( 'flash_edit_error', array('%name%' => $this->escapeHtml($this->admin->toString($object))), 'SonataAdminBundle' ) ); } } elseif ($this->isPreviewRequested()) { // enable the preview template if the form was valid and preview was requested $templateKey = 'preview'; $this->admin->getShow(); } } $view = $form->createView(); // set the theme for the current Admin Form $this->get('twig')->getExtension('form')->renderer->setTheme($view, $this->admin->getFormTheme()); return $this->render($this->admin->getTemplate($templateKey), array( 'action' => 'edit', 'form' => $view, 'object' => $object, )); } private function logModelManagerException($e) { $context = array('exception' => $e); if ($e->getPrevious()) { $context['previous_exception_message'] = $e->getPrevious()->getMessage(); } $this->getLogger()->error($e->getMessage(), $context); } private function toStrings($string) { $noWhiteSpaces = str_replace(' ', '', $string); return explode(',', $noWhiteSpaces); } }
And this is the error:
[2016-02-28 11:10:36] doctrine.DEBUG: "START TRANSACTION" [] [] [2016-02-28 11:10:36] doctrine.DEBUG: INSERT INTO cm_alias (name, created_at, updated_at, active) VALUES (?, ?, ?, ?) {"1":"alias1","2":null,"3":null,"4":true} [] [2016-02-28 11:10:36] doctrine.DEBUG: "ROLLBACK" [] [] [2016-02-28 11:10:36] app.ERROR: Failed to create object: PlatformAdminBundle\Entity\Alias {"exception":"[object] (Sonata\\AdminBundle\\Exception\\ModelManagerException(code: 0): Failed to create object: PlatformAdminBundle\\Entity\\Alias at /var/www/html/platform.sonata/vendor/sonata-project/doctrine-orm-admin-bundle/Model/ModelManager.php:142, Doctrine\\DBAL\\Exception\\NotNullConstraintViolationException(code: 0): An exception occurred while executing 'INSERT INTO cm_alias (name, created_at, updated_at, active) VALUES (?, ?, ?, ?)' with params [\"alias1\", null, null, 1]:\n\nSQLSTATE[23000]: Integrity constraint violation: 1048 Column 'created_at' cannot be null at /var/www/html/platform.sonata/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/AbstractMySQLDriver.php:112, Doctrine\\DBAL\\Driver\\PDOException(code: 23000): SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'created_at' cannot be null at /var/www/html/platform.sonata/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php:93, PDOException(code: 23000): SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'created_at' cannot be null at /var/www/html/platform.sonata/vendor/doctrine/dbal/lib/Doctrine/DBAL/Driver/PDOStatement.php:91)","previous_exception_message":"An exception occurred while executing 'INSERT INTO cm_alias (name, created_at, updated_at, active) VALUES (?, ?, ?, ?)' with params [\"alias1\", null, null, 1]:\n\nSQLSTATE[23000]: Integrity constraint violation: 1048 Column 'created_at' cannot be null"} []
Why TimestampableEntity trait is not processed by the new Admin controller? What I am missing here?
If you want to add same object with different aliases its better to create a CRUDController controller for your admin class, Once you have your CRUDController you can override createAction & editAction of base class and implement your logic here prePresist/preUpdate events for your current object to play with to create copies for your object with different information use a controller. I have mentioned only necessary code below you can copy from sonata's CRUDController and implement the same logic in editAction
public function createAction(Request $request = null) { // .. some code here copy from base class try { $noWhiteSpaces = str_replace(' ', '', $object->getName()); // split into several names $aliases = explode(',', $noWhiteSpaces); if (count($aliases) > 1) { $object->setName($aliases[0]); $object = $this->admin->create($object); unset($aliases[0]); $DM = $this->getDoctrine()->getManager(); foreach ($aliases as $alias) { $newAlias = new Alias(); $newAlias->setName($alias); $DM->persist($newAlias); } $DM->flush(); } else { $object = $this->admin->create($object); } } catch (ModelManagerException $e) { $this->handleModelManagerException($e); $isFormValid = false; } // .. some code here copy from base class }
Edit for created_at not null error
You need to define a constructor function in your alias entity and there initialize your createdAt property with DateTime object
/** * Constructor */ public function __construct() { $this->createdAt = new \DateTime('now'); }
这篇关于可以在Sonata Admin控制器中使用prePersist / preUpdate来保存多个对象吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!