简体   繁体   English

Symfony2关系实体+形式

[英]Symfony2 Relationship entities + forms

I'm trying to write one form for submitting against MySQL DB, but I can't get it working, I've tried a lot of things (separate forms, create an ->add('foo', new foo()) to a field, and trying to parse plain SQL with a normal HTML form is my only solution, which is obviously not the best. 我正在尝试编写一种针对MySQL DB提交的表单,但我无法使其正常工作,我尝试了很多事情(单独的表单,创建->add('foo', new foo())字段,尝试用普通的HTML格式解析纯SQL是我唯一的解决方案,这显然不是最好的方法。

This is my DB structure: 这是我的数据库结构:

![enter image description here][1] ![在此处输入图片描述] [1]

As you can see I need to insert the comments textarea to ticketcomments among the user who wrote it, etc. 如您所见,我需要在编写comments的用户之间将comments文本区域插入到ticketcomments comments

On crmentity the description field. crmentity description字段。

Then on ticketcf the fields that I need to submit from form, are this (because you wont know if I don't tell you because of the field names): 然后在ticketcf上,我需要从表单提交的字段是这个(因为您不会因为字段名而不知道是否告诉您):

tcf.cf594 AS Type,
tcf.cf675 AS Suscription,
tcf.cf770 AS ID_PRODUCT,
tcf.cf746 AS NotificationDate,
tcf.cf747 AS ResponseDate,
tcf.cf748 AS ResolutionDate,

And, of course, every table needs to have the same ticketid id for the submitted form, so we can retrieve it with one simple query. 而且,当然,每个表都需要为提交的表单具有相同的ticketid ID ,因此我们可以通过一个简单的查询来检索它。

It will be easy to do with plain SQL instead of using DQL and Symfony2 forms, but is not a good way to do it. 使用普通SQL而不是使用DQL和Symfony2形式将很容易,但这不是一个好方法。

EDIT This is my new created entity Ticket.php , which has relations to the tables above... if someone could check it out and tell me if it's okay... 编辑这是我新创建的实体Ticket.php ,与上面的表有关系...如果有人可以检查出来并告诉我是否可以...

ticket.php ticket.php

<?php 
namespace WbsGo\clientsBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * VtigerTicketcomments
 *
 * @ORM\Table(name="vtiger_troubletickets")
 * @ORM\Entity(repositoryClass="WbsGo\clientsBundle\Entity\TicketsRepository")
 */

class Tickets
{
    /**
     * @var \WbsGo\clientsBundle\Entity\VtigerCrmentity
     *
     * @ORM\OneToOne(targetEntity="WbsGo\clientsBundle\Entity\VtigerCrmentity")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="ticketid", referencedColumnName="crmid", unique=true)
     * })
     * @ORM\Id
     */
    private $id;

    /**
     * @var string
     *
     * @ORM\Column(name="ticket_no", type="string", length=100, nullable=false)
     *
     */
    private $ticketNo;

    /**
     * @var string
     *
     * @ORM\Column(name="groupname", type="string", length=100, nullable=true)
     */
    private $groupName;

    /**
     * @ORM\ManyToOne(targetEntity="VtigerContactdetails")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="parent_id", referencedColumnName="contactid", unique=true)
     * })
     */
    private $parentId;

    /**
     * @ORM\ManyToOne(targetEntity="VtigerAssets")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="product_id", referencedColumnName="assetsid", unique=true)
     * })
     */
    private $productId;

    /**
     * @var string
     *
     * @ORM\Column(name="priority", type="string", length=100, nullable=true)
     */
    private $priority;

    /**
     * @var string
     *
     * @ORM\Column(name="severity", type="string", length=100, nullable=true)
     */
    private $severity;

    /**
     * @var string
     *
     * @ORM\Column(name="status", type="string", length=100, nullable=true)
     */
    private $status;

    /**
     * @var string
     *
     * @ORM\Column(name="category", type="string", length=100, nullable=true)
     */
    private $category;

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

    /**
     * @var text
     *
     * @ORM\Column(name="solution", type="text", nullable=true)
     */
    private $solution;

    /**
     * @var text
     *
     * @ORM\Column(name="update_log", type="text", nullable=true)
     */
    private $updateLog;

    /**
     * @var integer
     *
     * @ORM\Column(name="version_id", type="integer", nullable=true)
     */
    private $versionId;

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

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

    /**
     * @var integer
     *
     * @ORM\Column(name="from_portal", type="integer", nullable=true)
     */
    private $fromPortal;

    /**
     * @ORM\OneToMany(targetEntity="VtigerTicketcomments", mappedBy="ticketid")
     * 
     */
    protected $comments;

    /**
     * @ORM\OneToOne(targetEntity="VtigerTicketcf", mappedBy="id")
     */
    protected $ticketcf;
    /**
     * @ORM\OneToOne(targetEntity="VtigerCrmentity", mappedBy="crmid")
     */
    protected $crmtable;
}

VtigerTicketcf.php VtigerTicketcf.php

<?php

namespace WbsGo\clientsBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * VtigerTicketcf
 *
 * @ORM\Table(name="vtiger_ticketcf")
 * @ORM\Entity
 */
class VtigerTicketcf
{
    /**
     * @var string
     *
     * @ORM\Column(name="cf_546", type="string", length=255, nullable=true)
     */
    private $cf546;

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

    /**
     * @var string
     *
     * @ORM\Column(name="cf_589", type="string", length=3, nullable=true)
     */
    private $cf589;

    /**
     * @var string
     *
     * @ORM\Column(name="cf_590", type="string", length=3, nullable=true)
     */
    private $cf590;

    /**
     * @var string
     *
     * @ORM\Column(name="cf_592", type="string", length=100, nullable=true)
     */
    private $cf592;

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

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

    /**
     * @var string
     *
     * @ORM\Column(name="cf_675", type="string", length=50, nullable=true)
     */
    private $cf675;

    /**
     * @var float
     *
     * @ORM\Column(name="cf_689", type="decimal", nullable=true)
     */
    private $cf689;

    /**
     * @var float
     *
     * @ORM\Column(name="cf_690", type="decimal", nullable=true)
     */
    private $cf690;

    /**
     * @var float
     *
     * @ORM\Column(name="cf_691", type="decimal", nullable=true)
     */
    private $cf691;

    /**
     * @var float
     *
     * @ORM\Column(name="cf_693", type="decimal", nullable=true)
     */
    private $cf693;

    /**
     * @var string
     *
     * @ORM\Column(name="cf_746", type="string", length=50, nullable=true)
     */
    private $cf746;

    /**
     * @var string
     *
     * @ORM\Column(name="cf_747", type="string", length=50, nullable=true)
     */
    private $cf747;

    /**
     * @var string
     *
     * @ORM\Column(name="cf_748", type="string", length=50, nullable=true)
     */
    private $cf748;

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

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

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

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

    /**
     * @var string
     *
     * @ORM\Column(name="cf_770", type="string", length=50, nullable=true)
     */
    private $cf770;

    /**
     * @var \WbsGo\clientsBundle\Entity\Tickets
     * @ORM\Id
     * @ORM\OneToOne(targetEntity="WbsGo\clientsBundle\Entity\Tickets")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="ticketid", referencedColumnName="ticketid", unique=true)
     * })
     * 
     */
    private $id;
}

VtigerTicketcomments.php VtigerTicketcomments.php

<?php

namespace WbsGo\clientsBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * VtigerTicketcomments
 *
 * @ORM\Table(name="vtiger_ticketcomments")
 * @ORM\Entity
 */
class VtigerTicketcomments
{
    /**
     * @var string
     *
     * @ORM\Column(name="comments", type="text", nullable=true)
     */
    private $comments;

    /**
     * @var integer
     *
     * @ORM\Column(name="ownerid", type="integer", nullable=false)
     */
    private $ownerid;

    /**
     * @var string
     *
     * @ORM\Column(name="ownertype", type="string", length=10, nullable=true)
     */
    private $ownertype;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="createdtime", type="datetime", nullable=false)
     */
    private $createdtime;

    /**
     * @var integer
     *
     * @ORM\Column(name="commentid", type="integer")
     * @ORM\Id
     */
    private $id;

    /**
     * @var \WbsGo\clientsBundle\Entity\Tickets
     * @ORM\OneToOne(targetEntity="WbsGo\clientsBundle\Entity\Tickets")
     * @ORM\JoinColumns({
     *   @ORM\JoinColumn(name="ticketid", referencedColumnName="ticketid", unique=true)
     * })
     * 
     */
    private $ticketid;
}

