Display Hierarchical Data From Table In Twig Templ

2019-08-04 12:56发布

I am working with Symfony2 and Twig: I have a table that is set up to handle hierarchical data with Doctrine. It is a list of categories with parent->children->sub_children->sub_sub_children etc... Many many variations.

I am able to display them on the page like so, but the issue is there is no "indentation" to show which element belongs to what parent or child or child child etc etc.

 <table class="table" id="tableList">
            <thead>
            <tr>
                <th>Category Name</th>
            </tr>
            </thead>
            <tbody>
            {% for productCategory in productCategories %}
                <tr>
                    <td>{{ productCategory.name }}</td>
                </tr>
            {% endfor %}
            </tbody>
        </table>

I'd like the list to look something like this:

 Parent 
      Child
           Child
 Parent
      Child
 Parent
      Child
           Child
                Child

Instead of like this:

 Parent
 Child
 Child
 Child
 Parent
 Child
 Parent
 etc.
 etc.

Original Entity:

 <?php

 namespace WIC\ProductCategoryBundle\Entity;

 use Doctrine\ORM\Mapping as ORM;
 use Doctrine\Common\Collections\ArrayCollection;
 use Gedmo\Mapping\Annotation as Gedmo;
 use WIC\CommonBundle\DoctrineExtensions\Mapping\Annotation as Common;
 use Symfony\Component\Validator\Constraints as Assert;


 /**
  * ProductCategory
  *
  * @ORM\Table()
  * @ORM\Entity(repositoryClass="Gedmo\Tree\Entity\Repository\NestedTreeRepository")
  * @Gedmo\Tree(type="nested")
  * @Common\Loggable(logEntryClass="WIC\ProductCategoryBundle\Entity\ProductCategoryLog")
  * @Common\Accountable
  * @Gedmo\SoftDeleteable(fieldName="deletedAt")
  */
 class ProductCategory
 {
/**
 * @var integer
 *
 * @ORM\Column(name="id", type="integer")
 * @ORM\Id
 * @ORM\GeneratedValue(strategy="AUTO")
 */
private $id;

/**
 * @var string
 * @ORM\Column(name="name", type="string", length=255, nullable=false)
 * @Common\Versioned
 * @Assert\NotBlank(message="Location Name Cannot Be Left Blank.")
 */
protected $name;

/**
 * @Gedmo\TreeLeft
 * @ORM\Column(name="lft", type="integer")
 */
protected $lft;

/**
 * @Gedmo\TreeLevel
 * @ORM\Column(name="lvl", type="integer")
 */
protected $lvl;

/**
 * @Gedmo\TreeRight
 * @ORM\Column(name="rgt", type="integer")
 */
protected $rgt;

/**
 * @Gedmo\TreeRoot
 * @ORM\Column(name="root", type="integer", nullable=true)
 */
protected $root;

/**
 * @Gedmo\TreeParent
 * @ORM\ManyToOne(targetEntity="ProductCategory", inversedBy="children")
 * @ORM\JoinColumn(name="parent_id", referencedColumnName="id", onDelete="SET NULL")
 */
protected $parent;

/**
 * @ORM\OneToMany(targetEntity="ProductCategory", mappedBy="parent")
 * @ORM\OrderBy({"lft" = "ASC"})
 */
protected $children;

/**
 * @ORM\ManyToMany(targetEntity="WIC\ProductBundle\Entity\Product", mappedBy="productCategories", cascade={"persist"})
 */
protected $products;

/**
 * @ORM\ManyToOne(targetEntity="WIC\UserBundle\Entity\User")
 * @ORM\JoinColumn(name="created_by", referencedColumnName="id")
 * @Common\Blameable(on="create")
 */
private $createdBy;

/**
 * @ORM\ManyToOne(targetEntity="WIC\UserBundle\Entity\User")
 * @ORM\JoinColumn(name="updated_by", referencedColumnName="id")
 * @Common\Blameable(on="update")
 */
private $updatedBy;

/**
 * @ORM\ManyToOne(targetEntity="WIC\AccountBundle\Entity\Account", inversedBy="productCategorys", cascade={"remove","persist"})
 * @ORM\JoinColumn(name="account_id", referencedColumnName="id", nullable=false, onDelete="CASCADE")
 * @Common\Versioned
 * @Common\Blameable(on="create")
 */
protected $account;


/**
 * @var datetime $created
 *
 * @Common\Timestampable(on="create")
 * @ORM\Column(type="datetime")
 */
private $created;

/**
 * @var datetime $updated
 *
 * @Common\Timestampable(on="update")
 * @ORM\Column(type="datetime", nullable=true)
 */
protected $updated;

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


public function __construct()
{
    $this->products = new ArrayCollection();
}


/**
 * Get id
 *
 * @return integer 
 */
public function getId()
{
    return $this->id;
}

/**
 * Set name
 *
 * @param string $name
 * @return ProductCategory
 */
public function setName($name)
{
    $this->name = $name;

    return $this;
}

/**
 * Get name
 *
 * @return string 
 */
public function getName()
{
    return $this->name;
}


public function setLvl(ProductCategory $lvl = null)
{
    $this->lvl = $lvl;
}

public function getLvl()
{
    return $this->lvl;
}


public function setParent(ProductCategory $parent = null)
{
    $this->parent = $parent;
}

public function getParent()
{
    return $this->parent;
}

/**
 * Set account
 *
 * @param \WIC\AccountBundle\Entity\Account $account
 * @return User
 */
public function setAccount(\WIC\AccountBundle\Entity\Account $account = null)
{
    $this->account = $account;

    return $this;
}


/**
 * Get account
 *
 * @return \WIC\AccountBundle\Entity\Account
 */
public function getAccount()
{
    return $this->account;
}

/**
 * Add product
 *
 * @param \WIC\ProductBundle\Entity\Product $product
 * @return Product
 */
public function addProduct(\WIC\ProductBundle\Entity\Product $product)
{
    $this->products[] = $product;

    return $this;
}

/**
 * Remove product
 *
 * @param \WIC\ProductBundle\Entity\Product $product
 */
public function removeProduct(\WIC\ProductBundle\Entity\Product $product)
{
    $this->products->removeElement($product);
}

/**
 * Set products
 *
 * @return Product
 */
public function setProducts($products)
{
    $this->products = $products;

    return $this;
}

/**
 * Get products
 *
 * @return \Doctrine\Common\Collections\Collection
 */
public function getProducts()
{
    return $this->products;
}

/**
 * Set updated
 *
 * @param \DateTime $updated
 * @return User
 */
public function setUpdated($updated)
{
    $this->updated = $updated;

    return $this;
}

/**
 * Get updated
 *
 * @return \DateTime
 */
public function getUpdated()
{
    return $this->updated;
}

/**
 * Set deletedAt
 *
 * @param \DateTime $deletedAt
 * @return User
 */
public function setDeletedAt($deletedAt)
{
    $this->deletedAt = $deletedAt;

    return $this;
}

/**
 * Get deletedAt
 *
 * @return \DateTime
 */
public function getDeletedAt()
{
    return $this->deletedAt;
}

public function getOptionLabel()
{
    return str_repeat(
            html_entity_decode('&nbsp;', ENT_QUOTES, 'UTF-8'),
            ($this->getLvl() + 0 ) * 3
    ) . $this->getName();
}


}

