Buy
Buy

With a Subscription, click any sentence in the script to jump to that part of the video!

Login Subscribe

On production - because The SpaceBar is going to be a huge hit with a lot of thoughtful comments - this list will eventually become, way long. Not only will this page become hard to use, it will quickly slow down until it stops working. If you ever need to query and render more than 100 Doctrine entities, you're going to have slow loading times. If you try to print 1000, your page probably just won't load.

But no problem! Printing that many results is a total bummer for usability anyways! And that's why the Internet has a tried-and-true solution for this: pagination. Doctrine itself doesn't come with any pagination features. But, it doesn't need to: there are a few great libraries that do.

Search for KnpPaginatorBundle. As usual, my disclaimer is that I did nothing to help build this bundle, I just think it's great. Find the composer require line, copy that, go to your terminal and paste:

composer require knplabs/knp-paginator-bundle

While that's installing, go back to its documentation. As I love to tell you, over and over again, the main thing a bundle gives you is new services. And that's 100% true for this bundle.

But before we talk more about that, notice that this has some details about enabling your bundle. That happens automatically in Symfony 4 thanks to Flex. So, ignore it.

Paginator Usage and the Autowiring Alias

Anyways, look down at the Usage example. Hmm, from a controller, it says to use $this->get('knp_paginator') to get some paginator service. Then, you pass that a query, the current page number, read from a ?page query parameter, and the number of items you want per page. The paginator handles the rest! If you want 10 results per page and you're on page 3, the paginator will fetch only the results you need by adding a LIMIT and OFFSET to your query.

The one tricky thing is that the documentation is a little bit out of date. The $this->get() method - which is the same as saying $this->container->get() - is the historic way to fetch a service out of the container by using its id. Depending on your setup, that may or may not even be possible in Symfony 4. And, in general, it's no longer considered a best-practice. Instead, you should use dependency injection, which almost always means, autowiring.

But, hmm, it doesn't say anything about autowiring here. That's a problem: the bundle needs to tell us what class or interface we can use to autowire the paginator service. Ah, don't worry: we can figure it out on our own!

Go back to your terminal Excellent! The install finished. Now run:

php bin/console debug:autowiring

Search for pager. Boom! Apparently there is a PaginatorInterface we can use to get that exact service. We are in business!

Using the Paginator

Back in CommentAdminController, add that as the 3rd argument: PaginatorInterface. Make sure to auto-complete this to get the use statement. Call the arg $paginator:

... lines 1 - 5
use Knp\Component\Pager\PaginatorInterface;
... lines 7 - 10
class CommentAdminController extends Controller
{
... lines 13 - 15
public function index(CommentRepository $repository, Request $request, PaginatorInterface $paginator)
{
... lines 18 - 30
}
}

Next, go back to the docs and copy the $pagination = section, return, and paste:

... lines 1 - 10
class CommentAdminController extends Controller
{
... lines 13 - 15
public function index(CommentRepository $repository, Request $request, PaginatorInterface $paginator)
{
... lines 18 - 21
$pagination = $paginator->paginate(
$queryBuilder, /* query NOT result */
$request->query->getInt('page', 1)/*page number*/,
10/*limit per page*/
);
... lines 27 - 30
}
}

Ok, so what should we use for $query? When you use a paginator, there is an important, practical change: we are no longer responsible for actually executing the query. Nope, we're now only responsible for building a query and passing it to the paginator. This $query variable should be a QueryBuilder.

So, back in CommentRepository, let's refactor this method to return that instead. Remove the @returns and, instead, use a QueryBuilder return type:

... lines 1 - 16
class CommentRepository extends ServiceEntityRepository
{
... lines 19 - 31
/**
* @param string|null $term
*/
public function getWithSearchQueryBuilder(?string $term): QueryBuilder
{
... lines 37 - 49
}
... lines 51 - 79
}

Next, at the bottom, remove the getQuery() and getResults() lines:

