0

After many search and read posts, I'm still stuck with my code. Let me explain : I created a custom module who display newsletters from Mailjet and old newsletters comming from drupal. To avoid the scrolling, I'd like to use pager but as I understood I cannot use the Drupal pager to do that. So I created a custom pager service but it doesn't work. I read some posts like this one : How to add Pager to a custom page? but it's only for drupal entities I little help can be usefull.

I'm using Drupal 8.6

Here is my code

my Controller :

<?php
/**
 * @file
 * Contains AnrsNewsControler.php
 *
 */
namespace Drupal\anrs_news\Controller;

use Drupal\Core\Controller\ControllerBase;
use Drupal\anrs_news\AnrsNewsMailjetService;
use Drupal\anrs_news\AnrsNewsPagerService;

use Symfony\Component\DependencyInjection\ContainerInterface;


/**
 * 
 */
class AnrsNewsController extends ControllerBase
{

    private $mailjetService;

    protected $pagerService;

    public $_result;
    /**
     * Inject Mailjet and Pager services
     *
     */
    public static function create(ContainerInterface $container){
        $mailjetService = $container->get('anrsnews.mailjet');

        return new static(
            $mailjetService,
            $container->get('anrsnews.pager')
        );
    }   


    public function __construct(AnrsNewsMailjetService $mailjetService, AnrsNewsPagerService $pager){
        $this->mailjetService = $mailjetService;
        $this->pagerService = $pager;
    }


    /**
     * Create Drupal element with
     * buildNewsletters object
     *
     * @return array $element
     */ 
    public function getContent() {
        $element[] =    [
            '#theme'    =>  'list_news',
            '#newsletter'   =>  $this->mergeResult(),
            '#pager'        =>  $this->getPagination(),
            '#attached' =>  [
                'library'   =>  [
                    'anrs_news/section'
                ]
            ],
        ];
        $element[] = $this->attachPager();

        return $element;
    }

    /**
     * Create newsletters objects
     * using Mailjet service
     *
     * @service $mailjetService
     * @return array{} $newsletterObj
     */
    public function buildNewsletters(){
        $newsletters = $this->mailjetService->_getNewslettersID(); 
        $newsletterObj = array();
        $nbNews=0;
        $contactListId=$this->mailjetService->getConfig()->get('mailjet.contact_list_id');

        for($i=sizeof($newsletters)-1; $i>=0; $i--){
            if($newsletters[$i]) {
                $response = $this->mailjetService->displayNewsletterById($newsletters[$i]);
                $elements = json_decode($response);


                foreach ($elements as $key => $value) {
                    if(( $value->Url != "")&&($value->DeliveredAt != '')&&($value->ContactsListID==$contactListId)) {
                        // on each index, initialize object
                        $newsletterObj[$nbNews] = new \stdClass();

                        $newsletterObj[$nbNews]->title = $value->Subject;
                        $newsletterObj[$nbNews]->id = $value->ID;
                        // convert datetime to timestamps
                        $newsletterObj[$nbNews]->date = strtotime($value->DeliveredAt);
                        $newsletterObj[$nbNews]->url = $value->Url;
                        $nbNews++;
                    }
                }
            }
        }

        return $newsletterObj;
    }


    /**
     * Retreive old newsletters
     * from 'simplenews_issue' entity
     *
     * @return array{Obj} $result
     *
     */
    public function getOldNewsletters() {
        $storage = \Drupal::EntityTypeManager()->getStorage('node');
        $entityQuery = \Drupal::entityQuery('node')
        ->condition('type', 'simplenews_issue')
        ->condition('status', 1);

        $entities_ids = $entityQuery->execute();

        $total = $entityQuery->count()->execute();  // total rows

        $entities = $storage->loadMultiple($entities_ids);

        $oldNews = array();
        $n = 0;

        foreach ($entities as $key => $value) {
            $oldNews[$n] = new \StdClass();

            $oldNews[$n]->title = $value->getTitle();
            $oldNews[$n]->id = $value->id();
            $oldNews[$n]->date = $value->getCreatedTime();
            $oldNews[$n]->url = $value->url();
            $n++;
            //id : $value->id()
            //created (tmp): $value->getCreatedTime()
            //title: $value->getTitle()
            //link : $value->url()
        }

        return $oldNews;
    }


    /**
     * Merge result of Mailjet newsletters and 
     * 'simplenews_issue' newsletters
     *
     * @return array{obj} desc
     */
    public function mergeResult(){
        $this->_result = array_merge($this->buildNewsletters(), $this->getOldNewsletters());

        // sort array 
        usort($this->_result, function($a, $b){
            if($a->date == $b->date ){
                return 0;
            } else {
                return ($a->date < $b->date)? +1:-1;
            }
        });
        // return slice array
        $offset = $this->pagerService->getResults($this->_result);

        return $offset;
    }


