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.
Related
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 %}
I've got this entity, which contains entityName property and entityId property:
/**
* #var string
*
* #ORM\Column(name="entityName", type="string", length=255)
*/
private $entityName;
/**
* #var integer
* #ORM\Column(name="entityId", type="integer")
*/
private $entityId;
Instead of showing this entity using __toString() function, I wanted to actually return the entity with name and id. and show that in sonata admin list view.
for now, here is __toString:
public function __toString()
{
return $this->entityName . ":" . $this->entityId;
}
which should return something like:
public function __toString()
{
return $em->getRepository($this->entityName)->find($this->entityId);
}
I hope that I've described my problem well.
tnx
One workaround is to use custom list block for sonata.
create a new twig filter called entityFilter, this filter will convert FQCN of an sonata admin object to a readable route name generated by sonata. like admin_blablabla_show:
public function entityFilter($entityName)
{
$str = str_replace('\\', '_', $entityName);
$str = str_replace('Bundle', '', $str);
$str = str_replace('_Entity', '', $str);
$str = 'Admin' . $str . '_Show';
return strtolower($str);
}
public function getName()
{
return 'my_extension';
}
in you admin class, set the template of the desired field to a new twig template:
->add('orderItems', null, array(
'template' => 'AcmeBundle::order_items_list.html.twig'
))
And in your new twig template (order_items_list.html.twig):
{% extends 'SonataAdminBundle:CRUD:base_list_field.html.twig' %}
{% block field %}
<div>
{% for item in object.orderItems %}
{% if entity(item.entityName) == 'admin_first_entity_show' %}
{% set foo = 'Apple ID' %}
{% elseif entity(item.entityName) == 'admin_second_entity_show' %}
{% set foo = 'Device Accessory' %}
{% else %}
{% set foo = 'Not defiend' %}
{% endif %}
<a target="_blank" class="btn btn-default btn-xs" href="{{ path(entity(item.entityName), {'id': item.entityId}) }}"><i class="fa fa-external-link"></i> {{ foo }}</a>
{% endfor %}
</div>
{% endblock %}
I Want to show all font awesome icon in select option with Symfony Form Builder.
I add the select field with :
$choices = $this->getFontAwesome();
$form->add( $key, ChoiceType::class, array('label' => 'Texte', 'choices' => $choices, 'attr' => array('class' => "fa" ) ) );
My Function getFontAwesome();
public function getFontAwesome(){
$webroot = $this->get('kernel')->getRootDir() . '/../web';
$pattern = '/\.(fa-(?:\w+(?:-)?)+):before\s+{\s*content:\s*"\\\\(.+)";\s+}/';
$subject = file_get_contents( $webroot . '/assets/vendor/font-awesome/css/font-awesome.css');
preg_match_all($pattern, $subject, $matches, PREG_SET_ORDER);
foreach($matches as $match) {
$icons[$match[1]] = '&#x' . $match[2] . ';' ;
}
return $icons ;
}
But in the select field, don't see the icon:
Field show the code and not the icon
How i can do ?
I Try htmlspecialschars and others ( htmlentities, .. ) but don't work.
If you aren't using any js plugins like Select2 or Bootstrap-select, then you have http://jsfiddle.net/NyL7d/ this possibility, but we need work a bit to reach it.
First, to say that using <i class="fa fa-heart"></i> as label isn't a choice, because the <option> element can't have any child elements, but only text. (see related issue)
For reusability let's build a form type named "IconChoiceType" as child of "ChoiceType":
namespace AppBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\Extension\Core\Type\ChoiceType;
use Symfony\Component\Form\FormInterface;
use Symfony\Component\Form\FormView;
use Symfony\Component\OptionsResolver\OptionsResolver;
class IconChoiceType extends AbstractType
{
/**
* Cache for multiple icon fields or sub-requests.
*
* #var array
*/
private $choices;
private $kernelRootDir;
public function __construct($kernelRootDir)
{
$this->kernelRootDir = $kernelRootDir;
}
public function buildView(FormView $view, FormInterface $form, array $options)
{
// Pass this flag is necessary to render the label as raw.
// See below the twig field template for more details.
$view->vars['raw_label'] = true;
}
public function configureOptions(OptionsResolver $resolver)
{
$resolver->setDefaults([
'attr' => [
// It's the key of the solution and can be done in many ways.
// Now, the rendered <select> element will have a new font.
'style' => "font-family: 'FontAwesome';"
],
'choices' => $this->getFontAwesomeIconChoices(),
]);
}
public function getParent()
{
return ChoiceType::class;
}
protected function getFontAwesomeIconChoices()
{
if (null !== $this->choices) {
// don't to load again for optimal performance.
// useful for multi-icon fields and sub-requests.
return $this->choices;
}
// BTW we could configure the path to the "font-awesome.css".
$fontAwesome = file_get_contents($this->kernelRootDir.'/../web/assets/vendor/font-awesome/css/font-awesome.css');
// this regular expression only works with uncompressed version (not works with "font-awesome.min.css")
$pattern = '/\.(fa-(?:\w+(?:-)?)+):before\s+{\s*content:\s*"\\\\(.+)";\s+}/';
if (preg_match_all($pattern, $fontAwesome, $matches, PREG_SET_ORDER)) {
foreach ($matches as list(, $class, $code)) {
// this may vary depending on the version of Symfony,
// if the class name is displayed instead of the icon then swap the key/value
$this->choices['&#x'.$code.';'] = $class;
}
}
return $this->choices;
}
}
and their respective service to register:
# app/config/service.yml
services:
app.form.icon_choice_type:
class: AppBundle\Form\Type\ChoiceIconType
# Symfony has already a container parameter to the kernel root directory.
arguments: ['%kernel.root_dir%']
tags:
- { name: form.type }
well, so far there is no result different from yours.
<select id="form_icon" name="form[icon]" style="font-family: 'FontAwesome';">
<option value="fa-glass"></option>
<option value="fa-music"></option>
...
</select>
Where is the problem now? The <select> font family is ready, but the icons they aren't showing, why?
By default, in Symfony the Twig environment escapes all values that are rendered using htmlspecialchars (more details), so we need overwrite this behavior for this form type only. For that, we create a fields.html.twig template in app/Resources/views/form directory and copy this code inside:
{# app/Resources/views/form/fields.html.twig #}
{#
here isn't need to create the expected `icon_choice_widget` like shown
the documentation, because this looks equal to `choice_widget` from
`ChoiceType`, only we need overwrite the block that renders the label.
#}
{%- block choice_widget_options -%}
{% for group_label, choice in options %}
{%- if choice is iterable -%}
<optgroup label="{{ choice_translation_domain is same as(false) ? group_label : group_label|trans({}, choice_translation_domain) }}">
{% set options = choice %}
{{- block('choice_widget_options') -}}
</optgroup>
{%- else -%}
{# this line has been overwritten, see {{- block('choice_option_label') -}} to end #}
<option value="{{ choice.value }}"{% if choice.attr %} {% set attr = choice.attr %}{{ block('attributes') }}{% endif %}{% if choice is selectedchoice(value) %} selected="selected"{% endif %}>{{- block('choice_option_label') -}}</option>
{%- endif -%}
{% endfor %}
{%- endblock choice_widget_options -%}
{%- block choice_option_label -%}
{# this block has been called from choice_widget_options block #}
{%- if raw_label|default(false) -%}
{# the label is rendered as raw when IconChoiceType is used #}
{{ choice_translation_domain is same as(false) ? choice.label|raw : choice.label|trans({}, choice_translation_domain)|raw }}
{%- else -%}
{{ choice_translation_domain is same as(false) ? choice.label : choice.label|trans({}, choice_translation_domain) }}
{%- endif -%}
{%- endblock -%}
Note that {{ choice.label|raw }} raw filter displays the raw text stored (it prevents from being escaped) into label, in this case the icon font content.
finally, you need to register the form theme like describe the documentation:
# app/config/config.yml
{# ... #}
twig:
form_themes:
- 'form/fields.html.twig'
Conclusion:
$form->add('icon', IconChoiceType::class);
I know this is quite an old post and #yceruto's answer is correct andd has its place, but I think it's too complicated for something as simple as putting an icon on a form. Therefore, for new visitors, I offer my own version.
in formBilder
public function buildForm(FormBuilderInterface $builder, array $options)
{
// prepare an array with icons
$icons = [
'',
'',
];
// decode our icons
$icons = array_flip(array_map('html_entity_decode',$icons));
// add field to formBuilder
$builder->add('icon', ChoiceType::class, [
'choices' => $icons,
'mapped' => false,
]);
}
include FontAwesome library in you page and add css style
select { font-family: 'FontAwesome', serif }
I have created a custom action that renders a small form at the bottom of my show template for orders. The form is a basic checkbox and a select field to with tow buttons. It works perfectly but the rendering is not right.
I know the way I render the show template is not 100% correct, because when it renders, the left hand side menu doesn't work anymore.
Here is my custom controller with action;
namespace Qi\Bss\FrontendBundle\Controller;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpFoundation\Request;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Method;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Qi\Bss\FrontendBundle\Crud\Crud;
use Qi\Bss\BaseBundle\Entity\Business\PmodOrder;
use Symfony\Component\HttpFoundation\RedirectResponse;
class PmodOrderController extends Controller
{
/**
* #Route("/{id}/approve", name = "order_approve")
* #Security("is_granted('IS_AUTHENTICATED_FULLY')")
* #Method({"GET", "POST"})
*/
public function approveAction(Request $request, $id){
$em = $this->getDoctrine()->getManager();
$order = $em->getRepository('QiBssBaseBundle:PmodOrder')->find($id);
$approveForm = $this->createFormBuilder($order)
->add('requireApproval', 'checkbox', array('label' => 'Require second Approval', 'required' => false, 'mapped' => false))
->add('secondApprover', 'choice', array('choices' => Crud::enumStatus(), 'label' => 'User', 'required' => false))
->getForm();
$approveForm->handleRequest($request);
if ($approveForm->isSubmitted() && $approveForm->isValid()) {
$secondApproval = $request->request->get('form');
$approval = $approveForm->getData();
if (isset($secondApproval['requireApproval'])) {
$approval->setStatus(PmodOrder::STATUS_PARTLY_APPROVED);
$em->persist($approval);
$em->flush();
return new RedirectResponse($this->container->get('router')->generate('admin_bss_base_business_pmodorder_show', array('id' => $order->getId())));
} else {
$approval->setSecondApprover(NULL);
$approval->setStatus(PmodOrder::STATUS_APPROVED);
$em->persist($approval);
$em->flush();
return new RedirectResponse($this->container->get('router')->generate('admin_bss_base_business_pmodorder_show', array('id' => $order->getId())));
}
}
return $this->render('QiBssFrontendBundle:PmodOrder:order_approve.html.twig', array(
'order' => $order,
'form' => $approveForm->createView(),
));
}
}
What bothers me is the fact that I'm actually suppose to extend from Sonata's CRUDController. And when I do that I get an error;
An exception has been thrown during the rendering of a template
("There is no _sonata_admin defined for the controller
Path\To\Controller\PmodOrderController and the current
route ``")
And I am also aware that I'm actually suppose to use a return like return new RedirectResponse($this->admin->generateUrl('show'));
At this point I don't know what to do anymore. If somebody can please guide me how to extend correctly from CRUDController in my scenario, it would be really appreciated
Here an example, I don't know if it's the best solution but I hope that can help you :
1- Create a custom CRUDcontroller :
# CustomCRUDcontroller.php :
class CustomCRUDDController extends Controller
{
/**
* Show action.
*
* #param int|string|null $id
* #param Request $request
*
* #return Response
*
* #throws NotFoundHttpException If the object does not exist
* #throws AccessDeniedException If access is not granted
*/
public function showAction($id = null)
{
$request = $this->getRequest();
// DO YOUR LOGIC IN THE METHOD, for example :
if(isset($request->get('yourFormParam'))){
$this->doTheJob();
}
$id = $request->get($this->admin->getIdParameter());
$object = $this->admin->getObject($id);
if (!$object) {
throw $this->createNotFoundException(sprintf('unable to find the object with id : %s', $id));
}
$this->admin->checkAccess('show', $object);
$preResponse = $this->preShow($request, $object);
if ($preResponse !== null) {
return $preResponse;
}
$this->admin->setSubject($object);
return $this->render($this->admin->getTemplate('show'), array(
'action' => 'show',
'object' => $object,
'elements' => $this->admin->getShow(),
), null);
}
}
2- Register it in admin.yml :
# admin.yml :
x.admin.x:
class: Namespace\YourAdminClass
arguments: [~, Namespace\Entity, Namespace:CustomCRUD]
tags:
- {name: sonata.admin, manager_type: orm, group: X, label: X}
3- Create your own custom_show.html.twig (just a copy and paste of the original template base_show.html.twig located in the sonata-admin folder), here you can display extra elements to the view :
# custom_show.html.twig :
{% extends base_template %}
{% import 'SonataAdminBundle:CRUD:base_show_macro.html.twig' as show_helper %}
{% block actions %}
{% include 'SonataAdminBundle:CRUD:action_buttons.html.twig' %}
{% endblock %}
{% block tab_menu %}
{{ knp_menu_render(admin.sidemenu(action), {
'currentClass' : 'active',
'template': sonata_admin.adminPool.getTemplate('tab_menu_template')
}, 'twig') }}
{% endblock %}
{% block show %}
<div class="sonata-ba-view">
{{ sonata_block_render_event('sonata.admin.show.top', { 'admin': admin, 'object': object }) }}
{% set has_tab = (admin.showtabs|length == 1 and admin.showtabs|keys[0] != 'default') or admin.showtabs|length > 1 %}
{% if has_tab %}
<div class="nav-tabs-custom">
<ul class="nav nav-tabs" role="tablist">
{% for name, show_tab in admin.showtabs %}
<li{% if loop.first %} class="active"{% endif %}>
<a href="#tab_{{ admin.uniqid }}_{{ loop.index }}" data-toggle="tab">
<i class="fa fa-exclamation-circle has-errors hide"></i>
{{ admin.trans(name, {}, show_tab.translation_domain) }}
</a>
</li>
{% endfor %}
</ul>
<div class="tab-content">
{% for code, show_tab in admin.showtabs %}
<div
class="tab-pane fade{% if loop.first %} in active{% endif %}"
id="tab_{{ admin.uniqid }}_{{ loop.index }}"
>
<div class="box-body container-fluid">
<div class="sonata-ba-collapsed-fields">
{% if show_tab.description != false %}
<p>{{ show_tab.description|raw }}</p>
{% endif %}
{{ show_helper.render_groups(admin, object, elements, show_tab.groups, has_tab) }}
</div>
</div>
</div>
{% endfor %}
</div>
</div>
{% elseif admin.showtabs is iterable %}
{{ show_helper.render_groups(admin, object, elements, admin.showtabs.default.groups, has_tab) }}
{% endif %}
</div>
{{ sonata_block_render_event('sonata.admin.show.bottom', { 'admin': admin, 'object': object }) }}
{% endblock %}
4- Then indicate to your adminController to display your custom_show template when the current route is "show" (instead of the default template base_show.html.twig) :
# YourEntityAdminController.php :
class YourEntityAdminController extends Controller
{
// allows you to chose your custom showAction template :
public function getTemplate($name){
if ( $name == "show" )
return 'YourBundle:Admin:custom_show.html.twig' ;
return parent::getTemplate($name);
}
}
I have a list of friends which should be displayed 3 in a page. Each friend has a category and I also have a drop down menu to choose to view only the friends which are from the chosen category. They should also be display 3 in a page. The way in which filtered and not filtered friends are displayed is the same so I didn't want to have two almost actions in my controller and two identic templates, so I tried to make this in one controller's action and template, but there is a problem. I can't make the pagination for the second and following pages of the filtered friends. Pleae help! :( The problem is that I use a form and when I click on the second page, the variable which was filled in the form and binded, become undefined. Here is the code:
Controller's action
public function displayAction($page, Request $request)
{
$em = $this->getDoctrine()->getEntityManager();
$user = $this->get('security.context')->getToken()->getUser();
$cat = new Category();
$dd_form = $this->createForm(new ChooseCatType($user->getId()), $cat);
if($request->get('_route')=='filter')
{
if($request->getMethod() == 'POST')
{
$dd_form->bindRequest($request);
if($cat->getName() == null)
{
return $this->redirect($this->generateUrl('home_display'));
}
$filter = $cat->getName()->getId();
if ($dd_form->isValid())
{
$all_friends = $em->getRepository('EMMyFriendsBundle:Friend')
->filterFriends($filter);
$result = count($all_friends);
$FR_PER_PAGE = 3;
$pages = $result/$FR_PER_PAGE;
$friends = $em->getRepository('EMMyFriendsBundle:Friend')
->getFilteredFriendsFromTo($filter, $FR_PER_PAGE, ($page-1)*$FR_PER_PAGE);
$link = 'filter';
}
}
}
else
{
$all_friends = $user->getFriends();
$result = count($all_friends);
$FR_PER_PAGE = 3;
$pages = $result/$FR_PER_PAGE;
$friends = $em->getRepository('EMMyFriendsBundle:Friend')
->getFriendsFromTo($user->getId(), $FR_PER_PAGE, ($page-1)*$FR_PER_PAGE);
$link = 'home_display';
}
// Birthdays
$birthdays = null;
$now = new \DateTime();
$now_day = $now->format('d');
$now_month = $now->format('m');
foreach ($all_friends as $fr)
{
if($fr->getBirthday() != null)
{
if($fr->getBirthday()->format('d') == $now_day && $fr->getBirthday()->format('m') == $now_month)
{
$birthdays[]=$fr;
$fr->setYears();
}
}
}
// Search
$search = new Search();
$s_form = $this->createFormBuilder($search)
->add('words', 'text', array(
'label' => 'Search: ',
'error_bubbling' => true))
->getForm();
// Renders the template
return $this->render('EMMyFriendsBundle:Home:home.html.twig', array(
'name' => $name, 'friends' => $friends, 'user' => $user, 'birthdays' => $birthdays, 'pages' => $pages, 'page' => $page, 'link' => $link,
'dd_form' => $dd_form->createView(), 's_form' => $s_form->createView()));
}
Template
{% if birthdays != null %}
<div>
<img class="birthday" src="http://www.clker.com/cliparts/1/d/a/6/11970917161615154558carlitos_Balloons.svg.med.png">
<div class="try">
This friends have birthday today:
{% for bd in birthdays %}
<p>
{{ bd.name }}
<span class="years">
({{ bd.years }} years)
</span>
</p>
{% endfor %}
</div>
</div>
{% endif %}
{% for fr in friends %}
{# TODO: Fix where are shown #}
{% if fr.getWebPath()!=null %}
<a href="{{ path('friend_id', {'id': fr.id}) }}">
<img class="avatar" src="{{ fr.getWebPath }}">
</a>
{% endif %}
{% if loop.index is odd %}
<p class="list1">
{% else %}
<p class="list2">
{% endif %}
<a class="friends" href="{{ path('friend_id', {'id': fr.id}) }}">{{ fr.name }}</a>
</p>
{% endfor %}
{# TODO: Pagination #}
{% if pages>1 %}
<p>
{% for i in 0..pages %}
{% if page == loop.index %}
<span class="pagination">{{ loop.index }}</span>
{% else %}
<span class="pagination">{{ loop.index }}</span>
{% endif %}
{% endfor %}
</P>
{% endif %}
<p>Choose category:</p>
<form class="search" action="{{ path('filter') }}" method="post" {{ form_enctype(s_form) }}>
{{ form_widget(dd_form.name) }}
{{ form_rest(dd_form) }}
<input type="submit" value="Show friends" />
</form>
Repository
class FriendRepository extends EntityRepository
{
public function getFriendsFromTo ($user, $limit, $offset)
{
return $this->getEntityManager()
->createQuery('SELECT f FROM EMMyFriendsBundle:Friend f WHERE f.user='.$user. 'ORDER BY f.name ASC')
->setMaxResults($limit)
->setFirstResult($offset)
->getResult();
}
public function filterFriends ($filter)
{
$q = $this->createQueryBuilder('f');
$q->select('f')
->where('f.category = :filter')
->setParameter('filter', $filter);
return $q->getQuery()->getResult();
}
public function getFilteredFriendsFromTo ($filter, $limit, $offset)
{
$q = $this->createQueryBuilder('f');
$q->select('f')
->where('f.category = :filter')
->setMaxResults($limit)
->setFirstResult($offset)
->setParameter('filter', $filter);
return $q->getQuery()->getResult();
}
}
I tried a lot of things, but there is always a problem. In this code it says that the variable $all_friends in the birthday for loop is not defined - and yes, it isn't. Maybe I have to store it in session and I tried this:
$session = $this->getRequest()->getSession();
$session->set('all_friends');
and then passing $friends=$session->get('all_friends'); to the for loop, but it doesn't work and isn't the variable $all_friends too big to store it?
Any ideas will be apreciated! Thank you for your time and effort!
EDIT
When I use the way with the session and
$session = $this->getRequest()->getSession();
$session->set('all_friends');
$fri=$session->get('all_friends');
foreach ($fri as $fr)
{ .... }
the error I get is
Warning: Invalid argument supplied for foreach() in C:\xampp\htdocs\MyFriends\src\EM\MyFriendsBundle\Controller\HomeController.php line 100
and also
Warning: Missing argument 2 for Symfony\Component\HttpFoundation\Session::set(), called in C:\xampp\htdocs\MyFriends\src\EM\MyFriendsBundle\Controller\HomeController.php on line 71 and defined in C:\xampp\htdocs\MyFriends\app\cache\dev\classes.php line 148
When I don't use session I get
Notice: Undefined variable: all_friends in C:\xampp\htdocs\MyFriends\src\EM\MyFriendsBundle\Controller\HomeController.php line 100
when I choose a category to show the friends from it, and I click its second page.
P.S. The lines from the errors don't corespond to the lines in the code I pasted, bacause I skipped some parts of the action, repository and template, because they don't have a part in this problem and they work correctly. If someone wishes, I can send him or update here all the code.
You are setting nothing on session :
$session->set('all_friends');
You should be doing this instead:
$session->set('all_friends', $data);
You should really start respecting Symfony2 coding standards too.
My eyes are melting when I try to read your code. You should read this and don't forget to create form class instead of creating form in your controller.
EDIT: If your $data is a result from a Doctrine2 query, I suggest that you store only the entity id and the entity class in order to fetch them later when you need it.
EDIT2: Here's some code that might help you saving on session filters data. PS, don't forget to add the missing use ....
/**
* Set filters
*
* #param array $filters Filters
* #param string $type Type
*/
public function setFilters($name, array $filters = array())
{
foreach ($filters as $key => $value) {
// Transform entities objects into a pair of class/id
if (is_object($value)) {
if ($value instanceof ArrayCollection) {
if (count($value)) {
$filters[$key] = array(
'class' => get_class($value->first()),
'ids' => array()
);
foreach ($value as $v) {
$identifier = $this->getDoctrine()->getManager()->getUnitOfWork()->getEntityIdentifier($v);
$filters[$key]['ids'][] = $identifier['id'];
}
} else {
unset($filters[$key]);
}
} elseif (!$value instanceof \DateTime) {
$filters[$key] = array(
'class' => get_class($value),
'id' => $this->getDoctrine()->getManager()->getUnitOfWork()->getEntityIdentifier($value)
);
}
}
}
$this->getRequest()->getSession()->set(
$name,
$filters
);
}
/**
* Get Filters
*
* #param array $filters Filters
* #param type $type Type
*
* #return array
*/
public function getFilters($name, array $filters = array())
{
$filters = array_merge(
$this->getRequest()->getSession()->get(
$name,
array()
),
$filters
);
foreach ($filters as $key => $value) {
// Get entities from pair of class/id
if (is_array($value) && isset($value['class'])) {
if (isset($value['id'])) {
$filters[$key] = $this->getDoctrine()->getManager()->find($value['class'], $value['id']);
} elseif (isset($value['ids'])) {
$data = $this->getDoctrine()->getManager()->getRepository($value['class'])->findBy(array('id' => $value['ids']));
$filters[$key] = new ArrayCollection($data);
}
}
}
return $filters;
}
EDIT3: Why you're not using KnpPaginatorBundle for pagination ?