Symfony2 / Twig dealing with getting URL query string values - symfony

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.

Related

symfony createQueryBuilder leftjoin with certain selected fields

I made a query for selecting certain fields together with a leftjoin.
However I cannot get it to work both at the same time (have a leftjoin and certain selected fields).
$query = $em->getRepository(Product::class)
->createQueryBuilder('p')
->select('p, p.slug, p.price, p.title_x AS title, pc')
->leftJoin('p.productimgs', 'pc')
->getQuery();
I call the array with
{% for item in article.productimgs %}
but i get the error: Key "productimgs" for array with keys "0, slug, price, title" does not exist
I also tried to call it with the function
{% for item in article.getProductimgs() %}
but then i get this error : Impossible to invoke a method ("getProductimgs") on an array.
I am not so good with doctrine / query building.
The productimages is a onetomany relation in the product entity.
it's a symfony 5 project
All help appreciated, thank you!
Since you are mixing the entities and specific columns in the select the hydrated results will actually be arrays and not Products. You can see it's structure with
{{ dump(article) }}
If you just want to eager load the related product images in the one query use
$query = $em->getRepository(Product::class)
->createQueryBuilder('p')
->select('p, pc')
->leftJoin('p.productimgs', 'pc')
->getQuery();
This will hydrate the results as Products so you can access its properties by the Twig shorthands or as functions:
{{ article.slug }}
{{ article.getSlug() }}
If you access the Product's images it will not execute a new database query to fetch them since you added them to the select part and they were already hydrated into the result objects:
{{ article.productimgs }}
{{ article.getProductimgs() }}

How to use {% for in %} symfony?

My problem that when i use the loop , the data inside don't show up ,
this is the code here im using the loop even " mes boutiques " dont show, , only "shirts & tops" show up
and this function where im calling this template in the controller
Your function affichDQL() must have a problem, you should test the result in your controller with dump($enseignes); to see if you haves results. You can add an check in your twig too with {% dump(enseignes) %}
Your template looks ok. The problem probably is in the repository method that probably return the DQL: a string representing the query in Doctrine.
I suspect you have a method like this in your entity method:
// retrieve the DQL string of what was defined in QueryBuilder
$dql = $qb->getDql();
So you need to replace with something like this:
// retrieve the associated Query object with the processed DQL
$query = $qb->getQuery();
// Execute Query
$result = $query->getResult();
return $result;
Hope this help

How to retrieve translation of a "sub entity" using Symfony a2lix knp doctrine behaviors translatable

I'm new in symfo but I need to translate content of my site.
I'm using a2lix (last version) and KNP doctrine behaviors (Translatable).
Let's say that I have 2 entities (e.g. Articles and Categories).
As in the doc (https://github.com/KnpLabs/DoctrineBehaviors) for translations, I'm using 2 classes for Categories (Category and CategoryTranslation).
To retrieve the translations, of my category, I'm using a query with the locale. I get the locale with Request $request ($locale = $request->getLocale();). Here is an example of my controller and the query in my repository.
Controller
public function indexAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$locale = $request->getLocale();
$entities = $em->getRepository('AcmeBundle:Category')->findAllByLocale($locale);
return $this->render('CTCArtworkBundle:Backend/Artwork:index.html.twig', array(
'entities' => $entities,
));
}
Repository
I'm trying to retrieve informations for the locale.
public function findAllByLocale($locale){
return $this->createQueryBuilder('a')
->join('a.translations', 'aTrans')
->where('aTrans.locale = :locale')
->setParameter("locale", $locale)
->addSelect('aTrans')
->getQuery()
->getResult()
;
}
I don't know if it's a good practice but it works for me. I retrieve fr/en categories in my Twig template like so when I change the url :
<tr>
<th>Category</th>
<td>{{ category.translations|First.name }}</td>
</tr>
My problem
For the translation of my article, I do the same. I have 3 properties
- title
- description
- category (I'm using a2lix_translatedEntity (http://a2lix.fr/bundles/translation-form/#bundle-additional))
When I try to render a record of Article, I never retrieve the translation for my category Name but well for title and description.
I also read that (https://github.com/KnpLabs/DoctrineBehaviors#guess-the-current-locale) but I don't really understand. Is that a way to always pass locale ?
What am I doing wrong ?
I'm blocked and don't find any documentation to resolve my problem. Sorry for my english ;-)
Any help would be very appreciate. Many Thanks
KNP has its own way to guess the current locale, simply by accessing current request scope. The whole "passing locale" thing is useful if you want to pull records for specific locale.
Now, for your category translation. Since you did not include your entities, I will try to show you some examples to access your translations.
In your Category entity, lets say you have a property name that would return your category name. Then you can define a simple helper method that would return that name, by current locale:
public function getName() {
if( $name == $this->translate()->getName() ) {
return $name;
}
return '';
}
So, what have we done here?
$this->translate()->getName() - this line looks for your translation entity (in this case that would be CategoryTranslation) and invokes method getName() . Then, we either return translated category name, or an empty string if no translation has been added.
And lastly, this is how you can access your category name in your twig template:
Since we defined our helper method, there is no longer any need to access .translations in your template. You can simply call:
{{ category.name }}
Hope you got the idea.
And you can also use this
{{ category.translate.name }}
With DoctrineBehaviors v2, you can add this to your Category class:
public function __call($name, $arguments)
{
return $this->proxyCurrentLocaleTranslation($name, $arguments);
}
Here's what it does. So, in your Category entity, lets say you have a property description that would hold your category description. The code above will generate a corresponding property getter: getDescription(). Which ultimately will allow you to use this property in your Twig template:
{{ category.description }}

How to use custom repository methods in Twig template?

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.

Twig date difference

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

Resources