I am trying to create a custom page in Sonata where I basically read the current month created records of a particular table (Quotes). There is also money involved in every quote so at the end of the table I add an extra row for the Total of the month.
Now, since this is a custom template, I wanted to be able to put the Show action button that Sonata has on every quote, but I cannot find a way to do it... Any ideas? Thanks!
Im not using the Admin class since I am overriding the listAction method in a custom CRUDController as you can see here...
public function listAction()
{
if (false === $this->admin->isGranted('LIST')) {
throw new AccessDeniedException();
}
$datagrid = $this->admin->getDatagrid();
$formView = $datagrid->getForm()->createView();
// set the theme for the current Admin Form
$this->get('twig')->getExtension('form')->renderer->setTheme($formView, $this->admin->getFilterTheme());
$data = array();
$em = $this->getDoctrine()->getManager();
$request = $this->getRequest();
$form = $this->createFormBuilder(null, array('label' => 'Month: '))
->add('month', 'choice', array(
'choices' => $this->getMonths(),
'label' => false
))
->add('search', 'submit', array(
'attr' => array('class' => 'btn-small btn-info'),
))
->getForm();
$form->handleRequest($request);
if($request->isMethod('POST')){
$startDate = new \DateTime($form->get('month')->getData());
$endDate = new \DateTime($form->get('month')->getData());
$endDate->modify('last day of this month');
} else {
$endDate = new \DateTime('now');
$startDate = new \DateTime('now');
$startDate->modify('first day of this month');
}
$dql = 'SELECT q FROM AcmeQuoteBundle:Quote q WHERE q.date BETWEEN \' '
. $startDate->format('Y-m-d') . '\' AND \'' . $endDate->format('Y-m-d')
. '\' ORDER BY q.date DESC';
$query = $em->createQuery($dql);
$paginator = $this->get('knp_paginator');
$pagination = $paginator->paginate(
$query,
$this->get('request')->query->get('page', 1)/*page number*/,
50/*limit per page*/
);
$data['logrecords'] = $pagination;
return $this->render('AcmeQuoteBundle:Admin:quoteReport.html.twig',
array('data' => $data,
'action' => 'list',
'form' => $form->createView(),
'datagrid' => $datagrid
));
}
and here is the twig that I am using:
{% block list_table %}
{% set logrecords = data.logrecords %}
{# total items count #}
<div class="count">
<h4>Total number of records founded: {{ logrecords.getTotalItemCount }} </h4>
</div>
<table class="table table-striped table-hover table-bordered ">
<thead class="info">
<tr >
<th>#</th>
<th>{{ knp_pagination_sortable(logrecords, 'Created at', 'q.date') }}</th>
<th>{{ knp_pagination_sortable(logrecords, 'Quote token', 'q.viewToken') }}</th>
<th>Business name</th>
<th>$AUD</th>
<th>Action</th>
</tr>
</thead>
<tbody>
{% set grandTotal = 0.0 %}
{% for quote in logrecords %}
{% set total = 0.0 %}
{% for item in quote.items %}
{% set total = (item.unit * item.rate) %}
{% endfor %}
{% set grandTotal = grandTotal + total %}
<tr>
<td>{{ loop.index }}</td>
<td>{{ quote.date | date('Y-m-d') }}</td>
<td>{{ quote.viewToken }}</td>
<td>{{ quote.request.business.name }}</td>
<td>{{ total }}</td>
<td>
<!-- THIS IS WHERE I WANT TO SHOW THE SHOW BUTTON -->
<i class="icon-search"></i> SHOW
</td>
</tr>
{% endfor %}
<tr>
<td colspan="3"></td>
<td>TOTAL (AUD): </td>
<td>{{ grandTotal }}</td>
<td></td>
</tr>
</tbody>
</table>
{# display navigation #}
<div class="navigation">
{{ knp_pagination_render(logrecords) }}
</div>
{% endblock list_table %}
If I understand correctly, you wanna add a new route with custom action and templates to your list view.
The first you have to do is to modify your Admin as following:
// Add a new route to your admin
protected function configureRoutes(RouteCollection $collection)
{
$collection->add('custom_show_action', $this->getRouterIdParameter().'/customshow');
}
// Final Step is to add your custom route and a template to the listMapper
protected function configureListFields(ListMapper $listMapper)
{
// Optional you can change the list layout with the following function
// and to there some calculation on the visible entries.
$this->setTemplate('list', '::custom_list_layout.html.twig');
// ...
$listMapper
// ...
->add('_action', 'actions', array(
'actions' => array(
'view' => array(),
'edit' => array(),
'custom_show_action' => array('template' => '::your_template.html.twig'),
)
))
;
// ...
}
I recommend to calculate values in the controller. In my case I've done this for an invoice bundle in the following way:
// Acme/DemoBundle/Controller/AdminController
public function listAction()
{
if (false === $this->admin->isGranted('LIST')) {
throw new AccessDeniedException();
}
$datagrid = $this->admin->getDatagrid();
$formView = $datagrid->getForm()->createView();
$money_open = 0;
$money_payed = 0;
$money_referal = 0;
foreach($datagrid->getResults() as $key => $object) {
if ($object->getPayedAt()) {
$money_payed += $object->getPrice();
if ($object->getReferal() && $object->getReferalPrice() > 0) {
$money_referal += $object->getReferalPrice();
}
} else {
$money_open += $object->getPrice();
}
}
// set the theme for the current Admin Form
$this->get('twig')->getExtension('form')->renderer->setTheme($formView, $this->admin->getFilterTheme());
return $this->render($this->admin->getTemplate('list'), array(
'action' => 'list',
'form' => $formView,
'datagrid' => $datagrid,
'money_open' => $money_open,
'money_payed' => $money_payed,
'money_referal' => $money_referal,
));
}
As you can see my money calculation is done in controller and I only have to set it to the template.
Related
I would like to display the values in tmp ,tmp2 ,tmp3 as a table using the list.html.twig file. I tried using a form to display the values but I can't understand how to pass the values to the twig file to make a table containing these values (name , age , task)
The only way I can display these values is by using echo for each value in all__users
Here is the code of my controlleur:
/**
* #Route("/list", name="list_Users")
*/
public function list()
{
$form = $this->createFormBuilder()
->add('name', RangeType::class)
->add('age', RangeType::class)
->add('task', RangeType::class)
->getForm();
$all_Users = $this->getDoctrine()
->getRepository(User::class)
->findAll();
if (!$all_Users) {
throw $this->createNotFoundException(
'database is empty or there was an error connecting to db'
);
}
for ($x =0; $x < count($all_Users); $x++ ){
echo "$x";
$tmp = $all_Users[$x]->getName();
$tmp2 =$all_Users[$x]->getAge();
$tmp3 = $all_Users[$x]->getTask();
echo "$tmp ,$tmp2 , $tmp3 \n";
echo "\n";
}
return $this->render('User/list.html.twig', [
'form' => $form->createView(),
]);
}
This should work. But you need to render 'users' too. Or you could write your own extension.
<tr>
{% for property_title in users|keys %}
<td>{{ property_title }}</td>
{% endfor %}
</tr>
{% for user in users%}
<tr>
{% for field in users|keys %}
<td>{{ attribute(user, field) }}</td>
{% endfor %}
</tr>
{% endfor %}
If you want render form as table. Look here. It should answer all your questions.
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.
i have an app for pizza ordering. i have entity orders. When i am submitting order i have problem, because i have checkboxes for ingredients and i am saving it as array.
Entity/Orders
/**
* #Assert\NotBlank(
* message="please select!")
* #Assert\NotNull(
* message="please select!")
* #ORM\Column(name="ingredients", type="array")
*
*/
protected $ingredients;
public static function getIngredientsOptions(){
return array('cheese','tomatoes','salami','onions','mushroom', 'bacon','ham','vegetables','peppers','olives');
}
DefaultController
private function buildForm($order) {
return $this->createFormBuilder($order)
->add('name','text',array('required'=>false))
->add('address','textarea',array('required'=>false))
->add('phone','number',array('required'=>false))
->add('email','text',array('required'=>false))
->add('box','choice',array(
'choices' => Orders::getBoxOptions()))
->add('ingredients','choice',array(
'choices' => Orders::getIngredientsOptions(),
'expanded' => true,
'multiple' => true))
->add('delivery','choice',array(
'choices' => Orders::getDeliveryOptions(),
'expanded' => true))
->add('save','submit')
->getForm();
}
/**
* #Route("/new", name="new_order")
* #Template()
*/
public function orderAction(Request $request)
{
$order = new Orders();
$form = $this->buildForm($order);
$form->handleRequest($request);
if ($form->isValid()) {
$order = $form->getData();
$em = $this->getDoctrine()->getManager();
$em->persist($order);
$em->flush();
return $this->forward('S1500238090PizzaBundle:Default:index');
}
return array('form' => $form->createView());
}
index.html.twig
<h3>Orders</h3>
<table border>
<tr>
<th>ID</th>
<th>Name</th>
<th>Address</th>
<th>Phone</th>
<th>E-Mail</th>
<th>Box</th>
<th>Ingredients</th>
<th>Delivery</th>
</tr>
{% for order in orders %}
<tr>
<td>{{order.id}}</td>
<td>{{order.name}}</td>
<td>{{order.address}}</td>
<td>{{order.phone}}</td>
<td>{{order.email}}</td>
<td>{{boxOptions[order.box]}}</td>
<td>{{ingredientsOptions[order.ingredients]}}</td>
<td>{{deliveryOptions[order.delivery]}}</td>
<td>
Edit
Delete
</td>
</tr>
{% endfor %}
</table>
New order
i don't know how to save ingredients array correctly and after that render it.
I found out that,I have to change index.html.twig ingredients tag with the following:
<td>{% for ingredient in order.ingredients %}
{{ingredient}}
{% endfor %}
</td>
First I've read documents for both Collection Field Type and How to Embed a Collection of Forms ... The example is about one entity (Task) that has one-to-many relation with another entity (Tag), and I understand it, but I can not adapt it to what I want!
To make it simpler, let say I have a Task entity, this task entity has some relations with other objects like user and project (each task can have one user and one project)
I want to make one form, inside this form a list of Tasks, each task in one row of a table that shows information like task.title, task.startdate, task.user.name, task.user.company.name, task.project.name, And it has 2 fields editable, textbox "Description" and checkbox "active". You can edit multiple tasks and submit the form using one button at the bottom of the table in the main form, so basically you should be able to update multiple records in one transaction (instead of making one form and one submit button per row and therefor one record update per submit).
I have many issues with this complicated design:
First I wanted to follow the sample to embed a collection of forms inside the main form, So I made a Form Type for my Task that should be like one form per row. I made these files:
Form Type for Task:
// src/Acme/TaskBundle/Form/Type/TaskType.php
namespace Acme\TaskBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
class TaskType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('description', 'text', ['label' => false, 'required' => false, 'attr' => ['placeholder' => 'description']]);
$builder->add('active', 'checkbox', ['label' => false, 'required' => false, 'data' => true]);
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults(array(
'data_class' => 'Acme\TaskBundle\Entity\Task',
));
}
public function getName()
{
return 'taskType';
}
}
Form Type for main form:
// src/Acme/TaskBundle/Form/Type/SaveTasksType.php
namespace Acme\TaskBundle\Form\Type;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;
use Acme\TaskBundle\Form\Type\TaskType.php;
class SaveTasksType extends AbstractType
{
public function buildForm(FormBuilderInterface $builder, array $options)
{
$builder->add('tasksCollection', 'collection', ['type' => new TaskType()]);
$builder->add('tasksSubmit', 'submit', ['label' => 'Save']);
}
public function setDefaultOptions(OptionsResolverInterface $resolver)
{
$resolver->setDefaults([
'attr' => ['class' => 'form-horizontal'],
'method' => 'POST'
]);
}
public function getName()
{
return 'saveTasksType';
}
}
Tasks Form Controller:
// src/Acme/TaskBundle/Controller/ManageTasksController.php
namespace Acme\TaskBundle\Controller;
use Acme\TaskBundle\Entity\Task;
use Acme\TaskBundle\Form\Type\SaveTaskType;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class ManageTasksController extends Controller
{
public function showListAction(Request $request)
{
$repository = $this->getDoctrine()->getRepository('ExampleBundle:Task');
$tasks = $repository->findAll();
$taskSaveForm = $this->createForm(new SaveTasksType(['tasks' => $tasks]));
return $this->render('AcmeTaskBundle:Task:list.html.twig', array(
'taskSaveForm' => $taskSaveForm->createView(),
));
}
}
Task Form Twig Template (just related part):
<div class="innerAll">
{{ form_start(taskSaveForm) }}
{{ form_errors(taskSaveForm) }}
<table class="table table-bordered table-striped table-primary list-table">
<thead>
<tr>
<th>Task ID</th>
<th>Title</th>
<th>Start Date</th>
<th>User</th>
<th>Company</th>
<th>Project</th>
<th>Description</th>
<th>Active</th>
</tr>
</thead>
<tbody>
{% for task in taskSaveForm.tasksCollection %}
<tr>
<td>{{ task.id }}</td>
<td>{{ task.title }}</td>
<td>{{ task.startDate }}</td>
<td>{{ task.userName }}</td>
<td>{{ task.companyName }}</td>
<td>{{ task.projectName }}</td>
<td>{{ form_widget(task.description) }}</td>
<td>{{ form_widget(task.active) }}</td>
<td></td>
</tr>
{% endfor %}
</tbody>
</table>
<div>{{ form_row(taskSaveForm.tasksSubmit) }}</div>
{{ form_end(taskSaveForm) }}
</div>
BUT there is an issue here, when I get the result from query builder it is a mess of arrays containing objects in them, I get an error about
The form's view data is expected to be an instance of class Acme\TaskBundle\Entity\Task, but is a(n) array. You can avoid this error by setting the "data_class" option to null or by adding a view transformer that transforms a(n) array to an instance of Acme\TaskBundle\Entity\Task.
This is the query:
createQueryBuilder()
->select(
"
task.id,
task.title,
task.startDate,
task.description,
user.name as userName,
company.name as companyName,
project.name as projectName,
"
)
->from('Acme\TaskBundle\Entity\Task', 'task')
->innerJoin('task.project', 'project')
->innerJoin('task.user', 'user')
->innerJoin('Acme\TaskBundle\Entity\Company', 'company', 'with', 'store.company = company')
->where('task.active = :isActive')->setParameter('isActive', true);
Soooo, I used Partial Objects guide to see if it can help, it helps to make the task object in the query result and I could extract it and send it to form, but still it seems the rest of form is unaware of the rest of objects...
Ok, so maybe I'm choosing the wrong approach, I'm not sure! please if you have any suggestions about what should I do, put a note here... I'm struggling with this for more than a week! Thanks in advance for your time! Even if you don't put any note, I appreciate that you spend time reading my very long question! Thanks! :)
Here's a start on a possible solution. The example below takes a single entity Skills and presents all of them on a single page. What I don't know is whether this technique can be used to persist children objects. I would expect one could loop through the returned data and persist as required.
The code below results in a page with a list of all possible Skills and a checkbox for declaring each enabled or enabled.
In a controller:
$skills = $em->getRepository("TruckeeMatchingBundle:Skill")->getSkills();
$formSkills = $this->createForm(new SkillsType(), array('skills' => $skills));
...
if ($request->getMethod() == 'POST') {
$formSkills->handleRequest($request);
foreach ($skills as $existingSkill) {
$em->persist($existingSkill);
}
}
...
return ['formSkills' => $formSkills->createView(),...]
In a template:
{% for skill in formSkills.skills %}
{{ skill.vars.value.skill }}
<input type="hidden" name="skills[skills][{{ loop.index0 }}][skill]" value="{{ skill.vars.value.skill }}">
<input type="checkbox" name="skills[skills][{{ loop.index0 }}][enabled]"
{%if skill.vars.value.enabled %}checked="checked"{%endif%}
{% endfor %}
I use a different strategy. My TWIG file is similar to that of Monica's question. But has a few but very useful differences. Here your code:
{{ form_start(form) }}
{% for docente in docentes %}
Id: <input type="integer" name="{{ docente.id }}" required="required" style="width:30px" value="{{ docente.id }}" readonly>
Apellido: <input type="text" name="{{ docente.apellido }}" required="required" style="width: 80px" value="{{ docente.apellido }}" readonly>
Nombres: <input type="text" name="{{ docente.nombres }}" required="required" style="width: 80px" value="{{ docente.nombres }}" readonly>
Discrecional: <input type="checkbox" name="D{{ docente.id }}" value="{{ docente.discrecional }}" {% if docente.discrecional==1 %}checked{% endif %}> <br>
<br>
{% endfor %}
<input type="submit" value="Grabar" />
{{ form_end(form) }}
In TWIG file, I proceed to create a different name for each record in the form for the "discrecional" field. This will help me to identify each record in the controller. Watch up.
Once the user presses the "submit" button I perform an iteration in my Controller file, as shown below:
if ($form->isSubmitted() && $form->isValid()) {
$i=0;
foreach ($defaultData as $value) {
$data2= array('id' =>$request->request->get($defaultData[$i]['id']),
'discrecional' =>$request->request->get('D'.$defaultData[$i]['id']));
if (($request->request->get('D'.$defaultData[$i]['id'])== '0' and $defaultData[$i]['discrecional']=='0') or
($request->request->get('D'.$defaultData[$i]['id'])== NULL and $defaultData[$i]['discrecional']=='1'))
{
$em->getRepository('BackendBundle:Docentes')->findDocenteFiltId2($data2);
}
$i=$i+1;
}
But the update of registers, is a work that is done in my Repository file through a query using UPDATE, instead of doing it in the Controller file. To avoid unnecessary queries and a server overload, I only do an UPDATE of records that have previously changed. In the example, the following lines in my controller check if there has been a change in the record (in my case, I'm just editing a field called "discrecional". If the field has changed, then I call the query and update the record):
if (($request->request->get('D'.$defaultData[$i]['id'])== '0' and $Data[$i]['discrecional']=='0') or
($request->request->get('D'.$defaultData[$i]['id'])== NULL and $defaultData[$i]['discrecional']=='1'))
{
$em->getRepository('BackendBundle:Docentes')->findDocenteFiltId2($data2);
}
My complete Controller file is here:
public function discrecionalAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$defaultData= $em->getRepository('BackendBundle:Docentes')->buscarDocentesActivos2();
// construimos un formulario "vacĂo" sin campos definido
$form = $this->createFormBuilder($defaultData);
$form = $form->getForm();
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$i=0;
foreach ($defaultData as $value) {
$data2= array('id' =>$request->request->get($defaultData[$i]['id']),
'discrecional' =>$request->request->get('D'.$defaultData[$i]['id']));
if (($request->request->get('D'.$defaultData[$i]['id'])== '0' and $defaultData[$i]['discrecional']=='0') or
($request->request->get('D'.$defaultData[$i]['id'])== NULL and $defaultData[$i]['discrecional']=='1'))
{
$em->getRepository('BackendBundle:Docentes')->findDocenteFiltId2($data2);
}
$i=$i+1;
}
return $this->redirectToRoute('docentes_discrecional');
}
return $this->render('docentes/discrecional.html.twig', array(
'docentes' =>$defaultData,
'form' => $form->createView() ));
}
My complete first Repository query is here:
public function buscarDocentesActivos2()
{
$fields = array('d.id', 'd.apellido', 'd.nombres', 'd.discrecional');
$query = $this->getEntityManager()->createQueryBuilder();
$query
->select($fields)
->from('BackendBundle:Docentes', 'd')
->where('d.activo=true')
->orderBy('d.apellido, d.nombres');
$consulta = $query->getQuery()->getResult();
return $consulta;
}
My complete final Repository query with the UPDATE function is here:
public function findDocenteFiltId2($filtro)
{
if (is_null($filtro['discrecional'])){
$discrec= '0';
};
if ($filtro['discrecional']=='0'){
$discrec= '1';
};
$em = $this->getEntityManager();
$consulta = $em->createQuery('
UPDATE BackendBundle:Docentes d
SET d.discrecional = :disc
WHERE d.id = :idver
');
$consulta->setParameters(array(
'idver' => $filtro['id'],
'disc' => $discrec,
));
return $consulta->getArrayResult();
}
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 ?