I've been working on an online learning website for a school project. I've had trouble passing variales when clicking on a lesson, belonging to a section, inside a course. The idea is that on a course page (formation.html.twig), there's a summary of the course, and you can click on the lessons which are in a sidebar menu. It should then display a page with the same menu, and the content of the lesson showing in place of the course summary (lesson.html.twig).
I've updated the controller so the url goes:
formations/consulter-formationid-sectionid-lessonid
In the view, I wrote {{ path('app_formations_lesson', {'formation':formation.id, 'section': section.id, 'id':lesson.id}) }}
It's working alright for the url and the right values show when I click, but the page refreshes and won't load the right twig view (lesson.html.twig), it loads the same view I'm currently on (formation.html.twig).
FormationsController:
#[Route('/formations/consulter-{id}', name: 'app_formations_see')]
public function see($id): Response
{
$formation = $this->doctrine->getRepository(Formation::class)->findOneById($id);
$section = $this->doctrine->getRepository(Section::class)->findAll();
$lesson = $this->doctrine->getRepository(Lesson::class)->findAll();
return $this->render('formations/formation.html.twig', [
'formation' => $formation,
'sections' => $section,
'lessons' => $lesson
]);
}
#[Route('/formations/consulter-{formation}-{section}-{id}', name: 'app_formations_lesson')]
public function seeLesson($id): Response
{
$lesson = $this->doctrine->getRepository(Lesson::class)->findOneById($id);
return $this->render('formations/lesson.html.twig', [
'lesson' => $lesson
]);
}
formation.html.twig
{% extends 'base.html.twig' %}
{% block title %}{{ formation.title }}{% endblock %}
{% block content %}
<div class="formationcontainer text-center">
{% block sidebar %}
{% include "./formations/sidebar.html.twig" %}
{% endblock %}
<h1>{{ formation.title }} par {{ formation.user.firstname }} {{ formation.user.lastname }}</h1>
{{ formation.description }}
<hr>
<h2>Sommaire</h2>
<div class="tableau">
<table class="table">
{% for section in formation.sections %}
<thead class="table-success">
<tr>
<th scope="col">{{ section.name }}</th>
</tr>
</thead>
<tbody>
{% for lesson in section.lessons %}
<tr>
<td>{{ lesson.title }}</td>
</tr>
{% endfor %}
</tbody>
{% endfor %}
</table>
</div>
</div>
{% endblock %}
lesson.html.twig
{% extends 'base.html.twig' %}
{% block title %}titre de la leçon{% endblock %}
{% block content %}
<div class="formationcontainer text-center">
{% block sidebar %}
{% include "./formations/sidebar.html.twig" %}
{% endblock %}
<h1>Nom de la leçon</h1>
<hr>
<h2>Vidéo</h2>
<h2>Contenu</h2>
</div>
{% endblock %}
sidebar block
<!-- Sidear for lesson pages -->
<nav class="flex-shrink-0flex-shrink-0 p-3 bg-white sidenav">
<button class="btn btn-success" id="sidenav-btn" type="button" data-bs-toggle="collapse" data-bs-target="#sidebarCollapse" aria-expanded="false" aria-controls="collapseOne">
Sommaire
</button>
<div class="list-unstyled ps-0 ul-custom navbar-collapse collapse show" id="sidebarCollapse" aria-expanded="true">
<li class="mb-1">
{% for section in formation.sections %}
<ul class="list-unstyled align-items-center rounded fw-normal">
<li>{{ section.name }}</li>
</ul>
<div>
{% for lesson in lessons %}
<ul class="list-unstyled fw-normal pb-1 small">
<li>{{ lesson.title }}</li>
</ul>
{% endfor %}
</div>
{% endfor %}
</li>
<li class="border-top my-3"></li>
<li class="mb-1">
<ul class="list-unstyled fw-normal pb-1 small">
<li>retour à la liste des formations</li>
</ul>
</li>
</div>
</nav>
Where does this issue come from? How can I display the right view?
Thanks a lot!
edit: I swapped the code in the controller to match the seeLesson function first.
#[Route('/formations/consulter-{formation}-{section}-{id}', name: 'app_formations_lesson')]
public function seeLesson($id): Response
{
$formation = $this->doctrine->getRepository(Formation::class)->findOneById($id);
$section = $this->doctrine->getRepository(Section::class)->findAll();
$lesson = $this->doctrine->getRepository(Lesson::class)->findOneById($id);
return $this->render('formations/lesson.html.twig', [
'lesson' => $lesson,
'formation' => $formation,
'sections' => $section
]);
}
#[Route('/formations/consulter-{id}', name: 'app_formations_see')]
public function see($id): Response
{
$formation = $this->doctrine->getRepository(Formation::class)->findOneById($id);
$section = $this->doctrine->getRepository(Section::class)->findAll();
$lesson = $this->doctrine->getRepository(Lesson::class)->findAll();
return $this->render('formations/formation.html.twig', [
'formation' => $formation,
'sections' => $section,
'lessons' => $lesson
]);
}
It's rendering the wrong page because your URLs are too similar.
When trying to determine what method to execute, Symfony matches the requested URL against the route definitions above the controller methods from top to bottom.
If you're requesting for example /formations/consulter-1-2-3,
Symfony first tries to match this against /formations/consulter-{id}.
This matches if you substitute 1-2-3 for {id}, so it executes the see method.
To fix you have two options:
Either switch the order of the 2 methods in your controller so that the method seeLesson is defined above the see method. Symfony will then first try to match against the route for the seeLesson method.
Or keep the method order as is, but add a constraint to the {id} parameter in the route for the see method, to specify that the matched {id} can only consist of digits:
#[Route('/formations/consulter-{id}', name: 'app_formations_see', requirements: ['id' => '\d+'])]
Related
I am using Drupal and have twig for html template. I am super new to this project and see that the have a controller with a function that queries a database and then they return that query for the course page attributes, and I see where the attributes are displayed in the respective course.twig.html.
What I don't see is how they are connected and how the twig.html knows where its attributes are coming from. I am trying to add some more attributes to the page and don't see how this project is passing the mysql queries to the twig template.
{#
/**
* #file
* Default theme implementation to display a node.
*
* Available variables:
* - node: Full node entity.
* - id: The node ID.
* - bundle: The type of the node, for example, "page" or "article".
* - authorid: The user ID of the node author.
* - createdtime: Time the node was published formatted in Unix timestamp.
* - changedtime: Time the node was changed formatted in Unix timestamp.
* - label: The title of the node.
* - content: All node items. Use {{ content }} to print them all,
* or print a subset such as {{ content.field_example }}. Use
* {{ content|without('field_example') }} to temporarily suppress the printing
* of a given child element.
* - author_picture: The node author user entity, rendered using the "compact"
* view mode.
* - metadata: Metadata for this node.
* - date: Themed creation date field.
* - author_name: Themed author name field.
* - url: Direct URL of the current node.
* - display_submitted: Whether submission information should be displayed.
* - attributes: HTML attributes for the containing element.
* The attributes.class element may contain one or more of the following
* classes:
* - node: The current template type (also known as a "theming hook").
* - node--type-[type]: The current node type. For example, if the node is an
* "Article" it would result in "node--type-article". Note that the machine
* name will often be in a short form of the human readable label.
* - node--view-mode-[view_mode]: The View Mode of the node; for example, a
* teaser would result in: "node--view-mode-teaser", and
* full: "node--view-mode-full".
* The following are controlled through the node publishing options.
* - node--promoted: Appears on nodes promoted to the front page.
* - node--sticky: Appears on nodes ordered above other non-sticky nodes in
* teaser listings.
* - node--unpublished: Appears on unpublished nodes visible only to site
* admins.
* - title_attributes: Same as attributes, except applied to the main title
* tag that appears in the template.
* - content_attributes: Same as attributes, except applied to the main
* content tag that appears in the template.
* - author_attributes: Same as attributes, except applied to the author of
* the node tag that appears in the template.
* - title_prefix: Additional output populated by modules, intended to be
* displayed in front of the main title tag that appears in the template.
* - title_suffix: Additional output populated by modules, intended to be
* displayed after the main title tag that appears in the template.
* - view_mode: View mode; for example, "teaser" or "full".
* - teaser: Flag for the teaser state. Will be true if view_mode is 'teaser'.
* - page: Flag for the full page state. Will be true if view_mode is 'full'.
* - readmore: Flag for more state. Will be true if the teaser content of the
* node cannot hold the main body content.
* - logged_in: Flag for authenticated user status. Will be true when the
* current user is a logged-in member.
* - is_admin: Flag for admin user status. Will be true when the current user
* is an administrator.
*
* #see template_preprocess_node()
*
* #todo Remove the id attribute (or make it a class), because if that gets
* rendered twice on a page this is invalid CSS for example: two lists
* in different view modes.
*
* #ingroup themeable
*/
#}
{# {{ kint() }} #}
<article id="node-{{ node.id }}" {{ attributes }}>
{{node}}
{{ title_prefix }}
{% if not page %}
<h2{{ title_attributes }}>
{{ label }}
</h2>
{% endif %}
{{ title_suffix }}
{% if node.field_packaging.value == '1' %}
{% set image = content.field_image %}
{% set ce = content.field_tax_credit_hours %}
{% set goal = content.field_goal %}
{% set target_audience = content.field_audience %}
{% set objectives = content.field_objectives %}
{% set accreditation = content.field_accreditation %}
{% set disclosure = content.field_disclosure_statement %}
{# {% set references_old = content.field_references %} #}
{% set references = content.field_references_par %}
{% set appendix = content.field_appendix %}
{% set faculty = content.field_faculty %}
{% set related_courses = content.field_related_courses %}
{# set suggested_courses = content.field_suggested_courses #}
{% set additional = content.field_callout %}
{% set expiration = node.field_expiration.value %}
<div class="course-summary row">
{% if image|render %}
<div class="course-image small-6 small-offset-3 medium-4 medium-offset-0 columns">
{{ image }}
</div>
<div class="small-12 medium-8 columns">
{% else %}
<div class="small-12 columns">
{% endif %}
<div class="course-introduction">
<p>Welcome to <em>{{ label }}</em>.</p>
</div>
{% if not resource %}
{% if ce.0|render %}
<small class="credit-hours inline-label">Credit hours: {{ ce.0 }} CE</small>
{% endif %}
{% endif %}
<div class="enroll">
{% if signIn == "yes" %}
{% if regis == true %}
Go
{% else %}
Enroll
{% endif %}
{% else %}
Enroll
{% endif %}
</div>
</div>
</div>
{% if goal|render or objectives|render %}
<ul class="tabs some-tabs" data-responsive-accordion-tabs="tabs small-accordion medium-tabs" data-allow-all-closed="true" data-multi-expand="true" id="course-tabs">
<li class="tabs-title is-active">Overview</li>
{% if appendix|render %}
<li class="tabs-title">Appendix</li>
{% endif %}
{% if references|render %}
<li class="tabs-title">References</li>
{% endif %}
{% if faculty|render %}
<li class="tabs-title">Faculty</li>
{% endif %}
</ul>
<div class="tabs-content" data-tabs-content="course-tabs">
<div id="overview" class="tabs-panel is-active course-overview">
{{ additional|render ? additional }}
{% if goal|render %}
<h2 class="field-label">{{ node.field_goal.fielddefinition.label }}</h2>
{{ goal }}
{% endif %}
<h2 class="field-label">{{ node.field_audience.fielddefinition.label }}</h2>
{% if target_audience|render %}
{{ target_audience }}
{% else %}
<p>interested health-care professionals.</p>
{% endif %}
{% if objectives|render %}
<h2 class="field-label">{{ node.field_objectives.fielddefinition.label }}</h2>
<p>After completing the activities of this module, you will be able to:</p>
{{ objectives }}
{% endif %}
{% if expiration|render %}
<p>Please note this module expires on <strong>{{ expiration|date('n/j/Y') }}</strong>.</p>
{% endif %}
{% if accreditation|render or disclosure|render %}
<div class="course-supplements">
{% if accreditation|render %}
<h2 class="supplement-title">Accreditation Statement</h2>
<div id="accreditation" class="callout callout-arrow is-hidden" data-toggler=".is-hidden">
{% for i, value in accreditation %}
{% set acc_item = node.field_accreditation[i].entity %}
{% if acc_item %}
<h3>{{ acc_item.title.value }}</h3>
{% autoescape false %}
{{ acc_item.body.value|replace({'{{ #.## }}': ce.0|escape }) }}
{% endautoescape %}
{% endif %}
{% endfor %}
<button class="close-button" data-toggle="accreditation">×</button>
</div>
{% endif %}
{% if disclosure|render %}
<h2 class="supplement-title">Disclosures</h2>
<div id="disclosure" class="callout callout-arrow is-hidden" data-toggler=".is-hidden">
{{ disclosure }}
<button class="close-button" data-toggle="disclosure">×</button>
</div>
{% endif %}
</div>
{% endif %}
</div>
{% if appendix|render %}
<div id="appendix" class="tabs-panel course-appendix">
{% if appendix %}
<ul class="tabs tabs-style-text" data-tabs id="course-appendix-tabs">
{% for i, value in node.field_appendix.value %}
{% set ref_title = node.field_appendix[i].entity.field_title.value %}
{% if ref_title %}
<li class="tabs-title{{ i == 0 ? ' is-active'}}">{{ ref_title }}</li>
{% endif %}
{% endfor %}
</ul>
<div class="tabs-content" data-tabs-content="course-appendix-tabs">
{% for i, value in node.field_appendix.value %}
<div id="{{ node.field_appendix[i].entity.field_title.value|clean_class }}" class="tabs-panel{{ i == 0 ? ' is-active'}}">
{% autoescape false %}
{{ node.field_appendix[i].entity.field_content.value }}
{% endautoescape %}
</div>
{% endfor %}
</div>
{% endif %}
</div>
{% endif %}
{% if references|render %}
<div id="references" class="tabs-panel course-references">
{% if references %}
<ul class="tabs tabs-style-text" data-tabs id="course-references-tabs">
{% for i, value in node.field_references_par.value %}
{% set ref_title = node.field_references_par[i].entity.field_title.value %}
{% if ref_title %}
<li class="tabs-title{{ i == 0 ? ' is-active'}}">{{ ref_title }}</li>
{% endif %}
{% endfor %}
</ul>
<div class="tabs-content" data-tabs-content="course-references-tabs">
{% for i, value in node.field_references_par.value %}
<div id="{{node.field_references_par[i].entity.field_title.value|clean_class}}" class="tabs-panel{{ i == 0 ? ' is-active'}}">
{% autoescape false %}
{{ node.field_references_par[i].entity.field_content.value }}
{% endautoescape %}
</div>
{% endfor %}
</div>
{% endif %}
</div>
{% endif %}
{% if faculty|render %}
<div id="faculty" class="tabs-panel course-faculty">
<div class="sections">
{{ faculty }}
</div>
</div>
{% endif %}
</div>
{% endif %}
{% if related_courses|render %}
{% set ancillary_1 = node.field_related_courses.fielddefinition.label %}
{% set ancillary_2 = 'Guidance' %}
{# set ancillary_2 = node.field_suggested_courses.fielddefinition.label #}
<ul class="sections sections-border accordion mobile-accordion stacked-tabs" data-accordion data-allow-all-closed="true" data-multi-expand="true">
<li class="section accordion-item" data-accordion-item>
{{ ancillary_1 }}
{% if related_courses|render %}
<div class="tiles mobile-accordion-content" data-tab-content>
<h2 class="field-label section-title hide-for-small-only">{{ ancillary_1 }}</h2>
<div class="list-items list-format-3">
{{ related_courses }}
</div>
</div>
{% endif %}
</li>
<li class="section accordion-item" data-accordion-item>
{{ ancillary_2 }}
<div class="tiles mobile-accordion-content" data-tab-content>
<h2 class="field-label section-title hide-for-small-only">{{ ancillary_2 }}</h2>
<div class="list-items list-format-1 list-type-guidance">
{{ drupal_view('content_feed', 'guidance') }}
</div>
</div>
</li>
</ul>
{{ drupal_view('content_feed', 'guidance_modal') }}
{% endif %}
{% else %}
{{ content.body }}
{% endif %}
</article>
You should search for preprocess hooks (function yourmodule_preprocess...). If you are using drupal8 you can set a new variable like this:
$vars['myvar'] = 'test';
In twig, can be called like this
{{ myvar }}
Important: it will not work in every function. I use to work it with preprocess functions, but thanks to #leymannx, we know it works with other hooks too:
"Not only preprocess hooks can pass variables to templates. Implement
hook_theme and then in your controler theme the output and pass
variables along to a template"
When you render a twig template in the controller, you can also pass some variables as data. If you want to show that data in the twig template, you call them by their name inside twig functions and language constructs.
That's it in general.
I can not help you more because your question is very generic.
I have 3 entities: User (part of FOSUserBundle), Comment, Article.
I'd like to display a comment form on the article only of the visitor is logged in. It was displaying for everybody just fine.
My code doesn't work and also seems like very bad practice. I get "Variable "form" does not exist." because I'm stopping the form from getting passed to the view. Is the necessary if I put an if in the view? I'd appreciate any suggestions on how I can accomplish this!
Thanks a bunch.
My comment.html.twig
{% extends 'base.html.twig' %}
{% block body %}
{% form_theme form 'form/fields.html.twig' %}
{% if is_granted('ROLE_USER') -%}
<div class="form-group">{{ form_start(form) }}</div>
<div class="form-group">{{ form_row(form.comment.title) }}</div>
<div class="form-group">{{ form_row(form.comment.rating) }}</div>
<div class="form-group">{{ form_row(form.comment.comment) }}</div>
<div class="form-group">{{ form_row(form.comment.user.firstName) }}</div>
<div class="form-group">{{ form_row(form.comment.user.lastName) }}</div>
<div class="form-group">{{ form_row(form.comment.user.email) }}</div>
<input class="btn btn-default" type="submit" value="Create" />
{{ form_end(form) }}
{% else %}
<p>Please log in to post a comment!</p>
{% endif %}
{% endblock %}
My show.html.twig (for articles)
{% extends 'base.html.twig' %}
{% block body_id 'articlepage' %}
{% block body %}
<h1>Article: {{ article.name }}</h1>
<div class="well"><div class="media">
<div class="media-left media-top">
<img class="media-object" src="{{ article.thumbnail }}">
</div>
<div class="media-body">
<h4 class="media-heading">{{ article.name }}</h4>
<p>{{ article.description }}</p>
</div>
</div></div>
<h2>Article Comments:</h2>
{{ render(controller('AppBundle:Comment:index', {'article_id': article.id})) }}
<h2>Submit a new comment:</h2>
{{ render(controller('AppBundle:Article:comment', {'id': article.id})) }}
{% endblock %}
commentAction within ArticleController.php (a controller that gets embedded in the show.html.twig)
public function commentAction(Request $request, Article $article)
{
$auth_checker = $this->get('security.userization_checker');
$token = $this->get('security.token_storage')->getToken();
$user = $token->getUser();
$isRoleUser = $auth_checker->isGranted('ROLE_USER');
if($isRoleUser){
$comment = new Comment();
//Build the comment form.
$commentForm = $this->createFormBuilder($comment)
->add('comment', CommentType::class, array("label" => FALSE))
->setAction($this->generateUrl('article_comment', array('id' =>$article->getId())))
->getForm();
$commentForm->handleRequest($request);
if ($commentForm->isSubmitted() && $commentForm->isValid()) {
//Update existing user or create new
$em = $this->getDoctrine()->getManager();
$comment = $commentForm->getData()->getComment();
$user = $this->getUser($comment->getUser());
//Update the existing comment or get a new one
$user = $this->getUser($comment->getUser());
$comment = $this->getComment($user, $article, $comment);
//Set the user and article for the comment.
$comment->setUser($user);
$comment->setArticle($article);
$em->persist($comment);
$em->flush($comment);
$this->getDoctrine()->getManager()->flush();
return $this->redirectToRoute('article_show', array('id' => $article->getId()));
}
return $this->render('article/comment.html.twig', array(
'form' => $commentForm->createView(),
));
} else {
return $this->render('article/comment.html.twig');
}
}
If you want to check whether user logged in or not in your Twig templates, you could use app.user variable:
{% if app.user %}
{{ render(controller('AppBundle:Comment:index', {'article_id': article.id})) }}
{% endif %}
To render TOC (categories tree) inside the base.twig view I call the render() function passing it the corresponding action url:
{% block sidebar %}
{{ render(url('toc_documents_categories')) }}
{% endblock %}
The matching partial view for the '/toc/documents' action (_toc.documents_categories.twig) is defined as follows:
{% set category_id = (current_uri|split('/'))[4] %}
{% macro recursiveCategory(category, active_category_id) %}
<li>
{% if category.children|length %}
<a><span class="icon icon-plus"></span>{{ category.name_displayed }}</a>
{% else %}
{% set active_class = active_category_id == category.id ? 'active' %}
{% set url = app.url_generator.generate('documents_by_category', {category_id: category.id}) %}
<a href="{{ url }}" class="{{ active_class }}">
{{ category.name_displayed }}
</a>
{% endif %}
{% if category.children|length %}
<ul>
{% for child in category.children %}
{{ _self.recursiveCategory(child, active_category_id) }}
{% endfor %}
</ul>
{% endif %}
</li>
{% endmacro %}
{% if categories %}
<div id="categories">
<ul>
{% for category in categories %}
{{ _self.recursiveCategory(category, category_id) }}
{% endfor %}
</ul>
</div>
{% endif %}
As you can see I'm extracting current category's id by parsing current url. This is preceded by setting the current_uri global:
$app->before(function(Request $request) use ($app) {
$app['twig']->addGlobal('current_uri', $request->getRequestUri());
});
Accessing the route information (global.request.attributes.get('_route')) inside the partial view shows the corresponding subrequest route name and not the actual request route name (master request).
Is there a way to avoid manually parsing the current uri and to get the current request route params inside the partial view?
Here's the solution.
render() issues a subrequest, so you have to use the master request context:
use Symfony\Component\HttpFoundation\Request
$app->get('/documents_categories', function(Request $request) use($app) {
$master_request = $app['request_stack']->getMasterRequest();
$current_route = $master_request->get('_route');
$active_category_id = null;
if($current_route === 'documents_by_category') {
$active_category_id = $master_request->get('_route_params')['category_id'];
}
// ... do things: parse toc tree ...
return $app['twig']->render('_toc.documents.categories.twig', array(
"categories" => $toc_tree,
"active_category_id" => $active_category_id
));
})->bind('toc_documents_categories');
Then inside the partial view you have to only reference the passed active_category_id parameter:
{% if categories %}
<div id="categories">
<ul>
{% for category in categories %}
{{ _self.recursiveCategory(category, active_category_id) }}
{% endfor %}
</ul>
</div>
{% endif %}
Thanks to #keyboardSmasher for 'Why not pass the category_id in the render function' comment. Yet I'm not sure if I did it the way he assumed.
I'm building an application that uses slim, twig, and eloquent. On one of my pages, I'm showing a group of items first split into two groups, and then further split into group by category. Each item has a weight. I'm outputting the total weight of all the items from the first split. I'm outputting the name of each category once from the second split. Now I'd like to get the total weight of of only the items in that category and list it under that category name.
This is from the route:
$userId = $app->auth->id;
$collection = collect($app->item->where('user_id', $userId)->get()); // All items from the current user
$totalWeight = $collection->sum('grams');
$pack = $collection->filter(function($gear) { // All items with status 1 from the current user
if ($gear->status === 1) {
return true;
}
})->sortBy('category');
$storage = $collection->filter(function($gear) { // All items with status 0 from the current user
if ($gear->status === 0) {
return true;
}
})->sortBy('category');
$app->render('user/gear.php', [
'pack' => $pack,
'storage' => $storage,
'totalWeight' => $totalWeight
]);
This is from the view:
<div class="pack">
<header class="pack__header">
<h2 class="pack__header__title">Backpack</h2>
<span class="pack__header__weight">Total Weight: {{ totalWeight|outputWeights(totalWeight) }}</span>
</header>
{% set currentCategory = null %}
{% for item in pack %}
{% if item.category != currentCategory %}
<h3 class="categoryName">{{ item.category|getCatName(item.category) }}</h3>
{% set currentCategory = item.category %}
{% endif %}
<div class="item">
<ul class="item__lineOne">
<input type="checkbox" form="itemCheck" name="ID of the item" value="selected">
<li class="item__lineOne__name">{{ item.name }}</li>
<li class="item__lineOne__weight">{{ item.grams }}</li>
</ul>
<div class="collapse">
<ul class="item__lineTwo">
<li class="item__lineTwo__description">{{ item.description }}</li>
</ul>
<ul class="item__lineThree">
<li class="item__lineThree__url">
<a class="item__lineThree__url__link" href="{{ item.url }}">{{ item.url }}</a>
</li>
</ul>
<button type="button" class="modifyItemButton">Modify</button>
</div>
</div>
{% endfor %}
</div>
I also have a file with some Twig_SimpleFilters if I need to employ some code during the foreach in the view. I'm just not sure where or what is an effective way to solve this.
you can simplify your collection methods:
$pack = $collection->where('status', 1)->sortBy('category');
instead of filter.
you don't need sortyBy, use groupBy instead:
$pack = $collection->where('status', 1)->groupBy('category');
and then use sum in your template for each category:
{% for category,items in pack %}
<h3 class="categoryName">{{ category|getCatName(item.category) }}
<br>weight: {{ items.sum('grams') }}
</h3>
{% for item in items %}
<div class="item"> ... </div>
{% endfor %}
{% endfor %}
I need straightforward solution for dynamically set number of records per page with Knp Pagination Bundle.
I read the this page records per page allow user to choose - codeigniter pagination about dynamically set per page limits and I know I need a drop down with hyperlink inside each item that send a request to server and server use parameter on this request to set limit per page on knp pagination bundle. But I don't know exactly how to handle this actions on server and also and more harder to me how to create items on drop down related to the total number on my query.
my controller:
public function indexAction()
{
$page_title = Util::getFormattedPageTitle("Customers");
$em = $this->get('doctrine.orm.entity_manager');
$dql = "SELECT a FROM CustomersBundle:Customer a WHERE a.enable = 1 ORDER BY a.id";
//$query = $em->createQuery($dql);
//$customers = $query->execute();
$query = $em->createQuery($dql);
$paginator = $this->get('knp_paginator');
$pagination = $paginator->paginate(
$query,
$this->get('request')->query->get('page', 1)/*page number*/,
3/*limit per page*/
);
// parameters to template
return $this->render('CustomersBundle:Default:index.html.twig', array(
'page_title' => $page_title,
'pagination' => $pagination,
'image_path' => CustomersConstants::$customers_image_thumb_path
));
}
And my view code is:
{% extends '::base.html.twig' %}
{% block title %}
{{ page_title }}
{% endblock %}
{% block body %}
<h1>
{{ "customers" }}
</h1>
<br />
{% for customer in pagination %}
<a href="{{ customer.url }}" target="_blank">
<div dir="rtl" class="st_simple_box" id="customer{{customer.id}}" >
<table cellpadding="0" cellspacing="0" width="100%">
<tr>
<td style="vertical-align: top; width: 115px;">
{% if customer.imageName is not empty %}
<img class="newsimage" src="{{asset(image_path) ~ customer.imageName}}" alt="No Image/>
{% else %}
<img class="newsimage" src="{{asset('images/vakil_default_small.png') ~ customer.imageName}}" alt="No Image"/>
{% endif %}
</td>
<td style="text-align: center;">
<p><span style="font-family: Tahoma;">{{customer.titleFa}}</span></p>
</td>
<td style="text-align: justify;">
<p><span style="font-family: Tahoma;">{{customer.descriptionFa}}</span></p>
</td>
</tr>
</table>
</div>
</a>
{% endfor %}
<div class="navigation">
<span>
{{ knp_pagination_render(pagination) }}
</span>
<!--Here is my drop down html code-->
</div>
<br />
{% endblock %}
**
Edited on 12 March 2014
||||
||||
||||
\\\///
\\//
\/
Is there any way to set MaxItemPerPage on cookie to have a integrated variable and use this variable or change it while Knp Pagination is showed up on twig file.
the answer was correct but because of I used pagination in many bundles to paginate between my entities so I need an integrate variable to change all of them. I use your answer and customize sliding.html.twig on Knp Pagination to reach this code for "customized_sliding.html.twig"
<div class="ui small pagination menu">
<div style="clear: both;">
{% if pageCount > 1 %}
<div class="pagination" style="float: right;">
{% if first is defined and current != first %}
<a href="{{ path(route, query|merge({(pageParameterName): first})) }}" class="small icon item">
<i class="small double angle right icon"></i>
</a>
{% endif %}
{% if previous is defined %}
<a href="{{ path(route, query|merge({(pageParameterName): previous})) }}" class="small icon item">
<i class="small angle right icon"></i>
</a>
{% endif %}
{% for page in pagesInRange %}
{% if page != current %}
<a href="{{ path(route, query|merge({(pageParameterName): page})) }}" class="small item">
{{ page }}
</a>
{% else %}
<a class="small active item">
{{ page }}
</a>
{% endif %}
{% endfor %}
{% if next is defined %}
<a href="{{ path(route, query|merge({(pageParameterName): next})) }}" class="small icon item">
<i class="small angle left icon"></i>
</a>
{% endif %}
{% if last is defined and current != last %}
<a href="{{ path(route, query|merge({(pageParameterName): last})) }}" class="small icon item">
<i class="small double angle left icon"></i>
</a>
{% endif %}
</div>
{% endif %}
<div style="float: left;">
<select name="maxItemPerPage" id="maxItemPerPage">
<option selected="true" style="display:none;">Number Per Page</option>
<option id="10">5</option>
<option id="20">10</option>
<option id="30">20</option>
</select>
</div>
</div>
<script type="text/javascript">
//on select change, you navigate to indexAction and send the parameter maxItemPerPage
$('#maxItemPerPage').change(function(){
{% set currentPath = path(app.request.attributes.get('_route')) %}
var url = "{{path(app.request.attributes.get('_route'),{'maxItemPerPage': '_itemNum'})}}";
var item = $('#maxItemPerPage').find(":selected").text();
jQuery(location).attr('href', url.replace('_itemNum',item ));
});
</script>
</div>
I want to fetch and store MaxItemPerPage from cookie so there is no need to change all bundles code.
For example in my controller I don't know have to fetch the $maxItemPerPage from cookie
$pagination = $paginator->paginate(
$query,
$this->get('request')->query->get('page', 1)/*page number*/,
$maxItemPerPage/*limit per page*/
);
And I need change the value of maxItemPerPage on cookie by changing the value of html tag by javascript and redirect the page to same controller and no need to send maxItemPerPage to controller.
This can be done easily (if i understood well)
public function indexAction($maxItemPerPage=20)
{
$page_title = Util::getFormattedPageTitle("Customers");
$em = $this->get('doctrine.orm.entity_manager');
$dql = "SELECT a FROM CustomersBundle:Customer a WHERE a.enable = 1 ORDER BY a.id";
//$query = $em->createQuery($dql);
//$customers = $query->execute();
$query = $em->createQuery($dql);
$paginator = $this->get('knp_paginator');
$pagination = $paginator->paginate(
$query,
$this->get('request')->query->get('page', 1)/*page number*/,
$maxItemPerPage /*limit per page*/
);
// parameters to template
return $this->render('CustomersBundle:Default:index.html.twig', array(
'page_title' => $page_title,
'pagination' => $pagination,
'image_path' => CustomersConstants::$customers_image_thumb_path
));
}
in the view
{% extends '::base.html.twig' %}
{% block title %}
{{ page_title }}
{% endblock %}
{% block javascript%}
<script type="text/javascript">
//on select change, you navigate to indexAction and send the parameter maxItemPerPage
$('#maxItemPerPage').change(function(){
var url = '{{path('controller_index_route','maxItemPerPage':_itemNum)}}';
var item = $('#maxItemPerPage').find(":selected").text();
window.location.href = url.replace('_itemNum',item );
})
</script>
{% endblock %}
{% block body %}
<h1>
{{ "customers" }}
</h1>
<br />
{% for customer in pagination %}
<a href="{{ customer.url }}" target="_blank">
<div dir="rtl" class="st_simple_box" id="customer{{customer.id}}" >
<table cellpadding="0" cellspacing="0" width="100%">
<tr>
<td style="vertical-align: top; width: 115px;">
{% if customer.imageName is not empty %}
<img class="newsimage" src="{{asset(image_path) ~ customer.imageName}}" alt="No Image/>
{% else %}
<img class="newsimage" src="{{asset('images/vakil_default_small.png') ~ customer.imageName}}" alt="No Image"/>
{% endif %}
</td>
<td style="text-align: center;">
<p><span style="font-family: Tahoma;">{{customer.titleFa}}</span></p>
</td>
<td style="text-align: justify;">
<p><span style="font-family: Tahoma;">{{customer.descriptionFa}}</span></p>
</td>
</tr>
</table>
</div>
</a>
{% endfor %}
<div class="navigation">
<span>
{{ knp_pagination_render(pagination) }}
</span>
<!--Here is my drop down html code-->
</div>
<br />
<select name="maxItemPerPage" id="maxItemPerPage">
<option id="10">10</option>
<option id="20">20</option>
<option id="30">30</option>
</select>
{% endblock %}