Simple pagination with twig - php

I'm trying to create a simple pagination with a twig view.
I'm not using Symfony.
Here is my method from my manager :
public function getAllPosts()
{
if(isset($_GET['p']) && (!isset($_GET['page']))){
$currentPage = 1;
}
else {
$currentPage = $_GET['page'];
}
$q= $this->_db->query('SELECT COUNT(id) AS numberposts FROM posts');
$data = $q->fetch(PDO::FETCH_ASSOC);
$number_posts= $data['numberposts'];
$perPage = 1;
$numberPages = ceil($number_posts/$perPage);
$q = $this->_db->query("SELECT * FROM posts ORDER BY date DESC LIMIT ".(($currentPage-1)*$perPage).",$perPage");
while($data = $q->fetch(PDO::FETCH_ASSOC))
{
$datas[] = new Post($data);
}
return $datas;
}
I want to create a loop in my view, this is what I'm doing
{% for posts in allPosts %}
{% for i in 1..numberPages %}
{{ i }}
{% endfor %}
{% endfor %}
But it's not working. It seems like I can't access to numberPages and I don't know why.
If anybody can help me !
Thanks a lot
EDIT
My pagination is working now.
I had this in my method like #darkbee :
return array(
'records' => $datas,
'numberPages' => $numberPages,
);
And in my view :
{% for i in 1.. allPosts.numberPages %}
<li>{{ loop.index}}</li>
{% endfor %}
But now I have another issue. I only get the same posts in all the pages.
EDIT
I forgot the page= on my pages links ...
<li>{{ loop.index}}</li>
It's working now !
Thanks !

You need to return the number of pages as well.
An aproach could be this,
public function getAllPosts() {
/** ... code .. **/
return array(
'records' => $data,
'numberPages' => $numberPages,
);
}
{% for posts in allPosts.records %}
{% for i in 1.. allPosts.numberPages %}
{{ i }}
{% endfor %}
{% endfor %}

Related

Cartalyst\Sentinel getting all Users with resulting permissions

For the purpose of a user-management ui I want to get all users with resulting permissions. I use the native implementation of Cartalyst\Sentinel and tried:
$users = Sentinel::getUserRepository()->with('roles')->get();
$permissions = array();
foreach ($users as $user) {
$user_permissions = Sentinel::getResultingPermissionsFor($user);
$permissions[$user['id']] = $user_permissions;
}
But the function "getResultingPermissionsFor()" seems not to be available anymore in V5.
I solved this by passing the roles-Object to the twig template:
router.php
$app->get('/admin/users', function (Request $request, Response $response) {
$loggedUser = Sentinel::check();
$users = Sentinel::getUserRepository()->with('roles')->get();
$roles = Sentinel::getRoleRepository()->get();
if (!$loggedUser) {
// do sth.
}
if (!$loggedUser->hasAccess('user.*')) {
// do sth.
}
$view = Twig::fromRequest($request);
$view->render($response, 'admin.users.html.twig', array(
'loggedUser' => $loggedUser,
'users' => $users,
'roles' => $roles
));
return $response;
});
twig-template:
{% for user in users %}
{% set rolePermissions = [] %}
{% for role in user.roles %}
{% set rolePermissions = rolePermissions|merge(role.permissions) %}
{% endfor %}
{% set resultingPermissions = rolePermissions %}
{% set resultingPermissions = resultingPermissions|merge(user.permissions) %}
{% endfor %}
// followed by output html

Adding a CSS class to drupal_set_message

