Đây là hành vi bình thường của DoctrineCrudGenerator, bởi vì các máy phát điện chỉ sử dụng các mảng Doctrine\ORM\Mapping\ClassMetadataInfo::$fieldMappings
để tạo bảng, nhưng các ParentAlbum-ManyToOne liên kết nằm trong mảng Doctrine\ORM\Mapping\ClassMetadataInfo::$associationMappings
. Vì vậy, nó sẽ không bao giờ được công nhận trên thế hệ crud.
Để chứng minh một giải pháp khả thi tôi sử dụng thực sự Comment của ứng dụng symfony-demo:
<?php
/*
* This file is part of the Symfony package.
*
* (c) Fabien Potencier <[email protected]>
*
* 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 <[email protected]>
* @author Javier Eguiluz <[email protected]>
*/
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;
}
}
Có cột "bình thường" như id, nội dung, AUTHOREMAIL và publishedAt và hiệp hội một ManyToOne đến bài viết thực thể. Đối với thực thể này, siêu dữ liệu sau được tạo:
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}
}
Bạn có thể thấy, các trường thông thường nằm trong mảngMục điều khiển, trong khi liên kết nằm trong mảng liên kếtMẫu. Chạy máy phát điện crud cho đơn vị Comment sản xuất bàn duy nhất cho các cột "bình thường" mà không có bài liên quan:
<thead>
<tr>
<th>Id</th>
<th>Content</th>
<th>Authoremail</th>
<th>Publishedat</th>
<th>Actions</th>
</tr>
</thead>
Bây giờ, để thay đổi hành vi này, bạn chỉ cần phải "hợp nhất" mảng associationMappings trong fieldMappings mảng trên thế hệ crud. Bạn có thể làm điều đó trong số Sensio\Bundle\GeneratorBundle\Generator\DoctrineCrudGenerator
. Để sản xuất, bạn phải ghi đè lên Sensio\Bundle\GeneratorBundle\Generator\DoctrineCrudGenerator
và Sensio\Bundle\GeneratorBundle\Command\GenerateDoctrineCrudCommand
và thực hiện thay đổi trong lớp học của riêng bạn. Nhưng cũng giống như một bằng chứng của khái niệm tôi sẽ làm nhanh chóng và thực sự bẩn hack, một thêm thay đổi sau vào DoctrineCrudGenerator trực tiếp:
/**
* Generates a CRUD controller.
*
* @author Fabien Potencier <[email protected]>
*/
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;
}
}
Sau những thay đổi và nếu bạn thêm __toString để đơn vị Bưu chính, máy phát điện tạo mã sau:
<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>
Bạn có thể thấy, liên kết bài đăng được nhận dạng ngay bây giờ. Bạn có thể sử dụng điểm này làm điểm nhập nếu bạn muốn bắt đầu viết trình tạo của riêng bạn. Nhưng bạn phải điều tra, cách xử lý các hiệp hội ToMany và cách xử lý các liên kết ở các dạng và v.v ..
Phải có 3 trường: tên, sắp xếp, cấp độ gốc. Trường gốc không được tạo. –
symfony crud generateor lệnh: php app/giao diện điều khiển: tạo: crud --entity = AdminBundle: Album --route-prefix = admin/album --with-write --format = chú thích --không tương tác - ghi đè –