Anyone know how to accomplish this?

Thanks so much!

2条回答
祖国的老花朵
2楼-- · 2019-08-04 13:16

Just a little upgrade to previous answer.

<ul>
{% for productCategory in productCategories %}
    {{ _self.display_tree(productCategory) }}
{% endfor %}
</ul>

{% macro display_tree(level) %}
    <li>{{ level.name }}
    {% if level.children|default() %}
        <ul>
        {% for child in level.children %}
            {{ _self.display_tree(child) }}
        {% endfor %}
        </ul>
    {% endif %}
    </li>
{% endmacro %}

This would build better-looking html.

查看更多
孤傲高冷的网名
3楼-- · 2019-08-04 13:38

The indentation will be much easier using an unordered list because they automatically get indented by the browser's default user-agent stylesheet. This should do it:

Add this method to your ProductCategory entity:

public function getChildren() {
    return $this->children;
}

and this in your twig template

{% for productCategory in productCategories %}
    {{ _self.display_tree(productCategory) }}
{% endfor %}

{% macro display_tree(level) %}
    <ul>
        <li>{{ level.name }}
        {% if level.children|default() %}
            {% for child in level.children %}
                {{ _self.display_tree(child) }}
            {% endfor %}
        {% endif %}
        </li>
    </ul>
{% endmacro %}
查看更多
登录 后发表回答