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;
}
}
Related
I would like to deny access to the private areas on my website. But I don't know what I am doing wrong.
I don't want to use Acl::DENY as the default rule.
Instead I am using Acl::ALLOW as the global rule and denying access to the private resources.
Here is my code:
<?php
use Phalcon\Acl;
use Phalcon\Acl\Role;
use Phalcon\Acl\Resource;
use Phalcon\Events\Event;
use Phalcon\Mvc\User\Plugin;
use Phalcon\Mvc\Dispatcher;
use Phalcon\Acl\Adapter\Memory as AclList;
class SecurityPlugin extends Plugin {
public function getAcl() {
if (!isset($this->persistent->acl)) {
$acl = new AclList();
$acl->setDefaultAction(Acl::ALLOW);
$roles = array(
'admin' => new Role('Administrators'),
'guests' => new Role('Guests')
);
foreach ($roles as $role) {
$acl->addRole($role);
}
//Private area resources
$privateResources = array(
'admin' => array('index'),
'products' => array('index', 'search', 'new');
foreach ($privateResources as $resource => $actions) {
$acl->addResource(new Resource($resource), $actions);
}
foreach ($privateResources as $resource => $actions) {
foreach ($actions as $action) {
$acl->deny('Guests', $resource, $action);
}
}
}
return $this->persistent->acl;
}
public function beforeDispatch(Event $event, Dispatcher $dispatcher) {
$auth = $this->session->get('auth');
if (!$auth) {
$role = 'Guests';
} else {
$role = 'Admin';
}
$controller = $dispatcher->getControllerName();
$action = $dispatcher->getActionName();
$acl = $this->getAcl();
$allowed = $acl->isAllowed($role, $controller, $action);
if ($allowed != Acl::ALLOW) {
$dispatcher->forward(array(
'controller' => 'errors',
'action' => 'show401'
));
$this->session->destroy();
return false;
}
}
}
Thank you, for trying to help me.
You forgot to actually assign your ACL definitions to $this->persistent->acl
public function getAcl() {
if (!isset($this->persistent->acl)) {
$acl = new AclList();
...
//The acl is stored in session
$this->persistent->acl = $acl;
}
return $this->persistent->acl;
}
By looking at your code, I am guessing you used the Phalcon INVO example for this SecurityPlugin?
If so, refer to line 88. If not, this is a nice and easy example that can help you.
Hi can someone help me to prevent bjyauthorize to catch my api event error raised?
bjyauthorize redirect non logged user to login form as added to config. But since my api are allowed for all roles even for guest i just want it to return Json error message catched by ApiProblemListener
ApplicationRest\Module.php
class Module implements
ConfigProviderInterface,
AutoloaderProviderInterface
{
public function onBootstrap(MvcEvent $e)
{
$app = $e->getApplication();
$sm = $app->getServiceManager();
$events = $app->getEventManager();
$listener = $sm->get('ApplicationRest\ApiAuthenticationListener');
$events->getSharedManager()->attach('ApplicationRest\Controller', 'dispatch', $listener, 500);
$events->attach('render', array($this, 'onRender'), 100);
$events->attach($sm->get('ApplicationRest\ApiProblemListener'));
}
/**
* Listener for the render event
* Attaches a rendering/response strategy to the View.
*
* #param \Zend\Mvc\MvcEvent $e
*/
public function onRender($e)
{
$result = $e->getResult();
if (!$result instanceof RestfulJsonModel) {
return;
}
//var_dump(123);exit();
$app = $e->getTarget();
$services = $app->getServiceManager();
$view = $services->get('View');
$restfulJsonStrategy = $services->get('ApplicationRest\RestfulJsonStrategy');
$events = $view->getEventManager();
// register at high priority, to "beat" normal json strategy registered
// via view manager
$events->attach($restfulJsonStrategy, 500);
}
}
Have many modules and i am really thinking to move away my apiModule "ApplicationRest" to another project but don't really want to update model and service each time i make some updates on main project.
Any suggestions would welcome!
Thanks for your time!
EDIT: Provided more HeaderAuthentication class
class HeaderAuthentication implements AdapterInterface
{
const AUTHORIZATION_HEADER = 'Authorization';
const CRYPTO = 'sha256';
protected $request;
protected $repository;
public function __construct(RequestInterface $request, UserRepository $repository)
{
$this->request = $request;
$this->repository = $repository;
}
/**
* Authorization: Key={key} Timestamp={timestamp} Signature={signature}
* #return Result
*/
public function authenticate()
{
$request = $this->getRequest();
if (!$request instanceof Request) {
return;
}
$headers = $request->getHeaders();
// Check Authorization header presence
if (!$headers->has(static::AUTHORIZATION_HEADER)) {
return new Result(Result::FAILURE, null, array(
'Authorization header missing'
));
}
$authorization = $headers->get(static::AUTHORIZATION_HEADER)->getFieldValue();
// Validate public key
$publicKey = $this->extractPublicKey($authorization);
$user = $this->getUserRepository()
->findOneByApiSecret($publicKey);
if (null === $user) {
$code = Result::FAILURE_IDENTITY_NOT_FOUND;
return new Result($code, null, array(
'User not found based on public key'
));
}
// Validate signature
$signature = $this->extractSignature($authorization);
/*$hmac = $this->getHmac($request, $user);
if ($signature !== $hmac) {
$code = Result::FAILURE_CREDENTIAL_INVALID;
return new Result($code, null, array(
'Signature does not match'
));
}*/
return new Result(Result::SUCCESS, $user);
}
}
ApiAuthenticationListener
class ApiAuthenticationListener
{
protected $adapter;
public function __construct(HeaderAuthentication $adapter)
{
$this->adapter = $adapter;
}
public function __invoke(MvcEvent $event)
{
$result = $this->adapter->authenticate();
if (!$result->isValid()) {
$response = $event->getResponse();
// Set some response content
$response->setStatusCode(401);
return $response;
}
// All is OK
$event->setParam('user', $result->getIdentity());
}
}
I'm guessing you configured guards on your route. You need to tell BJYAuthorize, through your module config, that this controller or route shouldn't be protected.
'bjyauthorize' => [
'default_role' => 'guest',
...
'guards' => [
'BjyAuthorize\Guard\Controller' => [
// system tools
['controller' => 'Application\Controller\Api', 'roles' => [] ],
['controller' => 'error', 'roles' => []],
],
],
],
I cut out the nitty gritty that's app specific, but this type of thing is quickly solved. I had a similar need for CLI routes to be unprotected by what is otherwise, http auth.
I have a ZF2 application with 1 module and I am trying to use a class from another module called "CommonRestClient" located in the "vendor" directory.
The directory structure of this "vendor" directory is as under:
vendor
-->CommonRestClient
---->config
------>module.config.php
-->src
---->CommonRestClient
------->Service
--------->CommonRestClient.php
-->Module.php
vendor\CommonRestClient\config\module.config.php
================================================
<?php
return array();
?>
vendor\src\Module.php
======================
<?php
namespace CommonRestClient;
use Zend\Mvc\ModuleRouteListener;
use Zend\Mvc\MvcEvent;
use Zend\Http\Client as HttpClient;
use CommonRestClient\Service\CommonRestClient as CommonRestClient;
class Module
{
public function onBootstrap(MvcEvent $e)
{
$eventManager = $e->getApplication()->getEventManager();
$moduleRouteListener = new ModuleRouteListener();
$moduleRouteListener->attach($eventManager);
}
public function getConfig()
{
return include __DIR__ . '/config/module.config.php';
}
public function getAutoloaderConfig()
{
return array(
'Zend\Loader\StandardAutoloader' => array(
'namespaces' => array(
__NAMESPACE__ => __DIR__ . '/src/' . __NAMESPACE__,
),
),
);
}
public function getServiceConfig()
{
return array(
'factories' => array(
'CommonRestClient\Service\CommonRestClient' => function($sm) {
$httpClient = $sm->get('HttpClient');
$httpRestJsonClient = new CommonRestClient($httpClient);
return $httpRestJsonClient;
},
'HttpClient' => function($sm) {
$httpClient = new HttpClient();
$httpClient->setAdapter('Zend\Http\Client\Adapter\Curl');
return $httpClient;
},
),
);
}
}
vendor\src\CommonRestClient\Service\CommonRestClient.php
=========================================================
<?php
namespace CommonRestClient\Service;
use Zend\Http\Client as HttpClient;
use Zend\Http\Request;
use Zend\Stdlib\Parameters;
class CommonRestClient
{
protected $httpClient;
public function __construct(HttpClient $httpClient)
{
$this->httpClient = $httpClient;
}
public function get($url)
{
return $this->dispatchRequestAndDecodeResponse($url, "GET");
}
public function post($url, $data)
{
return $this->dispatchRequestAndDecodeResponse($url, "POST", $data);
}
public function put($url, $data)
{
return $this->dispatchRequestAndDecodeResponse($url, "PUT", $data);
}
public function delete($url)
{
return $this->dispatchRequestAndDecodeResponse($url, "DELETE");
}
protected function dispatchRequestAndDecodeResponse($url, $method, $data = null)
{
$request = new Request();
$request->getHeaders()->addHeaders(array(
'Content-Type' => 'application/x-www-form-urlencoded; charset=UTF-8'
));
$request->setUri($url);
$request->setMethod($method);
if ($data){
$request->setPost(new Parameters($data));
}
$response = $this->httpClient->dispatch($request);
# should interogate response status, throwing appropiate exceptions for error codes
return json_decode($response->getBody(), true);
}
}
So, in the main application module, I am trying to use the above class in a Model file, which looks like this:
<?php
namespace MyApplication\Model;
use CommonRestClient\Service\CommonRestClient as CommonRestClient;
class Users
{
protected $commonRestClient;
public function __construct(CommonRestClient $commonRestClient)
{
$this->commonRestClient = $commonRestClient;
}
public function getListOfUsers()
{
$url = 'http://xyz.google.com/getusers';
$jsonResponse = $this->commonRestClient->get($url);
return $jsonResponse;
}
}
I have configured MyApplication's application.config.php to use the "CommonRestClient" module.
The error I am recieving is:
Catchable fatal error: Argument 1 passed to
MyApplication\Model\Users::__construct() must be an instance of
CommonRestClient\Service\CommonRestClient, none given, called in
C:\Users\Public\myapp\myapplication\module\MyApplication\src\MyApplication\Controller\UsersController.php
on line 27 and defined in
C:\Users\Public\myapp\myapplication\module\MyApplication\src\MyApplication\Model\Users.php
on line 23
Can any one help me with what I could be missing here?
Thanks
In the constructor you defined for your Users class you specified a required argument of CommonRestClient which you are not supplying when creating the instance from your controller, so that's why you are getting the error.
You can either supply the argument yourself:
$users = new Users($this->getServiceLocator()->get('CommonRestClient\Service\CommonRestClient'));
or tell ZF how to do that using a factory:
public function getServiceConfig()
{
return array(
'factories' => array(
'Users' => function($sm) {
$commonRestClient = $sm->get('CommonRestClient\Service\CommonRestClient');
$users = new Users($commonRestClient);
return $users;
},
),
);
}
and then use the service locator to create the instance for you:
$users = $this->getServiceLocator()->get('Users');
I'm following this book, and I'm in chapter 3 and this code is returning me the following error: Fatal error: Class 'Users\Model\User' not found in /var/www/CommunicationApp/module/Users/src/Users/Controller/RegisterController.php on line 70
I want to know what is wrong with the code, or if it's not the code than what is it?
<?php
namespace Users\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Users\Form\RegisterForm;
use Users\Form\RegisterFilter;
use Users\Model\User;
use Users\Model\UserTable;
class RegisterController extends AbstractActionController
{
public function indexAction()
{
$form = new RegisterForm();
$viewModel = new ViewModel(array('form' => $form));
return $viewModel;
}
public function processAction()
{
if (!$this->request->isPost()) {
return $this->redirect()->toRoute(NULL , array(
'controller' => 'register',
'action' => 'index'
));
}
$post = $this->request->getPost();
$form = new RegisterForm();
$inputFilter = new RegisterFilter();
$form->setInputFilter($inputFilter);
$form->setData($post);
if (!$form->isValid()) {
$model = new ViewModel(array(
'error' => true,
'form' => $form,
));
$model->setTemplate('users/register/index');
return $model;
}
// Create user
$this->createUser($form->getData());
return $this->redirect()->toRoute(NULL , array(
'controller' => 'register',
'action' => 'confirm'
));
}
public function confirmAction()
{
$viewModel = new ViewModel();
return $viewModel;
}
protected function createUser(array $data)
{
$sm = $this->getServiceLocator();
$dbAdapter = $sm->get('Zend\Db\Adapter\Adapter');
$resultSetPrototype = new \Zend\Db\ResultSet\ResultSet();
$resultSetPrototype->setArrayObjectPrototype (new \Users\Model\User); //line 70
$tableGateway = new \Zend\Db\TableGateway\TableGateway('user' /* table name */, $dbAdapter, null, $resultSetPrototype);
$user = new User();
$user->exchangeArray($data);
$userTable = new UserTable($tableGateway);
$userTable->saveUser($user);
return true;
}
}
for a correct autoloading check if the model file is in the following directory
/module/Users/src/Users/Model/User.php
if is not zend can't autoload your model file and that triggers your error if (as you pointed out your classname and namespace in the model file is correct) the file is not placed there.
I am super new to doctrine and I just converted the Akrabat album rest api example to work with doctrine and it works well to show the data. But when i edit, delete or add albums it throws an error which says,
Fatal error: Call to undefined method Zend\Http\PhpEnvironment\Request::post()
Here's is my controller,
namespace Album\Controller;
use Zend\Mvc\Controller\AbstractActionController,
Zend\View\Model\ViewModel,
Album\Form\AlbumForm,
Doctrine\ORM\EntityManager,
Album\Entity\Album;
class AlbumController extends AbstractActionController
{
protected $em;
public function setEntityManager(EntityManager $em)
{
$this->em = $em;
}
public function getEntityManager()
{
if (null === $this->em) {
$this->em = $this->getServiceLocator()->get('Doctrine\ORM\EntityManager');
}
return $this->em;
}
public function indexAction()
{
return new ViewModel(array(
'albums' => $this->getEntityManager()->getRepository('Album\Entity\Album')->findAll()
));
}
public function addAction()
{
$form = new AlbumForm();
$form->get('submit')->setAttribute('label', 'Add');
$request = $this->getRequest();
if ($request->isPost()) {
$album = new Album();
$form->setInputFilter($album->getInputFilter());
$form->setData($request->post());
if ($form->isValid()) {
$album->populate($form->getData());
$this->getEntityManager()->persist($album);
$this->getEntityManager()->flush();
// Redirect to list of albums
return $this->redirect()->toRoute('album');
}
}
return array('form' => $form);
}
public function editAction()
{
$id = (int)$this->getEvent()->getRouteMatch()->getParam('id');
if (!$id) {
return $this->redirect()->toRoute('album', array('action'=>'add'));
}
$album = $this->getEntityManager()->find('Album\Entity\Album', $id);
$form = new AlbumForm();
$form->setBindOnValidate(false);
$form->bind($album);
$form->get('submit')->setAttribute('label', 'Edit');
$request = $this->getRequest();
if ($request->isPost()) {
$form->setData($request->post());
if ($form->isValid()) {
$form->bindValues();
$this->getEntityManager()->flush();
// Redirect to list of albums
return $this->redirect()->toRoute('album');
}
}
return array(
'id' => $id,
'form' => $form,
);
}
public function deleteAction()
{
$id = (int)$this->getEvent()->getRouteMatch()->getParam('id');
if (!$id) {
return $this->redirect()->toRoute('album');
}
$request = $this->getRequest();
if ($request->isPost()) {
$del = $request->post()->get('del', 'No');
if ($del == 'Yes') {
$id = (int)$request->post()->get('id');
$album = $this->getEntityManager()->find('Album\Entity\Album', $id);
if ($album) {
$this->getEntityManager()->remove($album);
$this->getEntityManager()->flush();
}
}
// Redirect to list of albums
return $this->redirect()->toRoute('default', array(
'controller' => 'album',
'action' => 'index',
));
}
return array(
'id' => $id,
'album' => $this->getEntityManager()->find('Album\Entity\Album', $id)->getArrayCopy()
);
}
}
What am i doing wrong here, I am not able to persist any changes that i make.
Because there's no post method. Try getPost(); see here Zend\Http\Request