Symfony crud 生成的索引视图,其中没有引用字段
Symfony crud generated index view, where is not have references fields
Symfony 命令doctrine:generate:crud 生成控制器<表单及其视图。但是,索引不包含其他 table 引用字段 "many-to-one".
实体模型:
<?php
namespace Acme\Bundle\AdminBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Albums
*
* @ORM\Table(name="albums", indexes={@ORM\Index(name="IDX_F4E2474F3D8E604F", columns={"parent"})})
* @ORM\Entity
*/
class Albums
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer", nullable=false)
* @ORM\Id
* @ORM\GeneratedValue(strategy="SEQUENCE")
* @ORM\SequenceGenerator(sequenceName="albums_id_seq", allocationSize=1, initialValue=1)
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=60, nullable=false)
*/
private $name;
/**
* @var integer
*
* @ORM\Column(name="sort", type="integer", nullable=false)
*/
private $sort;
/**
* @var \ParentAlbums
*
* @ORM\ManyToOne(targetEntity="ParentAlbums")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="parent", referencedColumnName="id")
* })
*/
private $parent;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* @param string $name
* @return Albums
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Set sort
*
* @param integer $sort
* @return Albums
*/
public function setSort($sort)
{
$this->sort = $sort;
return $this;
}
/**
* Get sort
*
* @return integer
*/
public function getSort()
{
return $this->sort;
}
/**
* Set parent
*
* @param \Acme\Bundle\AdminBundle\Entity\ParentAlbums $parent
* @return Albums
*/
public function setParent(\Acme\Bundle\AdminBundle\Entity\ParentAlbums $parent = null)
{
$this->parent = $parent;
return $this;
}
/**
* Get parent
*
* @return \Acme\Bundle\AdminBundle\Entity\ParentAlbums
*/
public function getParent()
{
return $this->parent;
}
}
Index.html.twig - table 头部部分:
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Sort</th>
<th>{{ 'views.index.actions'|trans({}, 'JordiLlonchCrudGeneratorBundle') }}</th>
</tr>
</thead>
crud 命令可以帮助您快速生成多个文件,但它并不是全部。 $parent 是指向另一个实体的指针。 crud 方法无法知道您要从此实体显示什么。假设 ParentAlbums 有一个 属性 '$name'。您可以通过稍微更改 index.html.twig 来非常简单地显示它:
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Parent</th>
<th>Sort</th>
<th>{{ 'views.index.actions'|trans({}, 'JordiLlonchCrudGeneratorBundle') }}</th>
</tr>
</thead>
<tbody>
{% for entity in entities %}
<tr>
<td>{{ entity.id }}</td>
<td>{{ entity.name }}</td>
<td>{{ entity.parent.name }}</td>
<td>{{ entity.sort }}</td>
<td>
<ul>
// actions here
</ul>
</td>
</tr>
{% endfor %}
</tbody>
这是 DoctrineCrudGenerator 的正常行为,因为生成器只使用 Doctrine\ORM\Mapping\ClassMetadataInfo::$fieldMappings
数组来生成 table,但是 ParentAlbum-ManyToOne 关联位于 Doctrine\ORM\Mapping\ClassMetadataInfo::$associationMappings
大批。所以它永远不会在 crud 生成中被识别。
为了演示可能的解决方案,我使用了 symfony-demo 应用程序的 Comment 实体:
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Entity
*
* Defines the properties of the Comment entity to represent the blog comments.
* See http://symfony.com/doc/current/book/doctrine.html#creating-an-entity-class
*
* Tip: if you have an existing database, you can generate these entity class automatically.
* See http://symfony.com/doc/current/cookbook/doctrine/reverse_engineering.html
*
* @author Ryan Weaver <weaverryan@gmail.com>
* @author Javier Eguiluz <javier.eguiluz@gmail.com>
*/
class Comment
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity="Post", inversedBy="comments")
* @ORM\JoinColumn(nullable=false)
*/
private $post;
/**
* @ORM\Column(type="text")
* @Assert\NotBlank(message="Please don't leave your comment blank!")
* @Assert\Length(
* min = "5",
* minMessage = "Comment is too short ({{ limit }} characters minimum)",
* max = "10000",
* maxMessage = "Comment is too long ({{ limit }} characters maximum)"
* )
*/
private $content;
/**
* @ORM\Column(type="string")
* @Assert\Email()
*/
private $authorEmail;
/**
* @ORM\Column(type="datetime")
* @Assert\DateTime()
*/
private $publishedAt;
public function __construct()
{
$this->publishedAt = new \DateTime();
}
/**
* @Assert\True(message = "The content of this comment is considered spam.")
*/
public function isLegitComment()
{
$containsInvalidCharacters = false !== strpos($this->content, '@');
return !$containsInvalidCharacters;
}
public function getId()
{
return $this->id;
}
public function getContent()
{
return $this->content;
}
public function setContent($content)
{
$this->content = $content;
}
public function getAuthorEmail()
{
return $this->authorEmail;
}
public function setAuthorEmail($authorEmail)
{
$this->authorEmail = $authorEmail;
}
public function getPublishedAt()
{
return $this->publishedAt;
}
public function setPublishedAt($publishedAt)
{
$this->publishedAt = $publishedAt;
}
public function getPost()
{
return $this->post;
}
public function setPost(Post $post = null)
{
$this->post = $post;
}
}
有 "normal" 列,如 id、content、authorEmail 和 publishedAt,以及一个与 Post 实体的 ManyToOne 关联。为此实体生成了以下元数据:
Doctrine\ORM\Mapping\ClassMetadata {#437
+name: "AppBundle\Entity\Comment"
+namespace: "AppBundle\Entity"
+rootEntityName: "AppBundle\Entity\Comment"
+customGeneratorDefinition: null
+customRepositoryClassName: null
+isMappedSuperclass: false
+isEmbeddedClass: false
+parentClasses: []
+subClasses: []
+embeddedClasses: []
+namedQueries: []
+namedNativeQueries: []
+sqlResultSetMappings: []
+identifier: array:1 [
0 => "id"
]
+inheritanceType: 1
+generatorType: 4
+fieldMappings: array:4 [
"id" => array:9 [
"fieldName" => "id"
"type" => "integer"
"scale" => 0
"length" => null
"unique" => false
"nullable" => false
"precision" => 0
"id" => true
"columnName" => "id"
]
"content" => array:8 [
"fieldName" => "content"
"type" => "text"
"scale" => 0
"length" => null
"unique" => false
"nullable" => false
"precision" => 0
"columnName" => "content"
]
"authorEmail" => array:8 [
"fieldName" => "authorEmail"
"type" => "string"
"scale" => 0
"length" => null
"unique" => false
"nullable" => false
"precision" => 0
"columnName" => "authorEmail"
]
"publishedAt" => array:8 [
"fieldName" => "publishedAt"
"type" => "datetime"
"scale" => 0
"length" => null
"unique" => false
"nullable" => false
"precision" => 0
"columnName" => "publishedAt"
]
]
+fieldNames: array:4 [
"id" => "id"
"content" => "content"
"authorEmail" => "authorEmail"
"publishedAt" => "publishedAt"
]
+columnNames: array:4 [
"id" => "id"
"content" => "content"
"authorEmail" => "authorEmail"
"publishedAt" => "publishedAt"
]
+discriminatorValue: null
+discriminatorMap: []
+discriminatorColumn: null
+table: array:1 [
"name" => "Comment"
]
+lifecycleCallbacks: []
+entityListeners: []
+associationMappings: array:1 [
"post" => array:19 [
"fieldName" => "post"
"joinColumns" => array:1 [
0 => array:6 [
"name" => "post_id"
"unique" => false
"nullable" => false
"onDelete" => null
"columnDefinition" => null
"referencedColumnName" => "id"
]
]
"cascade" => []
"inversedBy" => "comments"
"targetEntity" => "AppBundle\Entity\Post"
"fetch" => 2
"type" => 2
"mappedBy" => null
"isOwningSide" => true
"sourceEntity" => "AppBundle\Entity\Comment"
"isCascadeRemove" => false
"isCascadePersist" => false
"isCascadeRefresh" => false
"isCascadeMerge" => false
"isCascadeDetach" => false
"sourceToTargetKeyColumns" => array:1 [
"post_id" => "id"
]
"joinColumnFieldNames" => array:1 [
"post_id" => "post_id"
]
"targetToSourceKeyColumns" => array:1 [
"id" => "post_id"
]
"orphanRemoval" => false
]
]
+isIdentifierComposite: false
+containsForeignIdentifier: false
+idGenerator: Doctrine\ORM\Id\IdentityGenerator {#439
-sequenceName: null
}
+sequenceGeneratorDefinition: null
+tableGeneratorDefinition: null
+changeTrackingPolicy: 1
+isVersioned: null
+versionField: null
+cache: null
+reflClass: null
+isReadOnly: false
#namingStrategy: Doctrine\ORM\Mapping\DefaultNamingStrategy {#407}
+reflFields: array:5 [
"id" => null
"content" => null
"authorEmail" => null
"publishedAt" => null
"post" => null
]
-instantiator: Doctrine\Instantiator\Instantiator {#438}
}
可以看到,普通字段位于fieldMappings数组中,而关联位于associationMappings数组中。
运行 Comment 实体的 crud 生成器只为没有 post 关联的 "normal" 列生成 table:
<thead>
<tr>
<th>Id</th>
<th>Content</th>
<th>Authoremail</th>
<th>Publishedat</th>
<th>Actions</th>
</tr>
</thead>
现在,要更改此行为,您只需 "merge" 在生成 crud 时将 fieldMappings 数组中的 associationMappings 数组。
您可以在 Sensio\Bundle\GeneratorBundle\Generator\DoctrineCrudGenerator
中执行此操作。对于生产,您必须覆盖
Sensio\Bundle\GeneratorBundle\Generator\DoctrineCrudGenerator
和 Sensio\Bundle\GeneratorBundle\Command\GenerateDoctrineCrudCommand
并在您自己的 class 中进行更改。但是,作为概念证明,我将进行快速且非常肮脏的破解,并添加
直接对 DoctrineCrudGenerator 进行以下更改:
/**
* Generates a CRUD controller.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class DoctrineCrudGenerator extends Generator
{
// ...
/**
* Generates the index.html.twig template in the final bundle.
*
* @param string $dir The path to the folder that hosts templates in the bundle
*/
protected function generateIndexView($dir)
{
$this->renderFile(
'crud/views/index.html.twig.twig',
$dir . '/index.html.twig',
array(
'bundle' => $this->bundle->getName(),
'entity' => $this->entity,
'identifier' => $this->metadata->identifier[0],
// Use the function instead of the "raw" fieldMappings array
// 'fields' => $this->metadata->fieldMappings,
'fields' => $this->processFieldMappings(),
'actions' => $this->actions,
'record_actions' => $this->getRecordActions(),
'route_prefix' => $this->routePrefix,
'route_name_prefix' => $this->routeNamePrefix,
)
);
}
// ...
/**
* Add the associations to the array
*
* @return array
*/
protected function processFieldMappings()
{
/** @var \Doctrine\ORM\Mapping\ClassMetadata $metadata */
$metadata = $this->metadata;
$fields = $metadata->fieldMappings;
$associationMappings = $metadata->associationMappings;
foreach ($associationMappings as $k => $a) {
// Add the field only if it is a ToOne association and if the targetEntity implements the __toString method
if ($a['type'] & ClassMetadataInfo::TO_ONE && method_exists($a['targetEntity'], '__toString')) {
$fields[$k] = array(
"fieldName" => $a["fieldName"],
"type" => "text",
"scale" => 0,
"length" => null,
"unique" => false,
"nullable" => false,
"precision" => 0,
"columnName" => $k
);
}
}
return $fields;
}
}
更改后,如果您将 __toString 添加到 Post 实体,生成器会生成以下代码:
<table class="records_list">
<thead>
<tr>
<th>Id</th>
<th>Content</th>
<th>Authoremail</th>
<th>Publishedat</th>
<th>Post</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for entity in entities %}
<tr>
<td><a href="{{ path('comment_show', { 'id': entity.id }) }}">{{ entity.id }}</a></td>
<td>{{ entity.content }}</td>
<td>{{ entity.authorEmail }}</td>
<td>{% if entity.publishedAt %}{{ entity.publishedAt|date('Y-m-d H:i:s') }}{% endif %}</td>
<td>{{ entity.post }}</td>
<td>
<ul>
<li>
<a href="{{ path('comment_show', { 'id': entity.id }) }}">show</a>
</li>
<li>
<a href="{{ path('comment_edit', { 'id': entity.id }) }}">edit</a>
</li>
</ul>
</td>
</tr>
{% endfor %}
</tbody>
</table>
可以看到,post关联已经被识别了。如果你想开始写作,你可以以此为切入点
你自己的发电机。但是你必须调查,如何处理 ToMany 关联以及如何处理关联
表格等等..
Symfony 命令doctrine:generate:crud 生成控制器<表单及其视图。但是,索引不包含其他 table 引用字段 "many-to-one".
实体模型:
<?php
namespace Acme\Bundle\AdminBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
/**
* Albums
*
* @ORM\Table(name="albums", indexes={@ORM\Index(name="IDX_F4E2474F3D8E604F", columns={"parent"})})
* @ORM\Entity
*/
class Albums
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer", nullable=false)
* @ORM\Id
* @ORM\GeneratedValue(strategy="SEQUENCE")
* @ORM\SequenceGenerator(sequenceName="albums_id_seq", allocationSize=1, initialValue=1)
*/
private $id;
/**
* @var string
*
* @ORM\Column(name="name", type="string", length=60, nullable=false)
*/
private $name;
/**
* @var integer
*
* @ORM\Column(name="sort", type="integer", nullable=false)
*/
private $sort;
/**
* @var \ParentAlbums
*
* @ORM\ManyToOne(targetEntity="ParentAlbums")
* @ORM\JoinColumns({
* @ORM\JoinColumn(name="parent", referencedColumnName="id")
* })
*/
private $parent;
/**
* Get id
*
* @return integer
*/
public function getId()
{
return $this->id;
}
/**
* Set name
*
* @param string $name
* @return Albums
*/
public function setName($name)
{
$this->name = $name;
return $this;
}
/**
* Get name
*
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* Set sort
*
* @param integer $sort
* @return Albums
*/
public function setSort($sort)
{
$this->sort = $sort;
return $this;
}
/**
* Get sort
*
* @return integer
*/
public function getSort()
{
return $this->sort;
}
/**
* Set parent
*
* @param \Acme\Bundle\AdminBundle\Entity\ParentAlbums $parent
* @return Albums
*/
public function setParent(\Acme\Bundle\AdminBundle\Entity\ParentAlbums $parent = null)
{
$this->parent = $parent;
return $this;
}
/**
* Get parent
*
* @return \Acme\Bundle\AdminBundle\Entity\ParentAlbums
*/
public function getParent()
{
return $this->parent;
}
}
Index.html.twig - table 头部部分:
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Sort</th>
<th>{{ 'views.index.actions'|trans({}, 'JordiLlonchCrudGeneratorBundle') }}</th>
</tr>
</thead>
crud 命令可以帮助您快速生成多个文件,但它并不是全部。 $parent 是指向另一个实体的指针。 crud 方法无法知道您要从此实体显示什么。假设 ParentAlbums 有一个 属性 '$name'。您可以通过稍微更改 index.html.twig 来非常简单地显示它:
<thead>
<tr>
<th>Id</th>
<th>Name</th>
<th>Parent</th>
<th>Sort</th>
<th>{{ 'views.index.actions'|trans({}, 'JordiLlonchCrudGeneratorBundle') }}</th>
</tr>
</thead>
<tbody>
{% for entity in entities %}
<tr>
<td>{{ entity.id }}</td>
<td>{{ entity.name }}</td>
<td>{{ entity.parent.name }}</td>
<td>{{ entity.sort }}</td>
<td>
<ul>
// actions here
</ul>
</td>
</tr>
{% endfor %}
</tbody>
这是 DoctrineCrudGenerator 的正常行为,因为生成器只使用 Doctrine\ORM\Mapping\ClassMetadataInfo::$fieldMappings
数组来生成 table,但是 ParentAlbum-ManyToOne 关联位于 Doctrine\ORM\Mapping\ClassMetadataInfo::$associationMappings
大批。所以它永远不会在 crud 生成中被识别。
为了演示可能的解决方案,我使用了 symfony-demo 应用程序的 Comment 实体:
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <fabien@symfony.com>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace AppBundle\Entity;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Validator\Constraints as Assert;
/**
* @ORM\Entity
*
* Defines the properties of the Comment entity to represent the blog comments.
* See http://symfony.com/doc/current/book/doctrine.html#creating-an-entity-class
*
* Tip: if you have an existing database, you can generate these entity class automatically.
* See http://symfony.com/doc/current/cookbook/doctrine/reverse_engineering.html
*
* @author Ryan Weaver <weaverryan@gmail.com>
* @author Javier Eguiluz <javier.eguiluz@gmail.com>
*/
class Comment
{
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private $id;
/**
* @ORM\ManyToOne(targetEntity="Post", inversedBy="comments")
* @ORM\JoinColumn(nullable=false)
*/
private $post;
/**
* @ORM\Column(type="text")
* @Assert\NotBlank(message="Please don't leave your comment blank!")
* @Assert\Length(
* min = "5",
* minMessage = "Comment is too short ({{ limit }} characters minimum)",
* max = "10000",
* maxMessage = "Comment is too long ({{ limit }} characters maximum)"
* )
*/
private $content;
/**
* @ORM\Column(type="string")
* @Assert\Email()
*/
private $authorEmail;
/**
* @ORM\Column(type="datetime")
* @Assert\DateTime()
*/
private $publishedAt;
public function __construct()
{
$this->publishedAt = new \DateTime();
}
/**
* @Assert\True(message = "The content of this comment is considered spam.")
*/
public function isLegitComment()
{
$containsInvalidCharacters = false !== strpos($this->content, '@');
return !$containsInvalidCharacters;
}
public function getId()
{
return $this->id;
}
public function getContent()
{
return $this->content;
}
public function setContent($content)
{
$this->content = $content;
}
public function getAuthorEmail()
{
return $this->authorEmail;
}
public function setAuthorEmail($authorEmail)
{
$this->authorEmail = $authorEmail;
}
public function getPublishedAt()
{
return $this->publishedAt;
}
public function setPublishedAt($publishedAt)
{
$this->publishedAt = $publishedAt;
}
public function getPost()
{
return $this->post;
}
public function setPost(Post $post = null)
{
$this->post = $post;
}
}
有 "normal" 列,如 id、content、authorEmail 和 publishedAt,以及一个与 Post 实体的 ManyToOne 关联。为此实体生成了以下元数据:
Doctrine\ORM\Mapping\ClassMetadata {#437
+name: "AppBundle\Entity\Comment"
+namespace: "AppBundle\Entity"
+rootEntityName: "AppBundle\Entity\Comment"
+customGeneratorDefinition: null
+customRepositoryClassName: null
+isMappedSuperclass: false
+isEmbeddedClass: false
+parentClasses: []
+subClasses: []
+embeddedClasses: []
+namedQueries: []
+namedNativeQueries: []
+sqlResultSetMappings: []
+identifier: array:1 [
0 => "id"
]
+inheritanceType: 1
+generatorType: 4
+fieldMappings: array:4 [
"id" => array:9 [
"fieldName" => "id"
"type" => "integer"
"scale" => 0
"length" => null
"unique" => false
"nullable" => false
"precision" => 0
"id" => true
"columnName" => "id"
]
"content" => array:8 [
"fieldName" => "content"
"type" => "text"
"scale" => 0
"length" => null
"unique" => false
"nullable" => false
"precision" => 0
"columnName" => "content"
]
"authorEmail" => array:8 [
"fieldName" => "authorEmail"
"type" => "string"
"scale" => 0
"length" => null
"unique" => false
"nullable" => false
"precision" => 0
"columnName" => "authorEmail"
]
"publishedAt" => array:8 [
"fieldName" => "publishedAt"
"type" => "datetime"
"scale" => 0
"length" => null
"unique" => false
"nullable" => false
"precision" => 0
"columnName" => "publishedAt"
]
]
+fieldNames: array:4 [
"id" => "id"
"content" => "content"
"authorEmail" => "authorEmail"
"publishedAt" => "publishedAt"
]
+columnNames: array:4 [
"id" => "id"
"content" => "content"
"authorEmail" => "authorEmail"
"publishedAt" => "publishedAt"
]
+discriminatorValue: null
+discriminatorMap: []
+discriminatorColumn: null
+table: array:1 [
"name" => "Comment"
]
+lifecycleCallbacks: []
+entityListeners: []
+associationMappings: array:1 [
"post" => array:19 [
"fieldName" => "post"
"joinColumns" => array:1 [
0 => array:6 [
"name" => "post_id"
"unique" => false
"nullable" => false
"onDelete" => null
"columnDefinition" => null
"referencedColumnName" => "id"
]
]
"cascade" => []
"inversedBy" => "comments"
"targetEntity" => "AppBundle\Entity\Post"
"fetch" => 2
"type" => 2
"mappedBy" => null
"isOwningSide" => true
"sourceEntity" => "AppBundle\Entity\Comment"
"isCascadeRemove" => false
"isCascadePersist" => false
"isCascadeRefresh" => false
"isCascadeMerge" => false
"isCascadeDetach" => false
"sourceToTargetKeyColumns" => array:1 [
"post_id" => "id"
]
"joinColumnFieldNames" => array:1 [
"post_id" => "post_id"
]
"targetToSourceKeyColumns" => array:1 [
"id" => "post_id"
]
"orphanRemoval" => false
]
]
+isIdentifierComposite: false
+containsForeignIdentifier: false
+idGenerator: Doctrine\ORM\Id\IdentityGenerator {#439
-sequenceName: null
}
+sequenceGeneratorDefinition: null
+tableGeneratorDefinition: null
+changeTrackingPolicy: 1
+isVersioned: null
+versionField: null
+cache: null
+reflClass: null
+isReadOnly: false
#namingStrategy: Doctrine\ORM\Mapping\DefaultNamingStrategy {#407}
+reflFields: array:5 [
"id" => null
"content" => null
"authorEmail" => null
"publishedAt" => null
"post" => null
]
-instantiator: Doctrine\Instantiator\Instantiator {#438}
}
可以看到,普通字段位于fieldMappings数组中,而关联位于associationMappings数组中。 运行 Comment 实体的 crud 生成器只为没有 post 关联的 "normal" 列生成 table:
<thead>
<tr>
<th>Id</th>
<th>Content</th>
<th>Authoremail</th>
<th>Publishedat</th>
<th>Actions</th>
</tr>
</thead>
现在,要更改此行为,您只需 "merge" 在生成 crud 时将 fieldMappings 数组中的 associationMappings 数组。
您可以在 Sensio\Bundle\GeneratorBundle\Generator\DoctrineCrudGenerator
中执行此操作。对于生产,您必须覆盖
Sensio\Bundle\GeneratorBundle\Generator\DoctrineCrudGenerator
和 Sensio\Bundle\GeneratorBundle\Command\GenerateDoctrineCrudCommand
并在您自己的 class 中进行更改。但是,作为概念证明,我将进行快速且非常肮脏的破解,并添加
直接对 DoctrineCrudGenerator 进行以下更改:
/**
* Generates a CRUD controller.
*
* @author Fabien Potencier <fabien@symfony.com>
*/
class DoctrineCrudGenerator extends Generator
{
// ...
/**
* Generates the index.html.twig template in the final bundle.
*
* @param string $dir The path to the folder that hosts templates in the bundle
*/
protected function generateIndexView($dir)
{
$this->renderFile(
'crud/views/index.html.twig.twig',
$dir . '/index.html.twig',
array(
'bundle' => $this->bundle->getName(),
'entity' => $this->entity,
'identifier' => $this->metadata->identifier[0],
// Use the function instead of the "raw" fieldMappings array
// 'fields' => $this->metadata->fieldMappings,
'fields' => $this->processFieldMappings(),
'actions' => $this->actions,
'record_actions' => $this->getRecordActions(),
'route_prefix' => $this->routePrefix,
'route_name_prefix' => $this->routeNamePrefix,
)
);
}
// ...
/**
* Add the associations to the array
*
* @return array
*/
protected function processFieldMappings()
{
/** @var \Doctrine\ORM\Mapping\ClassMetadata $metadata */
$metadata = $this->metadata;
$fields = $metadata->fieldMappings;
$associationMappings = $metadata->associationMappings;
foreach ($associationMappings as $k => $a) {
// Add the field only if it is a ToOne association and if the targetEntity implements the __toString method
if ($a['type'] & ClassMetadataInfo::TO_ONE && method_exists($a['targetEntity'], '__toString')) {
$fields[$k] = array(
"fieldName" => $a["fieldName"],
"type" => "text",
"scale" => 0,
"length" => null,
"unique" => false,
"nullable" => false,
"precision" => 0,
"columnName" => $k
);
}
}
return $fields;
}
}
更改后,如果您将 __toString 添加到 Post 实体,生成器会生成以下代码:
<table class="records_list">
<thead>
<tr>
<th>Id</th>
<th>Content</th>
<th>Authoremail</th>
<th>Publishedat</th>
<th>Post</th>
<th>Actions</th>
</tr>
</thead>
<tbody>
{% for entity in entities %}
<tr>
<td><a href="{{ path('comment_show', { 'id': entity.id }) }}">{{ entity.id }}</a></td>
<td>{{ entity.content }}</td>
<td>{{ entity.authorEmail }}</td>
<td>{% if entity.publishedAt %}{{ entity.publishedAt|date('Y-m-d H:i:s') }}{% endif %}</td>
<td>{{ entity.post }}</td>
<td>
<ul>
<li>
<a href="{{ path('comment_show', { 'id': entity.id }) }}">show</a>
</li>
<li>
<a href="{{ path('comment_edit', { 'id': entity.id }) }}">edit</a>
</li>
</ul>
</td>
</tr>
{% endfor %}
</tbody>
</table>
可以看到,post关联已经被识别了。如果你想开始写作,你可以以此为切入点 你自己的发电机。但是你必须调查,如何处理 ToMany 关联以及如何处理关联 表格等等..