Here is my Message entity. It is a class that defines messages between users in my app.
class Message
{
/**
* @var integer
*
* @ORM\Column(name="id", type="integer")
* @ORM\Id
* @ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* @var string
* @Assert\NotBlank(message="private_message.title.blank")
* @ORM\Column(name="title", type="string", length=50)
*/
protected $title;
/**
* @Assert\NotBlank(message="private_message.receiver.blank")
* @ORM\ManyToOne(targetEntity="MedAppBundle\Entity\User")
* @ORM\JoinColumn(referencedColumnName="id")
*/
protected $receiver;
/**
* @ORM\ManyToOne(targetEntity="MedAppBundle\Entity\User")
* @ORM\JoinColumn(referencedColumnName="id")
*/
protected $sender;
/**
* @var string
* @Assert\NotBlank(message="private_message.content.blank")
* @ORM\Column(name="content", type="string")
*/
protected $content;
/**
* @var \DateTime
*
* @ORM\Column(name="sentAt", type="datetime")
*/
protected $sentAt;
/**
* @var boolean
*
* @ORM\Column(name="isSpam", type="boolean")
*/
protected $isSpam = false;
/**
* @var \DateTime
*
* @ORM\Column(name="seenAt", type="datetime",nullable=true)
*/
protected $seenAt = null;
/**
* @ORM\ManyToOne(targetEntity="PrivateMessageBundle\Entity\Message")
* @ORM\JoinColumn(referencedColumnName="id",nullable=true)
*/
protected $replyof;
/**
* @ORM\OneToMany(targetEntity="PrivateMessageBundle\Entity\Message", mappedBy="replyof")
**/
private $replies;
public function __construct() {
$this->replies = new ArrayCollection();
}
What's important to note is the replyof
variable, which tells what message is a parent of the message. If it's NULL, then the message is not a reply, it's a parent message(a root).
And the messages
variable, which is an array of Messages that are replies to the message. These replies can have replies, themselves. This array can also be NULL, for leaf nodes, because they don't have any reply.
All the other variables contain just some fields that define an actual message between two users.
What I am trying to do is display in Twig all of my messages in an arborescent format, like so:
message1 - root message, reply of none, but has replies
reply1 - first reply of message 1
reply1 first reply of reply 1 of message 1, leaf with no further replies
reply2 - second reply of message 1, leaf with no further replies
message2 - root message, no replies and a reply of none
The problem is that Twig only supports foreach
loops and I'm not sure how to display this format when it has a higher depth, bigger than two.
{% for reply in message.replies %}
<li> sent by: {{ reply.sender }} </li>
<li> title: {{ reply.title }} </li>
<li> content: {{ reply.content }} </li>
<li> date: {{ reply.sentAt|date('d-m-Y H:i:s') }} </li>
<hr>
{% endfor %}
This will display every reply of a message, but how can I display nested messages, in full depth?
I didn't tested it by you should be able to loop over replies:
{% for reply in message.replies %}
{% if loop.first %}<ul>{% endif %}
<li> sent by: {{ reply.sender }} </li>
<li> title: {{ reply.title }} </li>
<li> content: {{ reply.content }} </li>
<li> date: {{ reply.sentAt|date('d-m-Y H:i:s') }} </li>
{% for reply in reply.replies %}
{% if loop.first %}<li><ul>{% endif %}
<li> sent by: {{ reply.sender }} </li>
<li> title: {{ reply.title }} </li>
<li> content: {{ reply.content }} </li>
<li> date: {{ reply.sentAt|date('d-m-Y H:i:s') }} </li>
{% if loop.last %}</ul></li>{% endif %}
{% endfor %}
{% if loop.last %}</ul>{% endif %}
{% endfor %}
It will display only 2 levels of replies. You can use a Twig macro to define a reusable function that should recursively display replies:
{# define the macro #}
{% macro displayReply(reply) %}
<li> sent by: {{ reply.sender }} </li>
<li> title: {{ reply.title }} </li>
<li> content: {{ reply.content }} </li>
<li> date: {{ reply.sentAt|date('d-m-Y H:i:s') }} </li>
{% for reply in reply.replies %}
{% if loop.first %}<li><ul>{% endif %}
{{ displayReply(reply) }}
{% if loop.last %}</ul></li>{% endif %}
{% endfor %}
{% endmacro %}
{# use the macro #}
{% for reply in message.replies %}
{% if loop.first %}<ul>{% endif %}
{{ displayReply(reply) }}
{% if loop.last %}</ul>{% endif %}
{% endfor %}
Depending on your query, it may display replies in the wrong order, you may need to sort replies in descending order in your query.
You can do a recursive approach as follow:
in the main twig, you print the main message, and iterate recursively in a partial as follow:
## main twig
Root message:
<ul>
<li> sent by: {{ message.sender }} </li>
<li> title: {{ message.title }} </li>
<li> content: {{ message.content }} </li>
<li> date: {{ message.sentAt|date('d-m-Y H:i:s') }} </li>
{{ include('AcmeDemoBundle:Message:_elem.html.twig', {'replies': message.replies ) }}
</ul>
and
## AcmeDemoBundle:Message:_elem.html.twig
<ul>
{% for reply in replies %}
<li> sent by: {{ reply.sender }} </li>
<li> title: {{ reply.title }} </li>
<li> content: {{ reply.content }} </li>
<li> date: {{ reply.sentAt|date('d-m-Y H:i:s') }} </li>
{{ include('AcmeDemoBundle:Message:_elem.html.twig', {'replies': reply.replies ) }}
{% endfor %}
</ul>
hope this help
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With