VtigerCrmentity.php VtigerCrmentity.php

<?php

namespace WbsGo\clientsBundle\Entity;

use Doctrine\ORM\Mapping as ORM;

/**
 * VtigerCrmentity
 *
 * @ORM\Table(name="vtiger_crmentity")
 * @ORM\Entity
 */
class VtigerCrmentity
{
    /**
     * @var integer
     *
     * @ORM\Column(name="smcreatorid", type="integer", nullable=false)
     */
    private $smcreatorid;

    /**
     * @var integer
     *
     * @ORM\Column(name="smownerid", type="integer", nullable=false)
     */
    private $smownerid;

    /**
     * @var integer
     *
     * @ORM\Column(name="modifiedby", type="integer", nullable=false)
     */
    private $modifiedby;

    /**
     * @var string
     *
     * @ORM\Column(name="setype", type="string", length=30, nullable=false)
     */
    private $setype;

    /**
     * @var string
     *
     * @ORM\Column(name="description", type="text", nullable=true)
     */
    private $description;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="createdtime", type="datetime", nullable=false)
     */
    private $createdtime;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="modifiedtime", type="datetime", nullable=false)
     */
    private $modifiedtime;

    /**
     * @var \DateTime
     *
     * @ORM\Column(name="viewedtime", type="datetime", nullable=true)
     */
    private $viewedtime;

    /**
     * @var string
     *
     * @ORM\Column(name="status", type="string", length=50, nullable=true)
     */
    private $status;

    /**
     * @var integer
     *
     * @ORM\Column(name="version", type="integer", nullable=false)
     */
    private $version;

    /**
     * @var integer
     *
     * @ORM\Column(name="presence", type="integer", nullable=true)
     */
    private $presence;

    /**
     * @var integer
     *
     * @ORM\Column(name="deleted", type="integer", nullable=false)
     */
    private $deleted;

    /**
     * @var integer
     *
     * @ORM\Column(name="crmid", type="integer")
     * @ORM\Id
     */
    private $crmid;

}