... lines 1 - 16
class CommentRepository extends ServiceEntityRepository
{
... lines 19 - 31
/**
* @param string|null $term
*/
public function getWithSearchQueryBuilder(?string $term): QueryBuilder
{
... lines 37 - 46
return $qb
->orderBy('c.createdAt', 'DESC')
;
}
... lines 51 - 79
}

Finally, rename the method to getWithSearchQueryBuilder():

... lines 1 - 16
class CommentRepository extends ServiceEntityRepository
{
... lines 19 - 34
public function getWithSearchQueryBuilder(?string $term): QueryBuilder
{
... lines 37 - 49
}
... lines 51 - 79
}

Perfect! Back in the controller, add $queryBuilder = $repository->getWithSearchQueryBuilder($q). Pass this below:

... lines 1 - 10
class CommentAdminController extends Controller
{
... lines 13 - 15
public function index(CommentRepository $repository, Request $request, PaginatorInterface $paginator)
{
... lines 18 - 19
$queryBuilder = $repository->getWithSearchQueryBuilder($q);
$pagination = $paginator->paginate(
$queryBuilder, /* query NOT result */
$request->query->getInt('page', 1)/*page number*/,
10/*limit per page*/
);
... lines 27 - 30
}
}

Finally, instead of passing comments into the template, pass this pagination variable:

... lines 1 - 10
class CommentAdminController extends Controller
{
... lines 13 - 15
public function index(CommentRepository $repository, Request $request, PaginatorInterface $paginator)
{
... lines 18 - 19
$queryBuilder = $repository->getWithSearchQueryBuilder($q);
$pagination = $paginator->paginate(
$queryBuilder, /* query NOT result */
$request->query->getInt('page', 1)/*page number*/,
10/*limit per page*/
);
return $this->render('comment_admin/index.html.twig', [
'pagination' => $pagination,
]);
}
}

Open index.html.twig so we can make changes there. First, at the top, let's print the total number of comments because we will now only show 10 on each page. To do that, go back to the docs. Ah, this is perfect. Use: pagination.getTotalItemCount():

... lines 1 - 6
{% block content_body %}
<div class="row">
<div class="col-sm-12">
<h1>Manage Comments ({{ pagination.getTotalItemCount }})</h1>
... lines 11 - 66
</div>
</div>
{% endblock %}

Next, down in the loop, update this to for comment in pagination:

... lines 1 - 6
{% block content_body %}
<div class="row">
<div class="col-sm-12">
<h1>Manage Comments ({{ pagination.getTotalItemCount }})</h1>
... lines 11 - 28
<table class="table table-striped">
... lines 30 - 37
<tbody>
{% for comment in pagination %}
... lines 40 - 61
{% endfor %}
</tbody>
</table>
... lines 65 - 66
</div>
</div>
{% endblock %}

Yes, pagination is an object. But, you can loop over it to get the comments for the current page only.

Oh, and at the bottom, we need some navigation to help the user go to the other pages. That's really easy: on the docs, copy the knp_pagination_render() line and, paste!

... lines 1 - 6
{% block content_body %}
<div class="row">
<div class="col-sm-12">
<h1>Manage Comments ({{ pagination.getTotalItemCount }})</h1>
... lines 11 - 28
<table class="table table-striped">
... lines 30 - 37
<tbody>
{% for comment in pagination %}
... lines 40 - 61
{% endfor %}
</tbody>
</table>
{{ knp_pagination_render(pagination) }}
</div>
</div>
{% endblock %}

Phew! Let's go check it out! Yes! 100 total results, but only 10 on this page. We can click to page 2, then 3 and so-on. Heck, the search even works! Try something really common, like est. The URL has the ?q= query parameter. And, if you change pages, it stays: this is page 2 of that search. Dang, that's awesome.

Using the Bootstrap Pager Navigation Theme

