I currently have a big problem on my Symfony project since I switched to version 4.4. My versioning was correctly done but I have a "Project" page that displays all the projects created in the website database. The problem is that the project creation is feasible and the projects are well displayed in the database but the site does not display them. I checked the code of my ProjectController and everything seems to be normal. However, I changed one line of it because the syntax for calling classes through the getRepository has changed between versions 3.4 and 4.4. Before, I used to call my classes by doing getRepository('App::$className') with a className variable whose value changed depending on the classes that were called on my page. Now a getRepository doesn't accept the 'App::' and so I had to define the path of my classes by setting getRepository('App::$className'). And I have the impression that the problem can come from here because maybe it only retrieves the first class called and doesn't go to the next one.
I can't solve the problem because it's not an error message, so I'm looking for a needle in a haystack. I don't have a lot of experience with symfony because I've never used this framework before, so I came up with this project that just needed an upgrade.
I put the code of my ProjectController just below to better understand my explanation.
<?php
namespace App\Controller;
use App\Entity\Advancement;
use App\Entity\Alert;
use App\Entity\Project;
use App\Entity\State;
use App\Form\Search\ProjectSearchType;
use App\Form\Type\AdvancementType;
use App\Form\Type\AlertType;
use App\Form\Type\ProjectType;
use App\Model\ProjectSearch;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\DBAL\Exception\ForeignKeyConstraintViolationException;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\ParamConverter;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Security;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
class ProjectController extends BaseController
{
protected function listAction($className, $params = array())
{
return array_merge(array(
'title' => 'title.' . $className . '.list',
'pagetitle' => 'title.' . $className . '.list',
$className . 's' => $this->getRepository('App\\Entity\\' . $className)->getList(),
), $params);
}
protected function createAction($request, $project, $form, $className)
{
if ($form->handleRequest($request)->isSubmitted() && $form->handleRequest($request)->isValid()) {
$entity = $form->getData();
$entity->setCreatedBy($this->getUser());
$entity->setCreatedAt(new \DateTime());
$this->persist($entity);
$this->flush();
$this->addFlash('success', 'flash.success.created.' . $className);
return $this->redirect($this->generateUrl('project_edit', array('id' => $project->getId())) . '#tab-' . $className);
}
return array(
'form' => $form->createView(),
'title' => $this->trans('title.' . $className . '.create'),
'pagetitle' => $this->trans('title.' . $className . '.create'),
'projectLink' => $this->generateUrl('project_edit', array('id' => $project->getId())),
);
}
protected function editAction($request, $project, $form, $className, $class)
{
if ($form->handleRequest($request)->isSubmitted() && $form->handleRequest($request)->isValid()) {
$entity = $form->getData();
$entity->setUpdatedBy($this->getUser());
$entity->setUpdatedAt(new \DateTime());
$this->flush();
$this->addFlash('success', 'flash.success.updated.' . $className);
return $this->redirect($this->generateUrl('project_edit', array('id' => $project->getId())) . '#tab-' . $className);
}
return array(
'form' => $form->createView(),
'title' => $this->trans('title.' . $className . '.edit', array('%name%' => $class)),
'pagetitle' => $this->trans('title.' . $className . '.edit', array('%name%' => $class)),
'projectLink' => $this->generateUrl('project_edit', array('id' => $project->getId())),
);
}
protected function deleteAction($class, $className)
{
try {
$this->remove($class);
$this->flush();
$this->addFlash('success', 'flash.success.deleted.' . $className);
} catch (ForeignKeyConstraintViolationException $e) {
$this->addFlash('error', 'flash.error.deleted.' . $className);
}
if ($className != 'project') {
$id = $class->getProject()->getId();
$route = $this->generateUrl('project_edit', array('id' => $id)) . '#tab-' . $className;
} else {
$route = $this->generateUrl('project_list');
}
return $this->redirect($route);
}
/**
* #Route("/projects/{page}", defaults={"page":1}, name="project_list")
* #Template("Project\listProject.html.twig")
* #Security("has_role('ROLE_READER')")
*/
public function projectListAction(Request $request, $page = 1)
{
$searchModel = new ProjectSearch();
if (!$this->isGranted('ROLE_READER')) {
$searchModel->setCompany($this->getUser()->getCompany());
}
$searched = $searchModel;
$searchForm = $this->get('form.factory')->createNamed('', ProjectSearchType::class, $searchModel, array(
'method' => 'GET',
'action' => $this->generateUrl('project_list') . '#results',
));
$searchForm->handleRequest($request);
if ($searchForm->isSubmitted() && $searchForm->isValid()) {
$searched = $searchForm->getData();
}
$pager = $this->getPager($page, $this->getRepository(Project::class)->getSearchQuery($searched), $searchModel->getPerPage());
return $this->listAction('project', array(
'pager' => $pager,
'projects' => $pager->getCurrentPageResults(),
'searchForm' => $searchForm->createView(),
));
}
/**
* #Route("/project/new",name="project_create")
* #Template("Project\createProject.html.twig")
* #Security("has_role('ROLE_READER')")
*/
public function projectCreateAction(Request $request)
{
$project = new Project();
$project->setBeginAt(new \DateTime());
$project->setState($this->getRepository(State::class)->find(State::INITIALIZED));
$project->setCompany($this->getUser()->getCompany());
$form = $this->createForm(ProjectType::class, $project, array(
'mode' => 'create',
'display_company_select' => $this->isGranted('ROLE_SUPERADMIN'),
));
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$project = $form->getData();
$project->setCreatedBy($this->getUser());
$this->persist($project);
$this->flush();
$this->addFlash('success', 'flash.success.created.project');
return $this->redirect($this->generateUrl('project_list'));
}
return array(
'modeEdit' => false,
'form' => $form->createView(),
'title' => $this->trans('title.project.create'),
'pagetitle' => $this->trans('title.project.create'),
'project' => $project,
);
}
/**
* #Route("/project/edit/{id}", name="project_edit")
* #Template("Project\createProject.html.twig")
* #Security("is_granted('edit', project)")
*/
public function projectEditAction(Request $request, Project $project)
{
$project = $this->getManager(Project::class)->initForEdition($project);
$form = $this->createForm(ProjectType::class, $project, array(
'display_company_select' => $this->isGranted('ROLE_SUPERADMIN'),
));
try {
$alerts = $this->getRepository(Alert::class)->getAlertsByProject($project);
} catch (Exception $e) {
$alerts = array(new Alert());
}
try {
$advancements = $this->getRepository(Advancement::class)->getAdvancementsByProject($project);
} catch (Exception $e) {
$advancements = array(new Advancement());
}
if ($form->handleRequest($request)->isSubmitted() && $form->handleRequest($request)->isValid()) {
$project = $this->getManager(Project::class)->updateProject($form->getData());
$this->flush();
$this->addFlash('success', 'flash.success.updated.project');
return $this->redirect($this->generateUrl('project_list'));
}
return array(
'modeEdit' => true,
'form' => $form->createView(),
'advancements' => $advancements,
'alerts' => $alerts,
'title' => $this->trans('title.project.edit', array('%name%' => $project)),
'pagetitle' => $this->trans('title.project.edit', array('%name%' => $project)),
'project' => $project,
);
}
/**
* #Route("/project/view/{id}", name="project_view")
* #Template("viewProject.html.twig")
* #Security("is_granted('view', project)")
*/
public function projectViewAction(Request $request, Project $project)
{
return $this->projectEditAction($request, $project);
}
/**
* #Route("/project/delete/{id}", name="project_delete")
*/
public function projectDeleteAction(Request $request, Project $project)
{
// #todo : voir le delete en cascade
return $this->deleteAction($project, 'project');
}
/**
* #Route("/project/print", name="project_print")
*/
public function projectPrintAction(Request $request)
{
$projects = $this->getRepository(Project::class)->findById(array_keys($request->request->all()));
$html = '';
foreach ($projects as $project) {
$html .= $this->renderView('resume.html.twig', array(
'project' => $project,
));
}
if ($html == '') {
$this->addFlash('error', 'warn.project.check');
return $this->redirect($this->generateUrl('project_list'));
}
// Génération du pdf
$html2pdf = $this->get('html2pdf_factory')->create();
$html2pdf->WriteHTML($html);
return new Response(
$html2pdf->Output(),
200,
array(
'Content-Type' => 'application/pdf; charset=utf-8',
)
);
}
/**
* #Route("/advancements",name="advancement_list")
* #Template("listAdvancement.html.twig")
*/
public function advancementListAction(Request $request)
{
return $this->listAction('advancement');
}
/**
* #Route("/advancement/new/{id}",name="advancement_create")
* #Template("createAdvancement.html.twig")
*/
public function advancementCreateAction(Request $request, Project $project)
{
$avancement = new Advancement();
$avancement->setProject($project);
$form = $this->createForm(AdvancementType::class, $avancement, array());
return $this->createAction($request, $project, $form, 'advancement');
}
/**
* #Route("/advancement/edit/{id}", name="advancement_edit")
* #Template("createAdvancement.html.twig")
*/
public function advancementEditAction(Request $request, Advancement $advancement)
{
$form = $this->createForm(AdvancementType::class, $advancement, array());
return $this->editAction($request, $advancement->getProject(), $form, 'advancement', $advancement);
}
/**
* #Route("/advancement/delete/{id}", name="advancement_delete")
*/
public function advancementDeleteAction(Request $request, Advancement $advancement)
{
return $this->deleteAction($advancement, 'advancement');
}
/**
* #Route("/alerts",name="alert_list")
* #Template("listAlert.html.twig")
*/
public function alertListAction(Request $request)
{
return $this->listAction('alert');
}
/**
* #Route("/alert/new/{id}",name="alert_create")
* #Template("createAlert.html.twig")
*/
public function alertCreateAction(Request $request, Project $project)
{
$alerte = new Alert();
$alerte->setProject($project);
$form = $this->createForm(AlertType::class, $alerte, array());
return $this->createAction($request, $project, $form, 'alert');
}
/**
* #Route("/alert/edit/{projectid}/{alertid}", name="alert_edit")
* #ParamConverter("project", class="Project", options={"id" = "projectid"})
* #ParamConverter("alert", class="Alert", options={"id" = "alertid"})
* #Template("createAlert.html.twig")
*/
public function alertEditAction(Request $request, Project $project, Alert $alert)
{
$form = $this->createForm(AlertType::class, $alert, array());
return $this->editAction($request, $project, $form, 'alert', $alert);
}
/**
* #Route("/alert/delete/{id}", name="alert_delete")
*/
public function alertDeleteAction(Request $request, Alert $alert)
{
return $this->deleteAction($alert, 'alert');
}
/**
* #Template("_projectLoads.html.twig")
*/
public function projectLoadsAction(Request $request, $projectId)
{
$project = $this->getManager(Project::class)->getProject($projectId);
$slippingCalendar = $this->get('date.handler')->slippingCalendar();
// Returned loads can be outside start-end, so we limit to this year
$validLoads = array();
foreach ($project->getLoads() as $l) {
$id = $l->getUser()->getId();
$year = $l->getYear();
if (!array_key_exists($id, $validLoads)) {
$validLoads[$id] = array('user' => $l->getUser());
}
$validLoads[$id][$year][] = $l;
}
$activities = $this->getActivitiesByMonth($project);
return array(
'project' => $project,
'loads' => $validLoads,
'activities' => $activities,
'slippingCalendar' => $slippingCalendar, // yyyy-11-01, yyyy-12-01, yyyy-01-01,...
);
}
/**
* Build an array with the project activies spread by month and year
* #param Project $project
* #return array
*/
protected function getActivitiesByMonth(Project $project)
{
$validActivities = array();
foreach ($project->getActivities() as $a) {
$id = $a->getUser()->getId();
$date = $a->getMondayDate();
$i = 0;
do {
$year = $date->format('Y');
$month = $date->format('m');
if (!array_key_exists($id, $validActivities)) {
$validActivities[$id] = array('user' => $a->getUser());
}
if (!array_key_exists($year, $validActivities[$id])) {
$validActivities[$id][$year] = array();
}
$validActivities[$id][$year][$month][] = $a->getTimeDay($i);
$date->modify('+1 day');
$i++;
} while ($i < 7);
}
return $validActivities;
}
}
I am looking to see the projects in the database reappear on my web page.
The table is empty, although it should be populated by the projects in the DB.
everyone.
I am building symphony 5 project, but I have an issue.
The URL is not redirecting after I create or edit an element.
But in other functions, the redirectToRoute() function works.
Strange problem...
These are my controller code.
Please check it and let me know what I missed.
Thanks.
/**
* #Route("/list", name="animals")
*/
public function animals(): Response
{
if (!$this->getUser()) {
$this->redirectToRoute('app_login');
}
$animals = $this->getUser()->getAnimals();
return $this->render('animals/overview.html.twig', [
'animals' => $animals,
]);
}
And
/**
* #Route("/create", name="animal_create")
*/
public function create(Request $request, EntityManagerInterface $entityManager): Response
{
$animal = new Animal();
$customer = $this->em()->getRepository(Customer::class)->findOneBy(array('id' => $request->request->get('customer')));
$animal->setCustomer($customer);
$form = $this->createForm(AnimalType::class, $animal, [
'csrf_protection' => false,
]);
$form->handleRequest($request);
if (!$form->isSubmitted() || !$form->isValid()) {
return new Response('failed');
}
$customer->addAnimal($animal);
$entityManager->persist($animal);
$entityManager->flush();
return $this->redirectToRoute('animals');
}
/**
* #Route("/{id}/update", name="animal_update")
*/
public function update(Request $request, Animal $animal, EntityManagerInterface $entityManager): Response
{
$form = $this->createForm(AnimalType::class, $animal, [
'csrf_protection' => false,
]);
$form->handleRequest($request);
if (!$form->isSubmitted() || !$form->isValid()) {
return new Response('failed');
}
$entityManager->persist($animal);
$entityManager->flush();
return $this->redirectToRoute('animals');
}
You must redirect to the index route only if the form is submitted and validated, otherwise the form must be displayed.
The symfony documentation explains this perfectly:
public function create(Request $request, EntityManagerInterface $entityManager): Response
{
$animal = new Animal();
$customer = $this->em()->getRepository(Customer::class)->findOneBy(array('id' => $request->request->get('customer')));
$animal->setCustomer($customer);
$form = $this->createForm(AnimalType::class, $animal);
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$animal = $form->getData();
$customer->addAnimal($animal);
$entityManager->persist($animal);
$entityManager->flush();
return $this->redirectToRoute('animals');
}
// Here it's the name of your twig template for animal creation
return $this->renderForm('animal/create.html.twig', [
'form' => $form,
]);
}
Do the same thing for the update action.
I am having this issue where I'm only able to get the error message. I have some tables where student id is the foreign key, however even thou the id number is not any of the tables it still gives the message "You cannot delete this Student" but won't pass there if it can be deleted
public function findBystudentid($studentid)
{
$record= $this->getEntityManager()->getRepository('AcmeDemoBundle:record')->findBy(['studentid' => $studentid]);
$lecture = $this->getEntityManager()->getRepository('AcmeDemoBundle:lecture')->findBy(['studentid' => $studentid]);
$faculty = $this->getEntityManager()->getRepository('AcmeDemoBundle:faculty')->findBy(['studentid' => $studentid]);
if ($record||$lecture||$faculty){
return true;
} else {
return false;
}
}
public function deleteAction(Request $request, $studentid)
{
$form = $this->createDeleteForm($studentid);
$form->handleRequest($request);
$em = $this->getDoctrine()->getManager();
$deletable = $em->getRepository('AcmeDemoBundle:Student')->findBystudentid($studentid);
if ($deletable) {
$this->addFlash('error','ERROR! You cannot delete this Student' );
}
else
{
$em->remove($deletable);
$em->flush();
$this->addFlash('error','Student Deleted');
}
return $this->redirect($this->generateUrl('Student'));
}
First, your naming is a bit off. You need to fix it as it tends to be a bit confusing. With that in mind, I suggest you do it like this:
1. Controller method to check if student is deletable:
private function isStudentDeletable($studentid)
{
$em = $this->getEntityManager();
$record= $em->getRepository('AcmeDemoBundle:record')->findBy(['studentid' => $studentid]);
if ( $record ){
return false;
}
$lecture = $em->getRepository('AcmeDemoBundle:lecture')->findBy(['studentid' => $studentid]);
if ( $lecture ){
return false;
}
$faculty = $em->getRepository('AcmeDemoBundle:faculty')->findBy(['studentid' => $studentid]);
if ( $faculty ){
return false;
}
return true;
}
2. Controller's action to invoke the above
public function deleteAction(Request $request, $studentid)
{
$form = $this->createDeleteForm($studentid);
$form->handleRequest($request);
$deletable = $this->isStudentDeletable($studentid);
if (!$deletable) {
$this->addFlash('error','ERROR! You cannot delete this Student' );
}
else
{
$em = $this->getDoctrine()->getManager();
$student = $em->getRepository('AcmeDemoBundle:Student')->find($studentid)
$em->remove($student);
$em->flush();
$this->addFlash('error','Student Deleted');
}
return $this->redirect($this->generateUrl('Student'));
}
Hope this help and clarifies a bit.
I think you are calling findBystudentid wrong because findBystudentid is not in the Entity.
Here is the updated version
public function deleteAction(Request $request, $studentid)
{
$form = $this->createDeleteForm($studentid);
$form->handleRequest($request);
$em = $this->getDoctrine()->getManager();
$deletable = $this->findBystudentid($studentid);
if ($deletable) {
$this->addFlash('error','ERROR! You cannot delete this Student' );
} else {
$em->getRepository('AcmeDemoBundle:Student')->findBy(['studentid' => $studentid])
$em->remove($deletable);
$em->flush();
$this->addFlash('error','Student Deleted');
}
return $this->redirect($this->generateUrl('Student'));
}
Also findBystudentid should be a private function
private function findByStudentId() ...
I am new to ZF2 application. I trying the documentation part as n practice provided in ZF2 doc. Working on album module it is find with the other parts but as it comes to delete. My delete album part is not working and also not showing any error as well
My files for delete code as
//src/Album/Model/AlbumTable.php
namespace Album\Model;
use Zend\Db\TableGateway\TableGateway;
Class AlbumTable
{
protected $tableGateway;
public function __construct(TableGateway $tableGateway) {
$this->tableGateway = $tableGateway;
}
public function fetchAll()
{
$resultSet = $this->tableGateway->select();
return $resultSet;
}
public function getAlbum($id)
{
$id = (int) $id;
$rowset = $this->tableGateway->select(array('id'=> $id));
$row = $rowset->current();
if(!$row)
{
throw new Exception("Could not find row - $id");
}
return $row;
}
public function saveAlbum(Album $album)
{
$data = array(
'artist' => $album->artist,
'title' => $album->title,
);
$id = (int) $album->id;
if($id == 0)
{
$this->tableGateway->insert($data);
}
else
{
if($this->getAlbum($id))
{
$this->tableGateway->update($data, array('id' => $id));
}
else
{
throw new \Exception("Album ID does not exists");
}
}
}
public function deleteAlbum($id)
{
$this->tableGateway->delete(array($id => (int) $this->id));
}
}
Other Album Controller file is as
//src/Album/Controller/AlbumController.php
namespace Album\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Album\Model\Album; // For the Form Display
use Album\Form\AlbumForm; // album manipulation form view
Class AlbumController extends AbstractActionController
{
protected $albumTable;
public function getAlbumTable()
{
if(!$this->albumTable)
{
$sm = $this->getServiceLocator();
$this->albumTable = $sm->get('Album\Model\AlbumTable');
}
return $this->albumTable;
}
public function indexAction()
{
//Albums Retreiving from Model and Passing to View for listing the albums
return new ViewModel(array(
'albums' => $this->getAlbumTable()->fetchAll(),
));
}
public function addAction()
{
$form = new AlbumForm();
$form->get('submit')->setValue('Add');
$request = $this->getRequest();
if($request->isPost())
{
$album = new Album();
// printf($form);die();
$form->setInputFilter($album->getInputFilter());
$form->setData($request->getPost());
if($form->isValid())
{
$album->exchangeArray($form->getData());
$this->getAlbumTable()->saveAlbum($album);
//Redirect to list of albums
$this->redirect()->toRoute('album');
}
}
return array('form' => $form);
}
public function editAction()
{
$id = (int) $this->params()->fromRoute('id',0);
if(!$id)
{
return $this->redirect()->toRoute('album',array(
'action' => 'add'
));
}
// Get the Album with the specified id. An exception is thrown
// if it cannot be found, in which case go to the index page.
try
{
$album = $this->getAlbumTable()->getAlbum($id);
}
catch(\Exception $ex)
{
return $this->redirect()->toRoute('album', array(
'action' => 'index'
));
}
$form = new AlbumForm();
$form->bind($album);
$form->get('submit')->setAttribute('value', 'Edit');
$request = $this->getRequest();
if($request->isPost())
{
$form->setInputFilter($album->getInputFilter());
$form->setData($request->getPost());
if($form->isValid())
{
$this->getAlbumTable()->saveAlbum($album);
//Redirect to list all albums
return $this->redirect()->toRoute('album');
}
}
return array(
'id' => $id,
'form' => $form,
);
}
public function deleteAction()
{
$id = (int) $this->params()->fromRoute('id',0);
if(!$id)
{
return $this->redirect()->toRoute('album');
}
$request = $this->getRequest();
if($request->isPost())
{
$del = $request->getPost('del','No');
if($del=='Yes')
{
$id = (int)$request->getPost('id');
$this->getAlbumTable()->deleteAlbum($id);
}
//Redirect to list of Albums
return $this->redirect()->toRoute('album');
}
return array(
'id' => $id,
'album' => $this->getAlbumTable()->getAlbum($id),
);
}
}
Deleting File view as follows
//view/album/album/delete.phtml
$title = "Delete Album";
$this->headTitle($title);
?>
<h1><?php echo $this->escapeHtml($title); ?></h1>
<p>
Are you sure want to delete the album
'<?php echo $this->escapeHtml($album->title); ?>' By
'<?php echo $this->escapeHtml($album->artist); ?>' ??
</p>
<?php
$url = $this->url('album', array(
'action' => 'delete',
'id' => $this->id,
));
?>
<form action='<?php echo $url; ?>' method='post'>
<div>
<input type='hidden' name='id' value='<?php echo (int)$album->id; ?>'/>
<input type='submit' name='del' value='Yes'/>
<input type="submit" name="del" value='No'/>
</div>
</form>
When i'm trying to delete the album it askes for confirmation and when pressed as yes it get to album lists again showing the same record within the lists.
Maybe you are having problem with the first files itself for delete operation
In your //src/Album/Model/AlbumTable.php file
You stated the deleteAlbum function as
public function deleteAlbum($id)
{
$this->tableGateway->delete(array($id => (int) $this->id));
}
Rewrite the code as
public function deleteAlbum($id)
{
$this->tableGateway->delete(array('id' => (int) $id));
}
Hopefullly this was the only problem as you said it doesn't showing any error or at least exception.
I'm having issues trying to unit test an action which uses ZfcUser for authentication. I need some way to mock the ZfcUser Controller plugin but I'm not so sure how to do this. I've managed to successfully produce some unit tests for tables and models but the controller requires a lot of injected objects and is causing problems. Does anyone know how to set up the ZfcUser mocks to successfully unit test a controller?
Here is my test (copied from the ZF2 tutorial):
<?php
namespace SmsTest\Controller;
use SmsTest\Bootstrap;
use Sms\Controller\SmsController;
use Zend\Http\Request;
use Zend\Http\Response;
use Zend\Mvc\MvcEvent;
use Zend\Mvc\Router\RouteMatch;
use Zend\Mvc\Router\Http\TreeRouteStack as HttpRouter;
use PHPUnit_Framework_TestCase;
class SmsControllerTest extends PHPUnit_Framework_TestCase
{
protected $controller;
protected $request;
protected $response;
protected $routeMatch;
protected $event;
protected function setUp()
{
$serviceManager = Bootstrap::getServiceManager();
$this->controller = new SmsController();
$this->request = new Request();
$this->routeMatch = new RouteMatch(array('controller' => 'index'));
$this->event = new MvcEvent();
$config = $serviceManager->get('Config');
$routerConfig = isset($config['router']) ? $config['router'] : array();
$router = HttpRouter::factory($routerConfig);
$this->event->setRouter($router);
$this->event->setRouteMatch($this->routeMatch);
$this->controller->setEvent($this->event);
$this->controller->setServiceLocator($serviceManager);
}
/* Test all actions can be accessed */
public function testIndexActionCanBeAccessed()
{
$this->routeMatch->setParam('action', 'index');
$result = $this->controller->dispatch($this->request);
$response = $this->controller->getResponse();
$this->assertEquals(200, $response->getStatusCode());
}
}
I tried the following in the setUp method:
$mockAuth = $this->getMock('ZfcUser\Entity\UserInterface');
$authMock = $this->getMock('Zend\Authentication\AuthenticationService');
$authMock->expects($this->any())
->method('hasIdentity')
->will($this->returnValue(true));
$authMock->expects($this->any())
->method('getIdentity')
->will($this->returnValue(array('user_id' => 1)));
But I'm not sure how to inject this in to the controller instance.
Lets pretend my index action code is just as follows:
public function indexAction() {
//Check if logged in
if (!$this->zfcUserAuthentication()->hasIdentity()) {
return $this->redirect()->toRoute('zfcuser/login');
}
return new ViewModel(array(
'success' => true,
));
}
Test Results:
1) SmsTest\Controller\SmsControllerTest::testIndexActionCanBeAccessed
Zend\ServiceManager\Exception\ServiceNotFoundException: Zend\ServiceManager\ServiceManager::get was unable to fetch or create an instance for zfcUserAuthentication
/var/www/soap-app.localhost/Zend/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:450
/var/www/soap-app.localhost/Zend/vendor/zendframework/zendframework/library/Zend/ServiceManager/AbstractPluginManager.php:110
/var/www/soap-app.localhost/Zend/vendor/zendframework/zendframework/library/Zend/Mvc/Controller/PluginManager.php:90
/var/www/soap-app.localhost/Zend/vendor/zendframework/zendframework/library/Zend/Mvc/Controller/AbstractController.php:276
/var/www/soap-app.localhost/Zend/vendor/zendframework/zendframework/library/Zend/Mvc/Controller/AbstractController.php:291
/var/www/soap-app.localhost/Zend/module/Sms/src/Sms/Controller/SmsController.php:974
/var/www/soap-app.localhost/Zend/module/Sms/src/Sms/Controller/SmsController.php:974
/var/www/soap-app.localhost/Zend/module/Sms/src/Sms/Controller/SmsController.php:158
/var/www/soap-app.localhost/Zend/vendor/zendframework/zendframework/library/Zend/Mvc/Controller/AbstractActionController.php:87
/var/www/soap-app.localhost/Zend/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php:468
/var/www/soap-app.localhost/Zend/vendor/zendframework/zendframework/library/Zend/EventManager/EventManager.php:208
/var/www/soap-app.localhost/Zend/vendor/zendframework/zendframework/library/Zend/Mvc/Controller/AbstractController.php:108
/var/www/soap-app.localhost/Zend/module/Sms/test/SmsTest/Controller/SmsControllerTest.php:57
The line which causes this exception is the controller is: if (!$this->zfcUserAuthentication()->hasIdentity()) {
That line relates to line 974 in the SmsController.
It's obvious I don't have access to the ZfcUserAuthentication service, so the question is, How do I mock the ZfcUserAuthentication service and inject it in to my Controller?
To continue the theme how would I go about mocking a logged in user to successfully test my action is working to specification?
The ZfcUser documentation suggests that this is a plugin so you need to inject this into the controller.
You will need to amend your class names to pick up the ZfcUser classes
Your mocks will also need to be addapted as getIdenty returns a different object.
The following worked for me - insert in your phpunit setUp() method.
$serviceManager = Bootstrap::getServiceManager();
$this->controller = new RegisterController();
$this->request = new Request();
$this->routeMatch = new RouteMatch(array('controller' => 'add'));
$this->event = new MvcEvent();
$config = $serviceManager->get('Config');
$routerConfig = isset($config['router']) ? $config['router'] : array();
$router = HttpRouter::factory($routerConfig);
$this->event->setRouter($router);
$this->event->setRouteMatch($this->routeMatch);
$this->controller->setEvent($this->event);
$this->controller->setServiceLocator($serviceManager);
$mockAuth = $this->getMock('ZfcUser\Entity\UserInterface');
$ZfcUserMock = $this->getMock('ZfcUser\Entity\User');
$ZfcUserMock->expects($this->any())
->method('getId')
->will($this->returnValue('1'));
$authMock = $this->getMock('ZfcUser\Controller\Plugin\ZfcUserAuthentication');
$authMock->expects($this->any())
->method('hasIdentity')
-> will($this->returnValue(true));
$authMock->expects($this->any())
->method('getIdentity')
->will($this->returnValue($ZfcUserMock));
$this->controller->getPluginManager()
->setService('zfcUserAuthentication', $authMock);
There may be an easier way would welcome other thoughts.
This is how I did it.
<?php
namespace IssueTest\Controller;
use Zend\Test\PHPUnit\Controller\AbstractHttpControllerTestCase;
class IssueControllerTest extends AbstractHttpControllerTestCase
{
protected $serviceManager;
public function setUp()
{
$this->setApplicationConfig(
include '/media/policybubble/config/application.config.php'
);
parent::setUp();
$ZfcUserMock = $this->getMock('ZfcUser\Entity\User');
$ZfcUserMock->expects($this->any())
->method('getId')
->will($this->returnValue('1'));
$authMock = $this->getMock(
'ZfcUser\Controller\Plugin\ZfcUserAuthentication'
);
$authMock->expects($this->any())
->method('hasIdentity')
->will($this->returnValue(true));
$authMock->expects($this->any())
->method('getIdentity')
->will($this->returnValue($ZfcUserMock));
$this->serviceManager = $this->getApplicationServiceLocator();
$this->serviceManager->setAllowOverride(true);
$this->serviceManager->get('ControllerPluginManager')->setService(
'zfcUserAuthentication', $authMock
);
}
public function testIndexActionCanBeAccessed()
{
$this->dispatch('/issue');
$this->assertResponseStatusCode(200);
$this->assertModuleName('Issue');
$this->assertControllerName('Issue\Controller\Issue');
$this->assertControllerClass('IssueController');
$this->assertMatchedRouteName('issue');
}
public function testAddActionRedirectsAfterValidPost()
{
$issueTableMock = $this->getMockBuilder('Issue\Model\IssueTable')
->disableOriginalConstructor()
->getMock();
$issueTableMock->expects($this->once())
->method('saveIssue')
->will($this->returnValue(null));
$this->serviceManager->setService('Issue\Model\IssueTable', $issueTableMock);
$postData = array(
'title' => 'Gun Control',
'id' => '',
);
$this->dispatch('/issue/add', 'POST', $postData);
$this->assertResponseStatusCode(302);
$this->assertRedirectTo('/issue');
}
public function testEditActionRedirectsAfterValidPost()
{
$issueTableMock = $this->getMockBuilder('Issue\Model\IssueTable')
->disableOriginalConstructor()
->getMock();
$issueTableMock->expects($this->once())
->method('saveIssue')
->will($this->returnValue(null));
$this->serviceManager->setService('Issue\Model\IssueTable', $issueTableMock);
$issueTableMock->expects($this->once())
->method('getIssue')
->will($this->returnValue(new \Issue\Model\Issue()));
$postData = array(
'title' => 'Gun Control',
'id' => '1',
);
$this->dispatch('/issue/edit/1', 'POST', $postData);
$this->assertResponseStatusCode(302);
$this->assertRedirectTo('/issue');
}
public function testDeleteActionRedirectsAfterValidPost()
{
$postData = array(
'title' => 'Gun Control',
'id' => '1',
);
$this->dispatch('/issue/delete/1', 'POST', $postData);
$this->assertResponseStatusCode(302);
$this->assertRedirectTo('/issue');
}
}
<?php
namespace Issue\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Issue\Model\Issue;
use Issue\Form\IssueForm;
class IssueController extends AbstractActionController
{
protected $issueTable;
public function indexAction()
{
if (!$this->zfcUserAuthentication()->hasIdentity()) {
return;
}
return new ViewModel(
array(
'issues' => $this->getIssueTable()->fetchAll(
$this->zfcUserAuthentication()->getIdentity()->getId()
),
)
);
}
public function addAction()
{
if (!$this->zfcUserAuthentication()->hasIdentity()) {
return $this->redirect()->toRoute('issue');
}
$form = new IssueForm();
$form->get('submit')->setValue('Add');
$request = $this->getRequest();
if ($request->isPost()) {
$issue = new Issue();
$form->setInputFilter($issue->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$issue->exchangeArray($form->getData());
$this->getIssueTable()->saveIssue(
$issue,
$this->zfcUserAuthentication()->getIdentity()->getId()
);
// Redirect to list of issues
return $this->redirect()->toRoute('issue');
}
}
return array('form' => $form);
}
public function editAction()
{
if (!$this->zfcUserAuthentication()->hasIdentity()) {
return $this->redirect()->toRoute('issue');
}
$id = (int)$this->params()->fromRoute('id', 0);
if (!$id) {
return $this->redirect()->toRoute(
'issue', array(
'action' => 'add'
)
);
}
// Get the Issue with the specified id. An exception is thrown
// if it cannot be found, in which case go to the index page.
try {
$issue = $this->getIssueTable()->getIssue($id);
} catch (\Exception $ex) {
return $this->redirect()->toRoute(
'issue', array(
'action' => 'index'
)
);
}
$form = new IssueForm();
$form->bind($issue);
$form->get('submit')->setAttribute('value', 'Edit');
$request = $this->getRequest();
if ($request->isPost()) {
$form->setInputFilter($issue->getInputFilter());
$form->setData($request->getPost());
if ($form->isValid()) {
$this->getIssueTable()->saveIssue(
$issue,
$this->zfcUserAuthentication()->getIdentity()->getId()
);
// Redirect to list of issues
return $this->redirect()->toRoute('issue');
}
}
return array(
'id' => $id,
'form' => $form,
);
}
public function deleteAction()
{
if (!$this->zfcUserAuthentication()->hasIdentity()) {
return $this->redirect()->toRoute('issue');
}
$id = (int)$this->params()->fromRoute('id', 0);
if (!$id) {
return $this->redirect()->toRoute('issue');
}
$request = $this->getRequest();
if ($request->isPost()) {
$del = $request->getPost('del', 'No');
if ($del == 'Yes') {
$id = (int)$request->getPost('id');
$this->getIssueTable()->deleteIssue($id);
}
// Redirect to list of issues
return $this->redirect()->toRoute('issue');
}
return array(
'id' => $id,
'issue' => $this->getIssueTable()->getIssue($id)
);
}
public function getIssueTable()
{
if (!$this->issueTable) {
$sm = $this->getServiceLocator();
$this->issueTable = $sm->get('Issue\Model\IssueTable');
}
return $this->issueTable;
}
}