I'm trying to add a CSS class to a specific message in Drupal that is output upon success when subscribing to a mailchimp list, here's the code for for submission function:
public function submitForm(array &$form, FormStateInterface $form_state) {
global $base_url;
$list_details = mailchimp_get_lists($this->signup->mc_lists);
$subscribe_lists = array();
// Filter out blank fields so we don't erase values on the Mailchimp side.
$mergevars = array_filter($form_state->getValue('mergevars'));
$email = $mergevars['EMAIL'];
$mailchimp_lists = $form_state->getValue('mailchimp_lists');
// If we only have one list we won't have checkbox values to investigate.
if (count(array_filter($this->signup->mc_lists)) == 1) {
$subscribe_lists[0] = array(
'subscribe' => reset($this->signup->mc_lists),
'interest_groups' => isset($mailchimp_lists['interest_groups']) ? $mailchimp_lists['interest_groups'] : NULL,
);
}
else {
// We can look at the checkbox values now.
foreach ($mailchimp_lists as $list) {
if ($list['subscribe']) {
$subscribe_lists[] = $list;
}
}
}
$successes = array();
// Loop through the selected lists and try to subscribe.
foreach ($subscribe_lists as $list_choices) {
$list_id = $list_choices['subscribe'];
$interests = isset($list_choices['interest_groups']) ? $list_choices['interest_groups'] : array();
if (isset($this->signup->settings['safe_interest_groups']) && $this->signup->settings['safe_interest_groups']) {
$current_status = mailchimp_get_memberinfo($list_id, $email);
if (isset($current_status->interests)) {
$current_interests = array();
foreach ($current_status->interests as $id => $selected) {
if ($selected) {
$current_interests[$id] = $id;
}
}
$interests[] = $current_interests;
}
}
$result = mailchimp_subscribe($list_id, $email, $mergevars, $interests, $this->signup->settings['doublein']);
if (empty($result)) {
drupal_set_message(t('There was a problem with your newsletter signup to %list.', array(
'%list' => $list_details[$list_id]->name,
)), 'warning');
}
else {
$successes[] = $list_details[$list_id]->name;
}
}
if (count($successes) && strlen($this->signup->settings['confirmation_message'])) {
drupal_set_message($this->signup->settings['confirmation_message'], 'status');
}
$destination = $this->signup->settings['destination'];
if (empty($destination)) {
$destination_url = Url::fromRoute('<current>');
}
else {
$destination_url = Url::fromUri($base_url . '/' . $this->signup->settings['destination']);
}
$form_state->setRedirectUrl($destination_url);
}
I'm specifically interested in altering this portion:
if (count($successes) && strlen($this->signup->settings['confirmation_message'])) {
drupal_set_message($this->signup->settings['confirmation_message'], 'status');
}
I would like to add a class that is output only for this confirmation message, and not for all of them. I've tried a couple things:
According to some related Q&A, I've tried editing the 'status' portion above to add a class there: 'status conf' or 'status, conf', neither of these work, the only accepted values are 'status', 'warning', and 'error', other values are not translated.
I've also tried this:
if (count($successes) && strlen($this->signup->settings['confirmation_message'])) {
drupal_set_message('' . $this->signup->settings['confirmation_message'] . '', 'status');
This option doesn't add the markup and just outputs it as a string:
"<div class="conf">Our confirmation message</div>"
Any suggestions?
A twig template is used to output the message html.
Why the documentation suggests there are only 3 options for the 'type' parameter, I don't know, but it is wrong. The status messages are just like any other themable (is that a word?) output.
Adding your own class, eg. drupal_set_message('Our confirmation message', 'conf'); does work, except the class (when the classy theme template is used) will be messages--conf.
In the case of the 'classy' theme, the template for messages is located at "core/themes/classy/templates/misc/status-messages.html.twig" and it looks like this:
{#
/**
* #file
* Theme override for status messages.
*
* Displays status, error, and warning messages, grouped by type.
*
* An invisible heading identifies the messages for assistive technology.
* Sighted users see a colored box. See http://www.w3.org/TR/WCAG-TECHS/H69.html
* for info.
*
* Add an ARIA label to the contentinfo area so that assistive technology
* user agents will better describe this landmark.
*
* Available variables:
* - message_list: List of messages to be displayed, grouped by type.
* - status_headings: List of all status types.
* - attributes: HTML attributes for the element, including:
* - class: HTML classes.
*/
#}
{% block messages %}
{% for type, messages in message_list %}
{%
set classes = [
'messages',
'messages--' ~ type,
]
%}
<div role="contentinfo" aria-label="{{ status_headings[type] }}"{{ attributes.addClass(classes)|without('role', 'aria-label') }}>
{% if type == 'error' %}
<div role="alert">
{% endif %}
{% if status_headings[type] %}
<h2 class="visually-hidden">{{ status_headings[type] }}</h2>
{% endif %}
{% if messages|length > 1 %}
<ul class="messages__list">
{% for message in messages %}
<li class="messages__item">{{ message }}</li>
{% endfor %}
</ul>
{% else %}
{{ messages|first }}
{% endif %}
{% if type == 'error' %}
</div>
{% endif %}
</div>
{# Remove type specific classes. #}
{% set attributes = attributes.removeClass(classes) %}
{% endfor %}
{% endblock messages %}
To override it, just add your own 'status-messages.html.twig' to your theme (MY_THEME/templates/misc/status-messages.html.twig) and alter as needed.

How to stop array from being overwritten?

I'm using Symfony2, version 2.7. But anyone should be able to answer this because it's not entirely relevant to symfony.
I have a function. I want that function to add a new item (once clicked on from a form) to an array. Instead, my array keeps getting overwritten with the new item that was clicked.
I tried a few foreach loops but couldn't get it right. Please, any help is appreciated.
Below is relevant function.
/**
* Displays Bought Items
*
* #Route("/buy/{id}", name="item_buy")
* #Method("GET")
* #Template()
*/
public function buyAction(Request $request, $id)
{
$session = $request->getSession();
$cart[] = $id;
$em = $this->getDoctrine()->getManager();
$entity = $em->getRepository('AppBundle:Item')->find($id);
$entities = $em->getRepository('AppBundle:Item')->findAll();
$session->set('cart', $cart);
if (!$entity) {
throw $this->createNotFoundException('No Item ');
} else {
$cart[$entity->getId()] = $entity->getName();
}
$session->set('cart', $cart);
return array(
'cart' => $cart,
'entity' => $entity,
'entities' => $entities,
);
}
How it is being used in twig:
{% extends '::base.html.twig' %}
{% block body -%}
<h1>Items Bought...</h1>
<table class="record_properties">
<h3>You Bought...</h3>
{# {% if entity is defined %} #}
{% for key, cartValue in cart %}
<tr>
<td>{{ key }}: {{ cartValue }}</td>
{{ dump(entity.name) }}
{{ dump(cart) }}
</tr>
{% endfor %}
{# {% endif %} #}
<tbody>
{% for entity in entities %}
<tr>
<td>{{ entity.id }}</td>
<td>{{ entity.name }}</td>
<td>
<ul>
<li>
Buy
</li>
</ul>
</td>
</tr>
{% endfor %}
</tbody>
</table>
<ul class="record_actions">
<li>
<a href="{{ path('item') }}">
Back to the list
</a>
</li>
{% endblock %}
Maybe I am wrong, but I guess that this line is problem:
$cart[] = $id;
You initialize here new array, every time. If I am wright You shuld get this array from session.
Try
$cart = $this->get('session')->get('cart', []);
For better formats of code I am answering to Your last comment here.
Above You're writting about adding new elements and I helped You solve this problem. Now (if I understand correclty) You have problem with added elements to array which You saved in session. I'm surprised your surprise. If You want delete something now from array which You saved in session YOU HAVE TO IMPLEMENT IT. It's not difficult - to clear a cart You should write something like this:
public function clearCartAction(Request $request)
{
$session->set('cart', array()); //set empty array
//return something here..
}
To delete single object from cart something like this (very simple implementation):
public function removeAction(Request $request, $id)
{
$session = $request->getSession();
$em = $this->getDoctrine()->getManager();
$cart = $session->get('cart', array());
if (isset($cart[$id]) {
unset($cart[$id]);
}
$session->set('cart', $cart);
//return something here
}
I can see that You have many very basic problems - definatelly You need a lot of learn and study programming.
Btw. I guess that I helped You solve problem describing in topic - so You should mark my comment as helpfull and topic as resolved.

How do I define the index within the array?

I am trying to consume the Google Books API, but it says undefined index for "title", as I am attempting to search for a book title and for the results to appear within twig.
My Controller :-
public function googlebooksAction($id)
{
$client = new Client();
$response = $client->get('https://www.googleapis.com/books/v1/volumes?q=id='.$id);
$data = $response->json();
$books = $data['title'];
return $this->render('ReviewerReviewBundle:Google:googlebooks.html.twig',
array(
'title' => $books
));
}
My Twig File :-
{% extends "::base.html.twig" %}
{% block title %}{{ book.volumeInfo.title }}{% endblock %}
{% block body %}
<h1>Google Books</h1>
{% for book in books %}
<article>{{ book.volumeInfo['title'] }}</article>
{% endfor %}
{% endblock %}

How to recursively display comments using twig?

I'm rewriting an application using the Silex framework. In this application, users can comment on posts and comments. In the non-MVC application, inspired by this question, I wrote it like this:
function display_comments($postid, $parentid=0, $level=0){
// Get the current comment from DB and display with HTML code
display_comments($needid, $comment['id'], $level+1);
}
However, in the Silex application, I want to retrieve them comment(s) from the database in a repository, send it to a twig-template in the controller and finally display the HTML code in the template. This makes the previous solution incompatible.
What is a good solution for this problem in Silex? What do I put in the view, what in the controller and what in the model?
EDIT
I wrote the function in the controller now:
$app->get('/needdetail/{id}', function ($id) use ($app) {
$need = $app['need']->findNeed($id);
function display_comments($app, $needid, $comments=array(), $parentid=0, $level=0){
$replies = $app['comment']->findByNeed($needid, $parentid);
foreach($replies as $reply){
$reply['level'] = $level;
array_push($comments, $reply);
display_comments($app, $needid, $comments, $reply['id'], $level+1);
}
return $comments;
}
return $app['twig']->render('needdetail.html', array('need' => $need, 'comments' => display_comments($app, $id)));
})
The level 0 comments are now shown, but a deeper level isn't.
I managed to get the required result with a slightly different approach. The controller as well as the view contains a recursive function:
Controller:
$app->get('/needdetail/{id}', function ($id) use ($app) {
$need = $app['need']->findNeed($id);
function get_comments($app, $needid, $parentid=0){
$comments = array();
$replies = $app['comment']->findByNeed($needid, $parentid);
foreach($replies as $comment){
$comment['replies'] = get_comments($app, $needid, $comment['id']);
array_push($comments, $comment);
}
return $comments;
}
return $app['twig']->render('needdetail.html', array('need' => $need, 'comments' => get_comments($app, $id)));
})
View:
{% for comment in comments %}
{% include 'comment.html' with {'level': 0} %}
{% endfor %}
Comment.html:
<div class="comment">
//Comment HTML
</div>
{% if comment.replies %}
{%for reply in comment.replies %}
{% include 'comment.html' with {'comment': reply, 'level': level+1} %}
{% endfor %}
{% endif %}

Categories