Is there a syntax to separate some elements in a "for" tag please ?
For example I have a list of users, and I want to display their username with a "-" separator, so the expected result would be : Mickael - Dave - Chris - ...
I have found this solution :
{% for user in entity.users %}
{{ user.name }}{% if not loop.last %} - {% endif %}
{% endfor %}
But this is not very elegant. The join filter does not seem appropriate in a loop.
AFAIK, no, you can't use the join
filter for your use case without workarounds. This is because you need to pull getName
out of the object property. join
just link each element of the Traversable
instance with the given glue
.
There are however some workarounds if you need it.
In your User
entity, you can add a __toString
method to get the name of the user by default.
You should however take care if no other object are using the current default toString
as it may cause conflicts
namespace Acme\FooBundle\Entity;
class User
{
public function __toString()
{
return $this->getName();
}
}
Then you can use in your twig the join
filter
{{ entity.users|join(' - ') }}
In your controller, right before sending parameters to the view, you can map all the usernames for them to fit in an array.
Note: I assume getUsers
is a PersistentCollection
, if not, use array_map
instead
// Acme/FooBundle/Controller/MyController#fooAction
$users = $entity->getUsers();
$usernames = $users->map(function(User $user) {
return $user->getName();
});
return $this->render('AcmeFooBundle:My:foo.html.twig', array(
'entity' => $entity,
'usernames' => $usernames
);
Then in your twig
{{ usernames|join(' - ') }}
In your application, you can create a Twig Extension. In this example, I'll create a filter called joinBy
which will act like join
by specifying a method to join elements by.
Straight and easy, nothing too harsh but a standard declaration like in the docs
services.yml
acme_foo.tools_extension:
class: Acme\FooBundle\Twig\ToolsExtension
tags:
- { name: twig.extension }
@Acme\FooBundle\Twig\ToolsExtension
namespace Acme\FooBundle\Twig;
use Twig_Extension, Twig_Filter_Method;
use InvalidArgumentException, UnexpectedValueException;
use Traversable;
/**
* Tools extension provides commons function
*/
class ToolsExtension extends Twig_Extension
{
/**
* {@inheritDoc}
*/
public function getName()
{
return 'acme_foo_tools_extension';
}
/**
* {@inheritDoc}
*/
public function getFilters()
{
return array(
'joinBy' => new Twig_Filter_Method($this, 'joinBy')
);
}
/**
* Implode-like by specifying a value of a traversable object
*
* @param mixed $data Traversable data
* @param string $value Value or method to call
* @param string $join Join string
*
* @return string Joined data
*/
public function joinBy($data, $value, $join = null)
{
if (!is_array($data) && !($data instanceof Traversable)) {
throw new InvalidArgumentException(sprintf(
"Expected array or instance of Traversable for ToolsExtension::joinBy, got %s",
gettype($data)
));
}
$formatted = array();
foreach ($data as $row) {
$formatted[] = $this->getInput($row, $value);
}
return implode($formatted, $join);
}
/**
* Fetches the input of a given property
*
* @param mixed $row An array or an object
* @param string $find Property to find
* @return mixed Property's value
*
* @throws UnexpectedValueException When no matching with $find where found
*/
protected function getInput($row, $find)
{
if (is_array($row) && array_key_exists($find, $row)) {
return $row[$find];
}
if (is_object($row)) {
if (isset($row->$find)) {
return $row->$find;
}
if (method_exists($row, $find)) {
return $row->$find();
}
foreach (array('get%s', 'is%s') as $indic) {
$method = sprintf($indic, $find);
if (method_exists($row, $method)) {
return $row->$method();
}
}
if (method_exists($row, $method)) {
return $row->$method();
}
}
throw new UnexpectedValueException(sprintf(
"Could not find any method to resolve \"%s\" for %s",
$find,
is_array($row)
? 'Array'
: sprintf('Object(%s)', get_class($row))
));
}
}
You can now use it in your twig by calling
{{ entity.users|joinBy('name', ' - ') }}
# or
{{ entity.users|joinBy('getName', ' - ') }}
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