    public function getPagination() {

        if(count($this->_result)){
            $pagination = $this->pagerService;
            $response = $pagination->getResults($this->_result);

            if(count($response) != 0){
                $pageNum = '<div class="numbers">'.$pagination->getLinks($_GET).'</div>';
            }
        }
        // kint($_GET,$pageNum);
        return $pageNum;
    }

here is my pager service :

<?php 
namespace Drupal\anrs_news;

use Symfony\Component\DependencyInjection\ContainerAwareTrait;
use Symfony\Component\DependencyInjection\ContainerAwareInterface;
use Symfony\Component\HttpFoundation\RequestStack;

class AnrsNewsPagerService implements ContainerAwareInterface{


    use ContainerAwareTrait; 

    private $_properties = array();

    public $_defaults = array(
        'page'  => 1,
        'perPage'   => 3//\Drupal::Config('anrsnews.settings')->get('mailjet.posts_per_page')
    );

    public $page, $pages, $curpage, $length, $start;


    /**
     * Custom pager constructor
     * 
     */
    public function __construct($curPage = null, $perPage = null) {

        $this->curPage = ($curPage == null ? $this->_defaults['page']: $curPage);
        $this->perPage = ($perPage == null ? $this->_defaults['perPage']: $perPage);
    }


    public function __get($name){
        if(array_key_exists($name, $this->_properties)){
            return $this->_properties[$name];
        }
    }


    public function __set($name, $value){
        $this->_properties[$name] = $value;
    }


    public function getResults(array $array) {
        $this->array = $array; 

        if(!empty($this->curPage)   ){
            $this->page = $this->curPage;
        } else {
            $this->page = 1;
        }

        $this->length = count($this->array); // array length

        // number of pages 
        $this->pages = ceil($this->length/$this->perPage);

        // starting point
        $this->start = ceil(($this->page - 1) * $this->perPage);

        // return result offset
        return array_slice($this->array, $this->start, $this->perPage);
    }


    public function getLinks($params = array()) {
        $plinks = array();
        $links = array();
        $slinks = array();

        $queryUrl = '';
        // if(!empty($params) === true){
        //  unset($params['page']);
        //  $queryUrl = '&amp;'.http_build_query($params);
        // }
        if(!empty($params) === true){
            unset($params['page']);
            $queryUrl = '&amp;'.http_build_query($params);
        }

        if(($this->pages) > 1){
            if($this->page != 1){
                $plinks[] = '<a href="?page='.($this->page - 1).$queryUrl.'">&laquo;Prev</a>';
            }

            for($j=1; $j < ($this->pages +1); $j++) { 
                if($this->page == $j){
                    $links[] = '<a class="selected">'.$j.'</a>';
                } else {
                    $links[] = '<a href="?page='.$j.$queryUrl.'">'.$j.'</a>';
                }
            }

            // Assign the 'Next page'
            if( $this->page < $this->pages) {
                $slinks[] = ' <a href="?page='.($this->pages+1).$queryUrl.'"> Next &raquo; </a>';
            }

            return implode(' ', $plinks).implode(' | ', $links).implode(' ', $slinks);
        }


    }
}

thank u 4 ur help

1
  • I little up; nobody has an idee about that?
    – AVA
    Commented Sep 26, 2019 at 8:18

2 Answers 2

0

One of my mate find a solution, I had all the things on the file!! :,-( On the controller, in mergeResult function, instead to slice the array by the pager service, I sliced the array inside the function :

public function mergeResult(){
    $this->_result = array_merge($this->buildNewsletters(), $this->getOldNewsletters());

    // sort array 
    usort($this->_result, function($a, $b){
        if($a->date == $b->date ){
            return 0;
        } else {
            return ($a->date < $b->date)? +1:-1;
        }
    });
    // return slice array
    $limit = \Drupal::config('anrs_news.settings')->get('mailjet.posts_per_page');
    $offset=0;
    if(!empty($_REQUEST['page'])){
        $offset = $_REQUEST['page'] * $limit;
    }  

    return array_slice($this->_result, $offset, $limit);
}

and in the getContent function, I removed the pager variable :

public function getContent() {

    $element[] =    [
        '#theme'    =>  'list_news',
        '#newsletter'   =>  $this->mergeResult(),
        '#attached' =>  [
            'library'   =>  [
                'anrs_news/section'
            ]
        ],
    ];
    $element[] = $this->attachPager();

    return $element;
}

that's it!!

0

You can use the internal paging capabilities of Drupal without writing all that code. You just have to attach it in the returned render array. Here is an example

protected function method attachPager(int $totalRows, int $limit) : {
  pager_default_initialize($totalRows, $limit);
  return ['#type' => 'pager'];
}

Then attach that to the render array, like you are already doing, with the arguments:

$element[] = $this->attachPager(totalRows, limit);

The totalRows would come from your total results, and the limit is how many per page you want to show. The pager will generate based on that information. Your code would just need to implement the offset, based on the current page.

I would really evaluate this and try that out, otherwise you are having to maintain a lot more code. I have done this method for different types of data before, not just core entities.

1
  • Hi kevin, thank you for your comment. I'm really intersting about your evaluation result. It's like that we improve our knowledge ^^. To be honnest, it was the first time I developed pager inside custom module. Create a paging by service was for me a good point for maintenance.
    – AVA
    Commented Oct 11, 2019 at 13:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.