I've got an entity with a starting date and an ending date.
Is it possible to get the difference in time between them by using twig?
Since PHP 5.3 There is another option without to write an extension.
This example show how to calc the plural day/days
{# endDate and startDate are strings or DateTime objects #}
{% set difference = date(endDate).diff(date(startDate)) %}
{% set leftDays = difference.days %}
{% if leftDays == 1 %}
1 day
{% else %}
{{ leftDays }} days
{% endif %}
Explanation:
PHP 5.3 DateTime object has diff() method which return a DateInterval object with the result difference between endDate and beginDate
Twig
Twig date function always return a DateTime object so we can call diff method
Finally we can access to the properties of the DateInterval object or format it with the Twig date filter.
Note: There is no need of wrap endDate or startDate with the date function if the variable is already a DateTime object.
Note2: DateTime is used here as a synonym of DateTimeInterface.
There's no built-in function to do that, but you can easily do it yourself, extending twig is easy!
The quick'n'easy way is to do it with twig's simple function class:
$function = new Twig_SimpleFunction('date_difference', function ($start, $end) {
// ... calculate difference and return it
});
// assuming $twig is an instance of Twig_Environment
$twig->addFunction($function);
The reusable way is to create a twig extension (documented on the same link). That's still easy.
Also note there is an existing Date extension from Sensio Labs that offer a time_diff filter.
Then you can use it like this:{{ entity.ending_date|time_diff(entity.starting_date) }}
Please note that this plugin is abandonned and not supported with Twig 3 : https://packagist.org/packages/twig/extensions
For Symfony 5, I recommand using the KnpTimeBundle
it provides the twig function |ago
To install : composer require knplabs/knp-time-bundle
Related
Is there a more elegant way of checking if a variable in Twig is both defined (safe to reference/use) and also check the boolean value of as I am doing below?
I have a number of Twig templates which have messy logic in it like this and i'd rather it was more readable, however I don't know how this is done in Twig.
{% if primaryMethod is defined and paymentInProgress is defined and transactions is defined and not primaryMethod and not paymentInProgress and not transactions %}
You could write your own test to reduce the amount of Twig code you need.
This is fairly simple to do and just requires 2 steps:
First register your test in twig (either directly or use the method getTests in your twig extension
$twig->addTest(new \Twig_SimpleTest('false', null, [ 'node_class' => '\MyProject\Twig\Node\FalseExpressionNode' ]));
Create the test
<?php
namespace MyProject\Twig\Node;
class FalseExpressionNode extends \Twig_Node_Expression_Test_Defined {
public function compile(\Twig_Compiler $compiler)
{
$compiler->subcompile($this->getNode('node'))
->raw('&& $context[\''.$this->getNode('node')->getAttribute('name').'\'] === false');
}
}
Then you could use your test inside twig
{% if primaryMethod is false and paymentInProgress is false and transactions is false %}
sidenote : The test FalseExpressionNode is extending from Twig_Node_Expression_Test_Defined in order to suppress any undefined variables messages when twig is in debug mode
I am using translatable
It can handle the data directly depending on the current locale setting.
However I want to access each data sometimes with ignoring locale setting.
in contoroller.
I can access each data like this.
$transRepo = $em->getRepository('Gedmo\Translatable\Entity\Translation');
$repo = $transRepo->findTranslations($myEntity);
var_dump($repo['en']['comment']);
Then, is there any way to fetch each language data in twig??
{{comment}} // it shows the comment depending on the locale setting.
{{comment | trancelate(en)}} // I want to ignore the locale setting like this.
How about passing the translations to your Twig template since you need to show them:
$translations = $repository->findTranslations($article);
And then in your Twig template you could do something like:
{{ translations.en.comment }}
{{ translations.de.comment }}
{{ translations.fr.comment }}
The official documentation might help.
How can I insert new \Datetime() jj-mm-aaaa format with Symfony2 ? or if is it impossible how to show it in this format in Twig N
What about using the Date Twig Filter,
{{ yourDateTimeObject|date("d-m-Y") }}
Assuming I have an entity User and an entity Book and they're both joined by User.bookId = Book.id (this marks a user owns a certain book, relation type oneUserToManyBook).
If I now want to execute a performance friendly fetch with Doctrine's DQL or QueryBuilder for all Books a User has read, what is the best way to implement this in a Symfony2/Doctrine2 webapp, so that I can use them in my User loop in a Twig template?
Twig
{% for user in users %}
{{ user.name|e }}
{% for address in user.getAddressesByUserId(user.getId()) %}
{{ address.city }}
{% endfor %}
{% endfor %}
I see two approaches, but both don't lead to my target:
1st approach
Create a custom repository class BookRepository:
public function getBooksOwnedByUser($user_id) {
return $em->createQuery('SELECT b.title
FROM MyBundle\Entity\User u,
MyBundle\Entity\Book b
WHERE u.book_id = b.id'
AND u.id = :user_id)
->setParameter('user_id', $user_id)
->getResult();
}
Problem: Works fine, but I cant call getBooksOwnedByUser() in my Twig template (because it's not tied to the entity User, but to it's repository, which is a subclass of Doctrine\ORM\EntityRepository.
2nd approach
Execute the same query as above - not in my UserRepository, but directly in my User entity class.
Problem here: I could call this method in my Twig template, but I cannot (and should not) use the EntityManager in my User entity class.
It's best if you make a relationship from User to Books. Assuming you have made this relationship you can make your query like this:
public function getBooksOwnedByUser($user_id) {
return $em->createQuery('SELECT u, b
FROM MyBundle\Entity\User u
JOIN u.books b
WHERE u.id = :user_id')
->setParameter('user_id', $user_id)
->getResult();
}
Then in your controller:
$em = $this->getDoctrine()->getManager();
$user_with_books = $em->getRepository('MyBundle\Entity\User')
->getBooksOwnedByUser($user->getId());
return $this->render('YourTemplate.html.twig', array(
'user_with_books' => $user_with_books,
));
In twig:
{% for book in user.books %}
{{ book.title }}
{% endfor %}
Some considerations:
For multiple users you will have to change the query (lazy loading is possible but not advised).
If it's a lot of data you can get a performance boost by getting a scalar result (Array)
If you need different queries for the user that can not be combined you will have to store different variables (objects or arrays). That's why I named it "user_with_books". But if you only have this user in your template you can just as well call it "user".
user.getAddressesByUserId(user.getId()) <-- passing data from one model to query is the responsiblity of the controller (or a service). Best practice is to avoid doing this in your template.
So the answer:
You can not do anything with a custom repository method because it's a function. A function on itself doesn't represent any data. So this is a way you can retrieve the actual data with that function and display that.
I'm trying to manipulate the query string values in a URL.
I can get the current URL or route either from the Request object or Twig's functions, but it's the query string I'm struggling with.
I don't need app.request.attributes.get('_route_params') as this gets the query string params that are in the route.
I need to get query string params that are actually in the URL.
I want to be able to do the two things listed below in both Symfony2 (in a PHP controller) and Twig (in a Twig template):
Get all current query string values in the URL and display them
Do 1, but change one of the query string values before displaying them
I can't find anyone who knows how to do this.
You can use app.request.query.all to get your query strings.
If you want to change a param in Twig you can do this
{% set queryParams = app.request.query.all %}
{% set queryParams = queryParams|merge({queryKey: newQueryValue}) %}
To get the query string "https://stackoverflow.com?name=jazz"
{{ app.request.query.get('name') | default('default value if not set'); }}
Into controller
use Symfony\Component\HttpFoundation\Request;
public function fooAction(Request $request)
{
$params = $request->query->all();
}
please, pay attention: $request->query->all(); will return an array with keys named as query parameters
Into twig
As long you pass from controller (read this as always) you can pass your parameters to a view in that way
use Symfony\Component\HttpFoundation\Request;
public function fooAction(Request $request)
{
$params = $request->query->all();
return $this->render('MyFooBundle:Bar:foobar.html.twig', array('params' => $params));
}
Into your twig template foobar.html.twig you can access all query string parameters simply by using the params variable.
e.g with this request URL: http://example.com/?foo=bar&secondfoo=secondbar
{% for paramName, paramValue in params %}
<div>{{ paramName }}: {{ paramValue }}</div>
{% endfor %}
<div>{{ params.secondfoo }}</div>
twig output:
<div>foo: bar</div>
<div>secondfoo: secondbar</div>
<span>secondbar</span>
Another method is to use app.request.query.all in twig, without passing anything to twig from your controller.
Final note
If you want to modify one of those parameters when passing an array to twig from your controller, simply change one of the array values, as you would with normal values (i.e.: $params['id'] = $params['id'] - 1;)
Hi Stephen we have tried ur solution to get the value but it going to default value.
http://localhost:4000/about/investors/key-dates-and-events-details?year=2017#q1
i have used like this on my twig file
{{ app.request.query.get('year') | default('default value if not set'); }} Quareter Q1
Please let me know.