Of course, there's one super minor problem... um... dang, that navigation looks horrible. But, we can fix that! The bundle comes with a bunch of different themes for the navigation. Scroll back up to the configuration example. Obviously, you don't need to configure anything on this bundle. But, there are several options. The most important one is this: template.pagination. This determines which template is used to build the navigation links. And, it ships with one for Bootstrap 4, which is what we're using. Booya!

So, first question: where should this configuration live? Sometimes, a recipe will create a file for us, like stof_doctrine_extensions.yaml. But in this case, that didn't happen. And that's ok! Not every bundle needs to give you a config file. Just create it by hand: knp_paginator.yaml.

As usual, the filename matches the root config key. But, we know from previous tutorials that the filename is actually meaningless. Next, copy the config down to the pagination line, move over, paste, then remove all the stuff we don't need. Finally, copy the bootstrap v4 template name and, paste:

knp_paginator:
template:
pagination: '@KnpPaginator/Pagination/twitter_bootstrap_v4_pagination.html.twig'

We're ready! Move back and refresh. Boom! It still works! It's beautiful! We rock! Our pagination is awesome! I'm super happy!

Now that this is perfect, let's turn to our last big topic: generating a totally new, ManyToMany relationship.

Leave a comment!

  • 2019-04-16 Mike

    Thank you very much!

  • 2019-04-15 Mike

    I had to clear the cache as well, before it didn't work.

    Shortcut:
    ./bin/console c:c

  • 2019-03-18 Ian

    Thanks, Ryan! Very interesting, I'll play around with tweaking the query in some of those ways. I'll report back if I find anything interesting.

    Regarding the second innerJoin, that's used to find the country associated with the images (news items are posted by teams, and teams are in countries) -- the gallery allows you to filter by country, but I snipped that part of the code out here. Getting my paginator to keep track of this filtering was actually fairly interesting.

  • 2019-03-18 weaverryan

    Hey @Ian!

    Glad you got it sorted - sometimes when things get SUPER complex, the route you took is best :).

    I don't have an exact answer for you, but check this out: https://stackoverflow.com/q...

    Actually, *why* putting the left join into the from fixes this doesn't make a ton of sense to me. But, the paginator sorta "hijacks" your query and does some cool stuff with it, so it doesn't surprise me that some more complex queries might cause problems. Also, the NEXT answer says that upgrading to doctrine/dbal 2.5 fixed the problem for him.

    More generally, when I join, I usually don't use the version of innerJoin that requires 4 args - I just say ->innerJoin('i.news', 'n'), which is where I take advantage of the fact that NewsImage has a "news" property - so Doctrine figures out the rest for me. I'm not sure if that simpler join solves this problem or not. Side note: I don't think the second innerJoin is needed - I can't see where the Team stuff is used.

    Hope that offers *some* clarity.

    Cheers!

  • 2019-03-16 Ian

    Update: I decided it would take longer to debug this than just write my own simple paginator, so that's what I did :) But I'd still be interested in any insight into what might have been going wrong with the Knp Paginator in this case.

  • 2019-03-15 Ian

    I'm getting an error I'm having trouble figuring out. I've inherited a Symfony project from a dev who's no longer around. One action is responsible for displaying a photo gallery page. It builds the following query (this is directly in the controller):


    $qb = $em->createQueryBuilder('n')
    ->select('i')
    ->from('AIM\UserBundle\Entity\NewsImage', 'i')
    ->innerJoin('AIM\UserBundle\Entity\News', 'n', Join::WITH, 'n.id = i.news')
    ->innerJoin('AIM\TeamBundle\Entity\Team', 't', Join::WITH, 't.id = n.team')
    ->where('n.status=1');

    The page is pretty slow to load -- the newsimage table contains over 3,000 records (!). I think some lazy loading is the only thing that allows this page to render at all, but it still sucks usability-wise, so I'd like to add pagination. I have the paginator bundle installed and configured. This is the paginator code I added as per the docs/this video:


    $pagination = $paginator->paginate(
    $qb, /* query NOT result */
    $request->query->getInt('page', 1)/*page number*/,
    24/*limit per page*/
    );

    When I try to visit the page, Doctrine throws the following error: Cannot count query which selects two FROM components, cannot make distinction. The error message made me think Doctrine was confused by the JOIN clauses -- sure enough, if I remove the join statements from the query, the paginator works just fine, but I need these to get other info about each NewsImage object. I can't see why the join statements would cause a problem, as the query builder from this tutorial also contains a join statement.

    Any thoughts? I feel like I'm missing something obvious. Thanks in advance, love these tutorials, they've made me really appreciate Symfony.

    (I should add -- the project was on Symfony 2, but another dev recently upgraded to Symfony 4, but we still have the old Symfony2 directory structure, hence the bundles.)

  • 2019-03-01 Diego Aguiar

    Oh really, that was the problem? Nice discovery then!

  • 2019-03-01 mike

    for everyone having the issue I found the solution.

    $searchForm = $this->createFormBuilder($property)
    ->add('type', EntityType::class, [
    'class' => Type::class,
    'choice_label' => 'name',
    'mapped' => false,
    'expanded' => true,
    'multiple' => true,
    'label' => false,
    ])
    ->add('filter', SubmitType::class, [
    'attr' => [
    'class' => 'btn btn-outline-dark btn-rounded waves-effect'
    ]
    ])
    ->setMethod('GET')
    ->getForm();

    just add ->setMethod('GET') in createFormBuilder

  • 2019-02-28 mike

    /**
    * @Route("/", name="home", defaults={"page" = 1})
    * @param Request $request
    * @param $page
    * @return \Symfony\Component\HttpFoundation\Response
    */
    public function home(Request $request, $page)

    still nothing happening

  • 2019-02-28 Diego Aguiar

    Ok, so you don't have the problem I mentioned. Double check that you are passing the "page" query parameter. I believe it's missing

  • 2019-02-28 mike

    this is the query in the repository class:

    public function findByType($type){
    $query = $this->createQueryBuilder('p')
    ->andWhere('p.type IN (:type)')
    ->andWhere('p.isSold = 0')
    ->setParameter('type', $type)
    ->getQuery();

    return $query->execute();
    }

    and in the controller:

    /**
    * @Route("/", name="home")
    * @param Request $request
    * @return \Symfony\Component\HttpFoundation\Response
    */
    public function home(Request $request)
    {
    $property = new Property();

    $searchForm = $this->createFormBuilder($property)
    ->add('type', EntityType::class, [
    'class' => Type::class,
    'choice_label' => 'name',
    'mapped' => false,
    'expanded' => true,
    'multiple' => true,
    'label' => false,
    ])
    ->add('filter', SubmitType::class, [
    'attr' => [
    'class' => 'btn btn-outline-dark btn-rounded waves-effect'
    ]
    ])
    ->getForm();

    $searchForm -> handleRequest($request);

    if ($searchForm->isSubmitted() && $searchForm->isValid()){
    $type = $searchForm->get('type')->getData();

    $search = $this->getDoctrine()->getRepository(Property::class)->findByType($type);
    if (count($type) == 0) {
    $search = $this->getDoctrine()->getRepository(Property::class)->findBy(['isSold' => 0]);
    }

    } else {
    $search = $this->getDoctrine()->getRepository(Property::class)->findBy(['isSold' => 0]);
    }

    $paginator = $this->get('knp_paginator');
    $result = $paginator->paginate(
    $search,
    $request->query->getInt('page', 1),
    $request->query->getInt('limit', 10)
    );

    return $this->render('home/index.html.twig', [
    'property' => $result,
    'searchForm' => $searchForm->createView(),
    'propertyCountByType' => $propertyCountByType,
    ]);
    }

  • 2019-02-28 Diego Aguiar

    Hey @mike

    How are you ordering results? Some times pagination misbehave when you only order by date and dates are the same (having the same value). If that's your case, try adding a tie-breaker, I usually add a second orderBy clause (ordering by id)

    Let me know if that worked :)

    Cheers!

  • 2019-02-28 mike

    I am trying to filter with the help of pagination. when I try and do that the first page is ok when I click to go in the second page it shows the initial result so without any filter.

  • 2019-02-14 weaverryan

    Hey Sasa Milivojevic!

    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!

  • 2019-02-11 Sasa Milivojevic

    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)
    .......

  • 2019-02-11 weaverryan

    Hey Sasa Milivojevic!

    Try something like this:


    $('.container').infiniteScroll({
    path: '{{ path('news_route_name') }}?page={{ '{{#}}' }}',
    append: '.post',
    history: false,
    });

    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{{#}}< 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 (replace news_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 a pagination__next class on it whose URL points to the next page URL (e.g. /news?page=3).

    Cheers!

  • 2019-02-11 Sasa Milivojevic

    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

  • 2019-02-11 weaverryan

    Hey Sasa Milivojevic!

    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!

  • 2019-02-08 Sasa Milivojevic

    Is it posible, and how to make infinite scroll with KnpPaginatorBundle

  • 2018-11-27 Steve

    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

  • 2018-11-26 Diego Aguiar

    Hey Steve

    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!

  • 2018-11-26 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

  • 2018-11-26 Steve

    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

  • 2018-11-26 weaverryan

    Hey Steve!

    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.

  • 2018-11-26 Steve

    Hi

    I'm trying to tidy up the url so that ?page=3 becomes /3/, is there anyway to do this?

    Cheers

    Steve

  • 2018-11-23 Victor Bocharsky

    Hey Steve,

    Looks like we have "symfony/translation" package due to "knplabs/knp-time-bundle" that requires it to be installed :) If you don't have "knplabs/knp-time-bundle" in your project - then it makes sense that you have to install "symfony/translation" manually :)

    I hope this clarify things for you.

    Cheers!

  • 2018-11-23 Steve

    Hi

    With all my Symfony applications I start with a base project that I’ve built which covers the basics (I usually use jQuery DataTables but some applications can have 000s or results so Pagination is required). As I work along with the videos I’m building a new “starter” project in v4. When I install the Paginator bundle on my application I get The service "twig" has a dependency on a non-existent service "translator” error. I fixed this with composer require symfony/translation

    I didn’t get this error when following the video and using the downloaded code. I see that the composer.json file doesn’t contain the reference to the translation package. Have you manually added this or have I missed something?

    Thank you

    Steve

  • 2018-11-19 Victor Bocharsky

    Hey Fernando,

    Thanks! Haha, yes, that's exactly what we're trying to show: Symfony is not a monster ;)

    About $em - yeah, it's better to use $entityManager instead, but in many places Symfony docs have $em so we just want to be consistent to avoid confusing newcomers. But agree, $entityManager is much better name and it's good for you to use this name ;)

    Cheers!

  • 2018-11-16 Fernando Andrade

    I didn't think on that perspective of the course it self... with that in mind it makes perfect sense...

    And because I need to say this, I really like your tutorials, they are simple and show that Symfony is not a monster, on top of that you teach good code standards most of the time, it bugs me a bit to see $em instead of $entityManager, but this is my problem not yours :)

    and since I code with the videos, like good students do, I use the full description to name the vars xD

  • 2018-11-16 Victor Bocharsky

    Hey Fernando,

    Yeah, it would be great, especially, for learning purposes to write your own custom paginator. We just reused this one in our screencast first of all because we do not want to cover creating custom paginators in this course that would unintentionally stretch its time - we love covering specific topics in a short time. And also we wanted to reveal the good bundle for more users.

    But I think I see your point and partially agree with it, so yeah, it depends as always ;)

    Cheers!

  • 2018-11-15 Fernando Andrade

    Of course we should cut corners, I just am not entirely sure if I will use it besides here xD

    Also it is always good to know it exists...

    nothing against being lazy, I mean we have tech because someone was lazy before us and we are doing this because at some point we were lazy ourselves xD

  • 2018-11-14 Victor Bocharsky

    Hey Fernando,

    Haha, I see your point :) Well, using third party paginator has some advantages. First of all, you'll save your time, you don't need to implement it, just install and use. I think you're agree with me that implementing even a simple version of paginator requires more time then installing/configure it :) Also, popular third-party code is usually well-tested, so you don't need to write tests for this functionality as it's done by maintainers - once again you save some time. And if you have a few projects where you need pagination, you'll probably want to share your custom paginator between these projects, and it also require some time... so I think eventually you'll come up to a third party paginator or create another paginator bundle, your own... but the question why? :) Anyway, it depends on your case, probably you just need a pretty straightforward and simple solution and using third-party paginator is just overkill? So, it depends, but that's what my opinion on it :)

    Cheers!

  • 2018-11-14 Fernando Andrade

    is it just me or this is a complete waste? I mean, cool that exists but this is something that one can code instead of importing yet another dependency...

    just my opinion, don't get offended lol :P

  • 2018-07-24 cybernet2u

    fix it :) my fault
    "a.author" was on another mysql table, therefore i had to use join :)

  • 2018-07-24 cybernet2u

    can you also check this ? https://stackoverflow.com/q...
    it may be related to count() from paginator ...

  • 2018-07-23 cybernet2u

    public function getWithSearchQueryBuilder(?string $term): QueryBuilder
    {
    $qb = $this->createQueryBuilder('a');
    if ($term) {
    $qb->andWhere('a.content LIKE :term OR a.author LIKE :term OR a.title LIKE :term')
    ->setParameter('term', '%' . $term . '%');
    }
    return $qb->orderBy('a.createdAt', 'DESC');
    }


    public function Home(EntityManagerInterface $em, PaginatorInterface $paginator, Request $request)
    {
    $q = $request->query->get('q');
    $repository = $em->getRepository(Advert::class);
    $queryBuilder = $repository->getWithSearchQueryBuilder($q);
    $pagination = $paginator->paginate(
    $queryBuilder,
    $request->query->getInt('page', 1),
    10
    );

    return $this->render('home.html.twig', [
    'pagination' => $pagination,
    ]);
    }
  • 2018-07-23 weaverryan

    Hey cybernet2u!

    Hmmm. I'm not aware of anything that would have changed recently that could cause this issue! Can you post your getWithSearchQueryBuilder() method from CommentRepository - and also your controller code?

    Cheers!

  • 2018-07-22 cybernet2u

    symfony 4.1.1

    i get [Semantical Error] line 0, col 66 near 'author LIKE :term': Error: Invalid PathExpression. Must be a StateFieldPathExpression.

    only when i make a search

    any ideea ?

  • 2018-07-06 Victor Bocharsky

    Hey Nicolas,

    Ah, that was the key. Thanks for confirming that "Knp\Component\Pager\PaginatorInterface" fixes the problem.

    Cheers!

  • 2018-07-05 Nicolas Petitjean

    It works, thanks, i was using "Knp\Component\Pager\Pagination\PaginationInterface;"

  • 2018-07-02 Victor Bocharsky

    Hey Nicolas,

    Did you try to type hint this argument with "Knp\Component\Pager\PaginatorInterface" interface?


    use Knp\Component\Pager\PaginatorInterface;

    class CommentAdminController extends Controller
    {
    public function index(CommentRepository $repository, Request $request, PaginatorInterface $paginator)
    {
    // ...
    }
    }

    Please, make sure you have "use Knp\Component\Pager\PaginatorInterface;" used namespace in the beginning, looks like you just typehinted with incorrect namespace. And btw, you don't need that "$pagination: '@knp_paginator'" at all, just try the namespace I mentioned.

    If it still does not work, what version of Kn[PaginatorBundle do you use?

    Cheers!

  • 2018-06-30 Nicolas Petitjean

    Hello

    Got this error :

    Controller "App\Controller\CommentAdminController::index()" requires that you provide a value for the "$pagination" argument. Either the argument is nullable and no null value has been provided, no default value has been provided or because there is a non optional argument after this one.

    The only way to get this working is to bind a var in services.yaml :

    $pagination: '@knp_paginator'

    But this bring me this error :

    Type error: Argument
    3 passed to App\Controller\CommentAdminController::index() must implement interface Knp\Component\Pager\Pagination\PaginationInterface, instance of Knp\Component\Pager\Paginator given

    So i have to remove the type hint in the method :

    public function index(CommentRepository $repository, Request $request, $pagination) {
    ...
    }

    symfony 4.0.4

  • 2018-06-28 Daniel

    Hey that's awesome! Thanks, Diego!

  • 2018-06-28 Diego Aguiar

    Hey Daniel

    Using the : return_type syntax is the new way for specifing return types in PHP7, and it will throw an exception if your method return anything else than stated, but if you only specify the return type in a PHPdoc block, then nothing will check the actual return type, it's only for helping IDE's and for documentation.

    Cheers!

  • 2018-06-28 Daniel

    Hi!

    In this code:

    /**
    * @param null|string $term
    */
    public function findAllWithSearch(?string $term): QueryBuilder

    What's the difference between declaring the return type after ":" or at * @return QueryBuilder?

    Thanks!

  • 2018-06-22 Diego Aguiar

    Hey mouerr

    I'm afraid we do not count with any bundle for that topic, but, I just found one that looks good, probably you could give it a try: https://github.com/stwe/Dat...

    Cheers!

  • 2018-06-22 mouerr

    Hello guys,
    Am wondering if there is a knpbundle for datatable, if yes, is there a course for it?
    Thanks in Advance

  • 2018-06-16 weaverryan

    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.

  • 2018-06-15 Diego Aguiar

    Oh, yes, whenever you create a new translation file you have to clear the cache. Thanks for sharing the steps!

  • 2018-06-15 Peter Kosak

    For beginners like me:
    run "composer require symfony/translation"
    then create file "translations/KnpPaginatorBundle.en.yaml"
    paste there

    label_next: Next
    label_previous: Previous

    Then I had to run "php bin/console cache:clear"

    That seems to do the trick and everything is sorted.

  • 2018-06-13 Diego Aguiar

    Hey Peter Kosak

    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!

  • 2018-06-13 Peter Kosak

    All is working except my pagination labels for previous & next are : label_previous & label_next also on profiler bar I have 2 translation errors:

    en KnpPaginatorBundle 1 label_previous label_previous
    en KnpPaginatorBundle 1 label_next label_next

    so I was checking documentation and there is:

    Troubleshooting
    Make sure the translator is activated in your symfony config :
    framework:
    translator: { fallbacks: ['%locale%'] }
    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.

  • 2018-06-01 Victor Bocharsky

    Hey Alexandrer,

    Yeah, it's weird. I suppose you're talking about PHP warning, not a fatal error. It's difficult to say, you need to see the backtrace to understand where this error comes from. It sounds like a bug in somewhere, and it would be better to fix to be sure everything works well.

    Cheers!

  • 2018-05-31 Alexander Enlund

    It's really weird... it works but the error remains, yes I did use:
    {{ pagination.getTotalItemCount }} and that's where the error is...
    ...but I guess if it works then there is nothing to worry about, right.
    (thanks for the quick reply!)

  • 2018-05-31 Victor Bocharsky

    Hey Alexander,

    Do you see this error due to this "{{ pagination.getTotalItemCount }}" code? This is a valid syntax - I see it from the docs: https://github.com/KnpLabs/... . Did you call $paginator->paginate(...) method in your controller with proper arguments to initialize pagination? See example in docs: https://github.com/KnpLabs/... . If so, could you dump your "pagination" object in Twig? What object is it?

    Cheers!

  • 2018-05-31 Alexander Enlund

    Hey! Just one question, how come you can use methods and such even though it says: "field or method not found under construction." ? (e.g. {{ pagination.getTotalItemCount }})