Я пытаюсь отобразить дерево ссылок, используя ассоциацию самоссылки Doctrine. У меня есть сущность вроде:
<?php
namespace App\Entity;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Table(name = "link")
* @ORM\Entity(repositoryClass = "App\Repository\LinkRepository")
*/
class Link
{
/**
* @ORM\Column(name = "link_id", type = "integer", nullable=false, options = {"unsigned"=true})
* @ORM\Id()
* @ORM\GeneratedValue(strategy = "IDENTITY")
*/
private $linkId;
/**
* @ORM\Column(name = "name", type = "string", length=50)
*/
private $name;
/**
* @ORM\Column(name = "url", type = "string", length=500)
*/
private $url;
/**
* @ORM\Column(name = "parent_id", type = "integer")
*/
private $parentId;
/**
* @ORM\OneToMany(targetEntity = "Link", mappedBy = "parent")
*/
private $children;
/**
* @ORM\ManyToOne(targetEntity = "Link", inversedBy = "children")
* @ORM\JoinColumn(name = "parent_id", referencedColumnName = "link_id")
*/
private $parent;
public function __construct()
{
$this->children = new ArrayCollection();
}
public function getLinkId(): ?int
{
return $this->linkId;
}
// Getters and setters ...
/**
* @return ArrayCollection
*/
public function getChildren()
{
return $this->children;
}
}
и в моем контроллере он извлекает ссылку и вызывает шаблон ветки, например:
public function link(int $linkId, LinkRepository $linkRepository)
{
$link = $linkRepository->findOneBy(['linkId' => $linkId]);
return $this->render('link.html.twig',
[
'link' => $link
]);
}
И шаблон ветки примерно такой:
{% extends 'base.html.twig' %}
{% block body %}
{{ link.name }}
<h2>Children:</h2>
{% import _self as macros %}
<ul>
<li>{{ link.name }}
{{ macros.link_tree(link) }}
</li>
</ul>
{% endblock %}
{% macro link_tree(link) %}
{% import _self as macros %}
<ul>
{% for linkChild in link.children %}
<li>
{{ link.name }}
{% if linkChild.children %}
<ul>
{{ macros.link_tree(linkChild.children) }}
</ul>
{% endif %}
</li>
{% endfor %}
</ul>
{% endmacro %}
Хотя когда я вызываю этот контроллер, он выдает мне эту ошибку:
Neither the property "children" nor one of the methods "children()", "getchildren()"/"ischildren()"/"haschildren()" or "__call()" exist and have public access in class "Doctrine\ORM\PersistentCollection".
Кажется, это происходит, когда я ссылаюсь на linkChild.children в шаблоне ветки.
Как я могу рекурсивно перебирать детей () в ветке?




Прежде всего, ваше сопоставление Doctrine неверно: вы должны удалить поле parentId, в нем нет необходимости, поскольку вы уже добавили соответствующую ассоциацию с полем parent.
Во-вторых, вы должны использовать Symfony ParamConverter, чтобы получить ссылку внутри контроллера следующим образом:
public function link(Link $link)
Да, это так просто, как кажется, вы можете получить ссылку, просто набрав переменную ссылки в своем действии контроллера, нет необходимости использовать там LinkRepository. Вы можете найти больше о ParamConverter здесь.
Наконец, похоже, проблема в ваших данных, потому что вы получили экземпляр коллекции Doctrine, когда ожидаете экземпляр класса Link. Попробуйте выполнить отладку, используя {{ dump() }} внутри вашего шаблона ветки, на данный момент недостаточно данных, чтобы помочь вам в этом. Но вам определенно следует сначала решить проблему с отображением, прежде чем пытаться снова.
Вот и получается, что я отправлял не то в макрос, он ждал linkChild, а я пропускал linkChild.children. Внутри макроса он пытался сослаться linkChild.children.children
Это было исправлено с помощью:
{{ link.name }}
{% if linkChild.children %}
<ul>
{{ macros.link_tree(linkChild) }}
</ul>
{% endif %}
Спасибо за совет. Я посмотрю на ParamConvertor. Отображение доктрины не было проблемой (я попытался удалить поле
parentId, и это не решило проблему). Я разместил свое решение ниже.