The course is built on Symfony 4, but the principles still apply perfectly to Symfony 5 - not a lot has changed in the world of relations!
// composer.json
{
"require": {
"php": "^7.1.3",
"ext-iconv": "*",
"composer/package-versions-deprecated": "^1.11", // 1.11.99
"doctrine/doctrine-bundle": "^1.6.10", // 1.10.2
"doctrine/doctrine-migrations-bundle": "^1.3|^2.0", // v2.0.0
"doctrine/orm": "^2.5.11", // v2.7.2
"knplabs/knp-markdown-bundle": "^1.7", // 1.7.0
"knplabs/knp-paginator-bundle": "^2.7", // v2.7.2
"knplabs/knp-time-bundle": "^1.8", // 1.8.0
"nexylan/slack-bundle": "^2.0,<2.2.0", // v2.0.0
"php-http/guzzle6-adapter": "^1.1", // v1.1.1
"sensio/framework-extra-bundle": "^5.1", // v5.1.4
"stof/doctrine-extensions-bundle": "^1.3", // v1.3.0
"symfony/asset": "^4.0", // v4.0.4
"symfony/console": "^4.0", // v4.0.14
"symfony/flex": "^1.0", // v1.21.6
"symfony/framework-bundle": "^4.0", // v4.0.14
"symfony/lts": "^4@dev", // dev-master
"symfony/twig-bundle": "^4.0", // v4.0.4
"symfony/web-server-bundle": "^4.0", // v4.0.4
"symfony/yaml": "^4.0", // v4.0.14
"twig/extensions": "^1.5" // v1.5.1
},
"require-dev": {
"doctrine/doctrine-fixtures-bundle": "^3.0", // 3.0.2
"easycorp/easy-log-handler": "^1.0.2", // v1.0.4
"fzaninotto/faker": "^1.7", // v1.7.1
"symfony/debug-bundle": "^3.3|^4.0", // v4.0.4
"symfony/dotenv": "^4.0", // v4.0.14
"symfony/maker-bundle": "^1.0", // v1.4.0
"symfony/monolog-bundle": "^3.0", // v3.1.2
"symfony/phpunit-bridge": "^3.3|^4.0", // v4.0.4
"symfony/stopwatch": "^3.3|^4.0", // v4.0.4
"symfony/var-dumper": "^3.3|^4.0", // v4.0.4
"symfony/web-profiler-bundle": "^3.3|^4.0" // v4.0.4
}
}
84 Comments
I had a question but it figured itself out.
Anyways, thanks for the great tutorials!!
Is it posible, and how to make infinite scroll with KnpPaginatorBundle
Hey sasa1007!
For sure! I mean, the implementation depends on what JavaScript library you're using, but it's absolutely possible. Infinite scroll works like this:
A) When you scroll a certain distance, an AJAX request is made to get the "next" results (e.g. the next 20 results)
B) When that AJAX request finishes, those results are added to the bottom of your list, so you can keep scrolling
Behind the scenes, this is no different than pagination. The only differences is that you're initiating pagination via a scroll event (instead of clicking a link) and you're putting the results on the bottom of the list instead replacing the current list.
So here's how it might work:
1) When you user scrolls to a certain point, you start the AJAX request. You would set some JavaScript variable that keeps track of the current "page" - 1 by default. First, increment that to 2. Then, make an AJAX request to an endpoint - e.g. /articles/{page}. This AJAX endpoint would read the page you're sending it and you would set up pagination like normal. You would then render a template and render the results (but without an "extends" - you just want the result, no the page template). Alternatively, you could return the "current results" as JSON.
2) You then read the data back, put it at the bottom of your "articles list" and increment the JavaScript "page" variable to 3. The next time they scroll down far enough, they would make an AJAX request to /articles/3.
Let me know if that makes sense!
Cheers!
Hi Ryan,
Thank you for your response.
I thought it would be easier.
Its html template that using https://infinite-scroll.com/
So on Infinite Scroll documentation they say that only need to Initialize it,
$('.container').infiniteScroll({
// options
path: '.pagination__next', // this is problem
append: '.post',
history: false,
});
it work when i hardcoded
http://localhost:8000/news/?page=2
but only for that page
Hey sasa1007!
Try something like this:
I know, this looks a little crazy :). According to their docs, to pass "path" a URL, you need to use the form "/news?page={{#}}" - and then the library will replace the <code{{#}}
part with whatever the next page number should be. So, above, I'm first printing the URL to the /news page using the path() function (replacenews_route_name` with your actual route name). Then I'm adding ?page={{#}}. However, because {{#}} looks like Twig code, this will cause a Twig error. That's why I actually use Twig to print this string - which looks totally weird, I realize :).The code you had before -
path: '.pagination__next'is also a valid way to do it - but for this to work, you need to ALWAYS have a link on the page with apagination__nextclass on it whose URL points to the next page URL (e.g. /news?page=3).Cheers!
Thanks,
It is not working with
$('.container').infiniteScroll({
path: '{{ path('news_route_name') }}?page={{ '{{#}}' }}',
append: '.post',
history: false,
});
but work with
$('.container').infiniteScroll({
path: '{{ path('news_route_name') }}?page={{ 0 }}',
append: '.post',
history: false,
});
One more time thank you for help
and one more thing he show all posts (news, never mind) until last one, but when I continue to scroll I get more and more ajax requests
.....
5342ad GET xhr 200 /vesti/?page=38 106ms
1430e4 GET xhr 200 /vesti/?page=39 103ms
580b47 GET xhr 200 /vesti/?page=40 108ms
20748a GET xhr 200 /vesti/?page=41 106ms
d9fca0 GET xhr 200 /vesti/?page=42 98ms
(endless)
.......
Hey sasa1007!
Awesome! Thank you for sharing your working solution :).
> and one more thing he show all posts (news, never mind) until last one, but when I continue to scroll I get more and more ajax requests
Hmm, I'm not sure about this. It seems like InfiniteScroll should be smart enough to realize when it has reached the final page (because the endpoint is returning 0 results) and stop making more requests. If there is a fix for this, it's probably something related to that JS library - it looks like you're doing everything correctly to me.
Cheers!
Thank you very much!
Hi
I'm trying to tidy up the url so that ?page=3 becomes /3/, is there anyway to do this?
Cheers
Steve
Hey Steve D.!
Yes, buuuuuut, maybe you don't want to do it :). Let me explain both parts:
1) To get a clean /3/ URL, change the Route to be
/admin/comment/{page}. I could be wrong, but if I remember correctly, the paginator will be smart enough to generate the URLs correctly by doing this.2) This is a FINE solution. However, if you later also want to add some filtering/searching, you'll probably do that by adding a ?q= to the end of the URL. If you ALSO try to put this into the URL, then suddenly things start to get a bit ugly - should you do /admin/comment/{search}/{page} or /admin/comment/{page}/{search}? In general, that's a bit why these are often put as query parameters. But also, what I'm saying is more true for APIs, where pretty URLs aren't important at all. So yes, in this case, making the URL is pretty - but I wouldn't do it in an API :).
Cheers! Oh, and let me know if I'm wrong about (1) and the paginator doesn't generate the URLs the way you want.
Hi Ryan
You're spot on, it does do that. I'm already using a search query (as in the video) and have the search parameter in the url which makes point 2 very valid, its not right. Plus, if I've navigated to a page then search for an item it fails to return the correct results. I've always used DataTables but with huge records the filter can be a bit of pain thus wanting to try Paginator
... Hold the front page...
I've changed the search term to be a post variable rather than get variable and if there is a search term present then the page number is reset to 1. I've also set a session var to store the search term so that it is not lost when navigating pages, this gets cleared when the reset is clicked or a new search term is used. Happy days.
Thanks again Ryan
Steve
Hey Steve D.
Using POST method for only fetching information is not right, a POST request is meant for updating the system, such as a record on the database, so you is better to use a GET request for this task and use query parameters to avoid storing data into the user's session
Cheers!
Very true Diego, and I've gone back to using GET in this instance but have an application that does store search queries so I guess POST would be applicable :)
Thank you for your assistance
Steve
It seems this is not going to work, there are issues with other actions in the controller as they match the route of index action. Never mind
All is working except my pagination labels for previous & next are : label_previous & label_next also on profiler bar I have 2 translation errors:
<br />en KnpPaginatorBundle 1 label_previous label_previous<br />en KnpPaginatorBundle 1 label_next label_next<br />so I was checking documentation and there is:
`
Troubleshooting
Make sure the translator is activated in your symfony config :
framework:
If your locale is not available, create your own translation file in app/Resources/translations/KnpPaginatorBundle.en.yml (substitute en for your own language code if needed) . Then add these lines:
label_next: Next
label_previous: Previous
`
but I dont want to break it so I will wait for translation screencast and then fix it.
Hey Peter K.
Don't be too afraid of playing around with Symfon :)
Look's like you only need to activate translations. If you are on Symfony4, you have even less work to do (thanks to Symfony Flex): http://symfony.com/doc/4.0/...
Cheers!
For beginners like me:
run "composer require symfony/translation"
then create file "translations/KnpPaginatorBundle.en.yaml"
paste there
<br />label_next: Next<br />label_previous: Previous<br />Then I had to run "php bin/console cache:clear"
That seems to do the trick and everything is sorted.
Oh, yes, whenever you create a new translation file you have to clear the cache. Thanks for sharing the steps!
Or at least, I think you may need to clear cache for the FIRST translation file - not sure for the 2nd and 3rd - Symfony *should* see those automatically.
I had to clear the cache as well, before it didn't work.
Shortcut:
./bin/console c:c
"Doctrine itself doesn't come with any pagination features."
"Doctrine\ORM\Tools\Pagination\Paginator" is there at least from 2013 (version 2.4).
It is very simple to compare with KnpPagination Bundle, but it is there.
This pure doctrine paginator is also used in the Symfony FastTrack book.
Hey Peter L.!
You're absolutely correct! The reason I typically use an extra library on top of that is because the Doctrine paginator doesn't make it easy to determine what the "next" page is (or if one is needed) or the previous page - the book calculates those manually. That's not a *huge* problem, but it's always felt better to have a library handle those things for me.
Cheers!
Hi, and want ask from another side. If we are using API Platform (currently it this time v2.6+) should we use somehow the pagination from it without that we will call api request ? Mean by use statement in controller of some part of Api Platfrom ?
Hey Miky!
You absolutely *can* choose to do this. But it's not SO easy (there is not one simply function you can call to re-use the paginator). In API Platform, they actually use the core Doctrine paginator. This is basically the logic here: https://github.com/api-plat...
They basically (A) create a QueryBuilder then (B) in a different part of the code they set the max results and limit https://github.com/api-plat...
But there are a few problems with this:
1) You can't just re-use the code from API Platform, you would be copying it.
2) The Doctrine paginator is very low-level: it's your job to look at the current page number and calculate the "offset" that should be used. It also gives you no help for generating things on the frontend (like next/prev links).
So... the answer is that... you "sort" of can re-use the paginator from ApiPlatform, but there is probably not aa huge advantage to doing so :).
Cheers!
I did the exact steps but adding bootstrap didn't work.
Hey @Farry7
What exactly not working? styling or HTML markup? do you have any errors in console?
Cheers!
I tried installing paginator and got this error. However, the pagination works (except bootstrap). I think the paginator was already installed with knp?
Script security-checker security:check returned with error code 1
!!
!! The web service failed for an unknown reason (HTTP 403).
!!
!!
Script @auto-scripts was called via post-update-cmd
Installation failed, reverting ./composer.json to its original content.
Hey @Farry7
I'd recommend you to remove
sensiolabs/security-checkerfrom you project, BTW this bundle is abandoned, and if you download fresh code for this tutorial you will not find it =)Cheers!
And what about https://www.doctrine-projec...
I think this tutorial have to be updated with provided reference because it out of date.
Hey rtwent,
That is native Doctrine pagination, so that's a different thing. Yes, both solves pagination problem, but in this video we use a third-party bundle for this called knplabs/knp-paginator-bundle . It already has more features and easier to use than Doctrine pagination. Doctrine pagination is kinda low-level thing and you need to do more work to get things work with it, so KnpPaginatorBundle is easier to use and more powerful - you can think about it as a wrapper around native Doctrine pagination. But in case you don't want to install more bundles in your project - yes, you can take a look at that Doctrine pagination, it already provides with Doctrine library, their docs are pretty good on it, so you can easily start with it, though still will need to do more work to get things work as they works in KnpPaginatorBundle.
That's why this tutorial is not out of date and still relevant :)
Cheers!
Hi,
for me the templates do not work. I see the pagination links at the bottom but no matter which template I choose in knp_paginator.yaml: no changes on the output.
Any hints for me??
Thx
Aaaargh, it was the cache. Clearing the cache and it works.
hehehe it happens!
I was wondering if anyone has figured out a simple way of getting the pagination autocomplete work for both the pagination and getItems() being interpreted as an array of the objects being paginated in a Twig template.
At the moment, what I'm doing is this:
And then I pass both variables to the Twig template:
If you only pass the PaginationInterface to the Twig template, you'd only be able to get PhpStorm (other IDEs probably too) autocomplete working for the PaginationInterface object, but you won't get the autocomplete for the $replacementAds array (or whatever array of object you are paginating).
Any room for improving / simplifying this code?
P.S. If you copy some text in the textarea of the comments box, it just ads several lines/break lines in each paragraph of your comment. Making it REALLY hard to copy paste anything (like code snippets). This is at least happening in Firefox (latest) in Linux.
Hey Carlos,
Hm, nothing much we can do here probably, especially if you want to autocomplete getItems() for different entities. Probably your solution is the best you can do. The next improvement would be to write a plugin for PhpStorm (or add support of KnpPaginatorBundle to Symfony Plugin) that will help with autocomplete. But that's complex and really the next level. So, I'd recommend you to stick to your workaround, or if you really curious about it - try to figure out how to write your custom PhpStorm plugin for this.
> P.S. If you copy some text in the textarea of the comments box, it just ads several lines/break lines in each paragraph of your comment. Making it REALLY hard to copy paste anything (like code snippets). This is at least happening in Firefox (latest) in Linux.
Yeah, I also noticed this problem, that's so annoying, not sure when Disqus will fix it for Firefox. As a workaround for this - use Google Chrome, it works great for copy/pasting :)
I hope this helps!
Cheers!
Thanks for the quick reply :) That's what I thought, but wanted to reassure I wasn't overkilling or making things hard.
Most of the times, I implement the twig template without pagination at first, so it doesn't bother much. But when you come back to that template and try to add more fields or display more information from the paginated objects, it becomes annoying.
Will keep with my way then. Cheers!
Hey Carlos,
Yeah, I see, it would be cool to have full autocompletion, but unfortunately. Though your workaround is good and simple I think :) Thanks for sharing it with others!
Cheers!
Hi, I want to know how did the terminal search box come out?
Hey Lothar,
Good question! Usually, if you're on a Mac, it works by pressing Cmd + F - it's a general shortcut for search. Same should work in your browser. On Windows/Linux try Ctrl + F.
And you always can find how to search in app menu, like in your terminal app menu. For me it's "Edit" -> "Find" -> "Find..." item in the menu, and it also shows its shortcut there.
I hope this helps!
Cheers!
Hey i get this error when trying to show the pages
''There are no registered paths for namespace "KnpPaginator".'
Anyone else having this Problem ?
Hey Robert
Is it possible that you forgot to register the bundle? If you are on Symfony4+ it should be done automatically
Hey the Bundle is registered as so Knp\Bundle\PaginatorBundle\KnpPaginatorBundle::class => ['all' => true],
Hey Roby,
Hm, could you clear the cache and try again? If you still have this issue - most probably the problem with versions. Please, take a look at this thread, you will find a workaround at the end that should help: https://github.com/KnpLabs/...
Cheers!
For Symfony 5, use the Doctrine Paginator https://www.doctrine-projec... - Fabien's book (section 10.6 Paginating the Comments) has the example which matches this chapter fairly closely.
Hey Edward B.!
I like the Doctrine paginator too - it's something powerful and relatively easy that you get out-of-the-box. I *do* wish that I could pass it the "max per page" and "page number" instead of needing to calculate the limit & the offset - that would give me the extra "developer experience" that I crave with it. But that's ultimately a minor detail - I also used it recently for something.
Cheers!
That brings out a question - suppose I created a wrapper for the Doctrine paginator which DOES translate limit/offset because it's something I do a lot. Where would you put it? I suppose if there were many such wrappers (three or more), put them in a separate folder; but until then put them in the Repository folder since they're query-related?
Hey Ed,
You might be interested to look at implementation of Paginator in Symfony Demo that is based on Doctrine paginator :)
https://github.com/symfony/...
Cheers!
Yea, that's a good question. My instinct is that I'd create a
PaginatorFactoryclass. We would pass it the QueryBuilder and then it would set the limit/offset stuff. Something like:For the QueryBuilder itself, that should live in some repository. So the code that uses this would look something like:
There are certainly other valid ways of doing it - but that's probably what I would do :).
Cheers!
Oh, boy! Watch out for using PaginatorInterface and not PaginationInterface! :D Took me awhile to figure it out... (sigh). I knew something was fishy when Storm said there's no paginate() method...
Hey Payskin,
Nice tip! :) Yep, you always should look closer to the namespaces you use in PhpStorm, some of them very similar and better to double check you use the correct namespace because it's easy to mess things up on this stage.
Cheers!
"Houston: no signs of life"
Start the conversation!