And this is my repository method... 这是我的存储库方法...

public function findByIdAndCustomerId($id) {
        $query = $this->getEntityManager()
                ->createQuery(
                        '
                        SELECT 
                        IDENTITY(t.id) AS id,
                        t.ticketNo AS Ticket,
                        t.title AS Asunto,
                        t.status AS Estado,
                        t.updateLog AS LOG,
                        t.hours AS Horas,
                        t.solution AS Solucion,
                        t.priority AS Prioridad,
                        tcf.cf748 AS F_Reso,
                        tcf.cf747 AS F_Resp,
                        tcf.cf746 AS F_Noti,
                        tcf.cf770 AS IDPROD,
                        tcf.cf594 AS Tipo,
                        tcf.cf675 AS Suscripcion,
                        c.comments AS Comments,
                        CONCAT (CONCAT(s.firstname, \' \'), s.lastname) AS Contacto
                        FROM WbsGoclientsBundle:Tickets t
                        JOIN t.parentId s
                        JOIN t.ticketcf tcf
                        JOIN t.comments c
                        WHERE  t.ticketNo = :ticketNo

        ')
        ->setParameter('ticketNo', $id)
        ;

        try {
            //return $query->getSingleResult();
            return $query->getResult();
        }
        catch (\Doctrine\ORM\NoResultException $e)
        {
            return null;
        }
    }

I can retrieve an array of X ticket even if I just search by ONE ID, because if ID1 has 4comments, then I got 4 same tickets, one per comment... How can I make it only ONE ticket with comments => array(...) so I can iterate inside that comments array inside twig? 即使我仅通过一个ID搜索,我也可以检索X票证的数组,因为如果ID1有4条评论,那么我将得到4张相同的票证,每个注释一张...我如何只用comments => array(...)所以我可以在树枝中的comments数组中进行迭代?

And also VtigerCrmentity.Description doesn't work either, it returns this error... 而且VtigerCrmentity.Description也不起作用,它返回此错误...

Notice: Undefined index: crmid in /var/www/wbsgo/dev.wbsgo/vendor/doctrine/orm/lib/Doctrine/ORM/Query/SqlWalker.php line 826 注意:未定义的索引:在/var/www/wbsgo/dev.wbsgo/vendor/doctrine/orm/lib/Doctrine/ORM/Query/SqlWalker.php第826行中的crmid

I don't have getter and setter because I'm re-generating them again, if annotation are OK, the entities will update correctly with get/set and my forms will be able to submit using relationships, right? 我没有getter和setter,因为我再次重新生成它们,如果批注正常,则实体将使用get / set正确更新,并且我的表单将能够使用关系提交,对吗?

You may embed a form that does represent an underlying entity field by setting mapped option to false, eg: 您可以通过将mapped选项设置为false来嵌入一个表示基础实体字段的表单,例如:

->add('comments', 'collection', array(
    'type'   => new VtigerTicketcommentsType(),
    'mapped' => false
))

However, be careful when assigning form data, since $form->submit($data) will not set data to underlying collection of comment objects. 但是,在分配表单数据时要小心,因为$form->submit($data)不会将数据设置为注释对象的基础集合。 You'll need to process them manually inside the controller. 您需要在控制器内部手动处理它们。 You may access the data that has been flagged as non-mapped using $form->getExtraData() after the data is submitted to the form. 在将数据提交到表单之后,可以使用$form->getExtraData()访问已标记为未映射的数据。

If you'd like Symfony to automatically set data to comments, you'll need to construct a relationship between VtigerTroubletickets and VtigerTicketcomments entities, which, according to the question title, you don't have and try to avoid. 如果您希望Symfony自动将数据设置为注释,则需要在VtigerTroubleticketsVtigerTicketcomments实体之间构造一个关系,根据问题标题,您没有并试图避免这种关系。

Edit: 编辑:

A form type is bound to a given entity class. 表单类型绑定到给定的实体类。 By default, each field you add to a form type must have an underlying property in a declared entity class (or getter/setter pair if property is not defined public). 默认情况下,添加到表单类型的每个字段都必须在已声明的实体类中具有基础属性(如果属性未定义为public,则必须具有getter / setter对)。 When you construct a form object from form type ( OpenTicketType ) and data ( new VtigerTroubletickets() ): 从表单类型( OpenTicketType )和数据( new VtigerTroubletickets() )构造表单对象时:

$form = $this->createForm(new OpenTicketType(), new VtigerTroubletickets());

the form get bounds with data present in the object you just created. 表单将与您刚创建的对象中存在的数据绑定。 The object does not have comments property, even more, the form itself knows the field is not mapped and it will not try to populate it from the object, so naturally the collection is rendered as empty, as no data about comments was passed. 该对象没有注释属性,而且窗体本身知道该字段未映射,并且不会尝试从该对象填充该字段,因此自然会将该集合呈现为空,因为没有传递有关注释的数据。

To get past this, you may pass array of data instead of newly created object (note: the values may be empty, however comments array must have length > 0 - the comment has to exist, though without actual data). 为了解决这个问题,您可以传递数据数组,而不要传递新创建的对象(注意:这些值可能为空,但是comments数组的长度必须大于0-尽管没有实际数据,但注释必须存在)。

[
  "title"    => "...",
  "priority" => "...",
  "solution" => "...",
  "comments" => [
    0 => [/* comment 0 data */],
    1 => [/* comment 1 data */],
    .......
  ]
]

This is the form creation. 这是表单创建。 When the form is POST-ed, there is one additional step beside constructing the form. 将表单过帐后,除了构建表单外,还有一个额外的步骤。 The request data has to be bound onto form, so you do $form->submit($request) . 请求数据必须绑定到表单上,因此您可以执行$form->submit($request) Now the form AND underlying entity object will get populated with fresh data. 现在,表单AND基础实体对象将填充有新数据。

The $form->getExtraData() is simply a method for accessing the data that form holds and is not mapped to an underlying object - which comments field is, since we flagged it as such. $form->getExtraData()只是一种访问表单保存的数据的方法,该数据没有映射到基础对象-注释字段是,因为我们将其标记为此类。

Alternatively to using getExtraData - extracting data from form manually - you may add a property comments to VtigerTroubletickets entity with getters/setters and not mark it as a db column. 作为使用getExtraData替代方法-手动从表单提取数据,您可以使用getters / setters向VtigerTroubletickets实体添加属性comments ,而不将其标记为db列。 That way, you may remove the mapped => false option at form type, and form will automatically read/populate comments property. 这样,您可以在表单类型中删除mapped => false选项,并且表单将自动读取/填充注释属性。 Still, when persisting, these comments will not be considered for storing, so you'll have to handle them manually. 尽管如此,在保留时,这些注释将不被考虑存储,因此您必须手动处理它们。 Likewise, when fetching an object from database, the comments property would be empty, so prior to creating a form, you'd have to add some comments to an object, eg: 同样,从数据库中获取对象时,comment属性将为空,因此在创建表单之前,您必须向对象添加一些注释,例如:

$tickets = new VtigerTroubletickets();
$tickets->setComments(....);
$form = $this->createForm(new OpenTicketType(), $tickets);

I think @usoban has taken you most of the way. 我认为@usoban带走了您的大部分时间。 Think of these as two long comments as opposed to answers. 可以将它们视为两条长长的评论,而不是答案。

It seems you have a ticket entity and a comment entity with a 1 to many relationship between them but you don't want to actually establish a formal relationship between them because the "DB is used by another platform"? 看来您有一个票证实体和一个注释实体,它们之间具有一对多的关系,但是您不希望在它们之间建立正式的关系,因为“ DB被另一个平台使用了”? What exactly does that mean. 这到底是什么意思呢。 Are you sharing php code with another application? 您是否正在与其他应用程序共享php代码? Are you using doctrine 2? 您是否在使用教义2? With Doctrine 2 you can establish the relationship without changing the actual database. 使用Doctrine 2,您可以在不更改实际数据库的情况下建立关系。

You really should look at adding a getComments to your ticket entity. 您确实应该考虑将getComments添加到票证实体。 It will make your S2 life much easier. 这将使您的S2生活更加轻松。

This answer is built on what @usoban said about using an array but takes a slightly different approach. 这个答案建立在@usoban关于使用数组的内容上,但是采用了稍微不同的方法。

// In the controller
$formData = array();
$formData['ticket'] = new Ticket(),
$formData['comments'] = array(new Comment(), new Comment());

$form = $this->createForm(new TicketCommentsType(), $formData);
$form->handleRequest($request);

if ($form->isValid()) 
{ 
    $formData = $form->getData();
    $ticket   = $formData['ticket'];
    $comments = $formData['comments'];

    // Persist ticket

    // Persist comments

TicketCommentsFormType simply brings the two different entities into one form. TicketCommentsFormType只是将两个不同的实体整合为一种形式。

class TicketCommentsFormType

public function buildForm(

    $builder->add('ticket',new OpenTicketType());
    $builder->add('comments','collection',array(
            'type' => new VtigerTicketcommentsType()

With this approach there is no need to have any direct relation between Ticket and Comment. 使用这种方法,票证和评论之间没有任何直接关系。

I've found the way to do it, and the problems. 我已经找到了解决方法以及存在的问题。

The relations are this: 关系是这样的:

crmentity.id > Main, this table has not relationships crmentity.id > Main,该表没有关系

troubleticket.ticketid > This one has relation with crmentity.id troubleticket.ticketid >这与crmentity.id

ticketcf.ticketid > this one has relation with troubleticket.ticketid ticketcf.ticketid >这一个有关系troubleticket.ticketid

So the order when you insert needs to be crmentity -> troubleticket -> ticketcf 所以为了当你插入必须crmentity - > troubleticket - > ticketcf

But in Symfony2, when you make forms, you must create the last table element as the first form to be generated, so I'll post my code in case someone has the same problem as me. 但是在Symfony2中,制作表格时,必须创建最后一个表格元素作为要生成的第一个表格,因此,如果有人遇到与我相同的问题,我将张贴代码。

http://pastebin.com/wLPyXvbj http://pastebin.com/wLPyXvbj

:) :)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM