PHPUnit and ZF2 Services - php

I have a little problem when creating tests with PHPUnit.
Here is my setup :
protected function setUp()
{
$serviceManager = Bootstrap::getServiceManager();
$this->mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface');
$this->mockConnection = $this->getMock('Zend\Db\Adapter\Driver\ConnectionInterface');
$this->mockDriver->expects($this->any())->method('checkEnvironment')->will($this->returnValue(true));
$this->mockDriver->expects($this->any())->method('getConnection')->will($this->returnValue($this->mockConnection));
$this->mockPlatform = $this->getMock('Zend\Db\Adapter\Platform\PlatformInterface');
$this->mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface');
$this->mockDriver->expects($this->any())->method('createStatement')->will($this->returnValue($this->mockStatement));
$this->adapter = new Adapter($this->mockDriver, $this->mockPlatform);
$this->sql = new Sql($this->adapter);
$mockTableGateway = $this->getMock('Zend\Db\TableGateway\TableGateway', array(), array(), '', false);
$maiFormuleRevisionTable = $this->getMockBuilder('Maintenance\Model\BDD\PMaiFormulerevisionTable')
->setMethods(array())
->setConstructorArgs(array($mockTableGateway, $this->adapter, $this->sql))
->getMock();
$maiFormulerevisionService = $this->getMockBuilder('Maintenance\Service\Model\PMaiFormulerevisionService')
->setMethods(array())
->setConstructorArgs(array($maiFormuleRevisionTable))
->getMock();
$this->assertTrue($maiFormulerevisionService instanceof PMaiFormulerevisionService);
$this->controller = new RevisionsController($maiFormulerevisionService);
$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);
}
Here is the test for my function :
public function testEditFormuleActionCanBeAccessed()
{
$this->routeMatch->setParam('action', 'loadformule');
$this->routeMatch->setParam('idformule', '23');
$result = $this->controller->dispatch($this->request);
$response = $this->controller->getResponse();
$this->assertEquals(200, $response->getStatusCode());
}
And my Controler :
public function loadformuleAction()
{
try {
$iStatus = 0;
$iMaiFormuleRevisionId = (int) $this->params('idformule');
$oFormule = $this->maiFormulerevisionService->selectByIdOrCreate($iMaiFormuleRevisionId);
$maiFormulerevisionForm = new PMaiFormulerevisionForm($oFormule);
if ($this->getRequest()->isPost()) {
/* etc ... */
}
$viewModel = new ViewModel();
$viewModel->setTerminal(true);
$viewModel->setVariables([
'maiFormulerevisionForm' => $maiFormulerevisionForm,
'iMaiFormuleRevisionId' => $oFormule->getMaiFormuleRevisionId(),
'iStatus' => $iStatus
]);
return $viewModel;
} catch (\Exception $e) {
throw new \Exception($e);
}
}
But when I try to run my test, it shows an error, and I point that my test don't go into my service, when I call it ($this->maiFormulerevisionService) :
1) MaintenanceTest\Controller\RevisionsControllerTest::testEditFormuleActionCanBeAccessed
Exception: Argument 1 passed to Maintenance\Form\PMaiFormulerevisionForm::__construct() must be an instance of Maintenance\Model\PMaiFormulerevision, null given
I don't understand why my mock doesn't work ...
Thanks for your answers :)
Edit :
Hum ... when I try this :
$maiFormulerevisionService = new PMaiFormulerevisionService($maiFormuleRevisionTable);
Instead of this :
$maiFormulerevisionService = $this->getMockBuilder('Maintenance\Service\Model\PMaiFormulerevisionService')
->setMethods(array())
->setConstructorArgs(array($maiFormuleRevisionTable))
->getMock();
It goes into the service but not into the TableGateway specified in the constructor of the service ($maiFormuleRevisionTable) ... so it still doesn't work ...

You set a mock, but you also have to set what your mock returns when calling the method selectByIdOrCreate. Since you do:
$oFormule = $this->maiFormulerevisionService->selectByIdOrCreate($iMaiFormuleRevisionId);
$maiFormulerevisionForm = new PMaiFormulerevisionForm($oFormule);
The mock will return null for the selectByIdOrCreate method as long as you don't set a return value for this method.
Try to add a mock method like this:
$mock = $maiFormulerevisionService;
$methodName = 'selectByIdOrCreate';
$stub = $this->returnValue($maiFormuleRevisionTable);
$mock->expects($this->any())->method($methodName)->will($stub);

Related

Symfony FatalThrowableError : Call to a member function getId() on null

I am doing an e-commerce site, and in the end I realized a bug when modifying the informations of the customers informations:
the error is as follows:
Uncaught PHP Exception Error: "Call to a member function getId() on null"
at C:\wamp64\www\caviar-pro\src\Controller\CustomerController.php line 339
Here is the part of the code that is problematic:
The complete code is the following:
public function updateAction(Request $request): Response
{
$configuration = $this->requestConfigurationFactory->create($this->metadata, $request);
$this->isGrantedOr403($configuration, ResourceActions::UPDATE);
$resource = $this->findOr404($configuration);
$form = $this->resourceFormFactory->create($configuration, $resource);
$oldInfo = clone $resource;
$oldAddressInfo = $oldInfo->getDefaultAddress() ? clone $oldInfo->getDefaultAddress() : null;
if (in_array($request->getMethod(), ['POST', 'PUT', 'PATCH'], true) && $form->handleRequest($request)->isValid()) {
/** #var CustomerInterface $resource */
$resource = $form->getData();
$defaultAddress = $resource->getDefaultAddress();
if (!$defaultAddress->getId()) {
$defaultAddress->setFirstName($resource->getFirstName());
$defaultAddress->setLastName($resource->getLastName());
}
/** #var ResourceControllerEvent $event */
$event = $this->eventDispatcher->dispatchPreEvent(ResourceActions::UPDATE, $configuration, $resource);
if ($event->isStopped() && !$configuration->isHtmlRequest()) {
throw new HttpException($event->getErrorCode(), $event->getMessage());
}
if ($event->isStopped()) {
$this->flashHelper->addFlashFromEvent($configuration, $event);
if ($event->hasResponse()) {
return $event->getResponse();
}
return $this->redirectHandler->redirectToResource($configuration, $resource);
}
try {
$this->resourceUpdateHandler->handle($resource, $configuration, $this->manager);
$valueChangedPersonnalInfo = $this->compareCustomer($oldInfo, $resource);
$valueChangedAddress = $oldAddressInfo ? $this->compareAddressCustomer($oldAddressInfo, $resource->getDefaultAddress()) : [];
$valueChanged = array_merge($valueChangedPersonnalInfo, $valueChangedAddress);
/*sending email according to template bo*/
/** #var Email $email */
$email = $this->manager->getRepository('App\Entity\Email\Email')->findOneByCode(MailerManager::ACCOUNT_MODIFICATION_MAILER_CODE);
$user = $this->getUser();
$emailManager = $this->emailManager->letterParagraphBy($email->getContent(), $email, $user->getCustomer());
$emailToSend = $this->renderView('#SyliusShop/Email/userInfoChange.html.twig', [
'infoChanged' => $valueChanged,
'email' => $email,
'emailManager' => $emailManager,
]);
$emailFrom = [$email->getFromEmail() => $email->getFromName()];
$this->mailerManager->sendMail($resource->getEmail(), $email->getSubject(), $emailToSend, $emailFrom);
} catch (UpdateHandlingException $exception) {
if (!$configuration->isHtmlRequest()) {
return $this->viewHandler->handle(
$configuration,
View::create($form, $exception->getApiResponseCode())
);
}
$this->flashHelper->addErrorFlash($configuration, $exception->getFlash());
return $this->redirectHandler->redirectToReferer($configuration);
}
$postEvent = $this->eventDispatcher->dispatchPostEvent(ResourceActions::UPDATE, $configuration, $resource);
if (!$configuration->isHtmlRequest()) {
$view = $configuration->getParameters()->get('return_content', false) ? View::create($resource, Response::HTTP_OK) : View::create(null, Response::HTTP_NO_CONTENT);
return $this->viewHandler->handle($configuration, $view);
}
$this->flashHelper->addSuccessFlash($configuration, ResourceActions::UPDATE, $resource);
if ($postEvent->hasResponse()) {
return $postEvent->getResponse();
}
return $this->redirectHandler->redirectToResource($configuration, $resource);
}
if (!$configuration->isHtmlRequest()) {
return $this->viewHandler->handle($configuration, View::create($form, Response::HTTP_BAD_REQUEST));
}
$initializeEvent = $this->eventDispatcher->dispatchInitializeEvent(ResourceActions::UPDATE, $configuration, $resource);
if ($initializeEvent->hasResponse()) {
return $initializeEvent->getResponse();
}
$carrousels = $this->manager->getRepository(Carrousel::class)->findOneBy(['code' => 'my_account_carrousel', 'enabled' => true]);
$view = View::create()
->setData([
'configuration' => $configuration,
'metadata' => $this->metadata,
'resource' => $resource,
$this->metadata->getName() => $resource,
'form' => $form->createView(),
'carrousels' => $carrousels,
])
->setTemplate($configuration->getTemplate(ResourceActions::UPDATE . '.html'))
;
return $this->viewHandler->handle($configuration, $view);
}
If someone could tell me the solution to my problem I'm interested because I'm stuck on this part of my site for a while.
By !$defaultAddress->getId(), id will always exists except the entity is not yet persisted or null.
On you case, $defaultAddress is null. (dump the variable to see).
I think, you should do something like:
if (!$defaultAddress) {
$defaultAddress = new AddressObject(); //change this to your address class
$defaultAddress->setFirstName($resource->getFirstName());
$defaultAddress->setLastName($resource->getLastName());
}

Create a new OneToOne relation on the registration

I am new with Symfony and FOSUserBundle, I have a relation One To One between User and Stream, when a user want to register he check if he is a streamer or not. If he is a streamer I want to create a new stream in relation with the user so here is the registerAction from FOSUserBundle that I'm overriding :
$form = $this->container->get('fos_user.registration.form');
$formHandler = $this->container->get('fos_user.registration.form.handler');
$confirmationEnabled = $this->container->getParameter('fos_user.registration.confirmation.enabled');
$process = $formHandler->process($confirmationEnabled);
if ($process) {
$user = $form->getData();
/*This is what I added*/
if($user->getIsStreamer()){
$em = $this->getDoctrine()->getManager();
$stream = new Stream();
$stream->setUser($user);
$em->persist($stream);
$em->flush();
}
/********/
$authUser = false;
if ($confirmationEnabled) {
$this->container->get('session')->set('fos_user_send_confirmation_email/email', $user->getEmail());
$route = 'fos_user_registration_check_email';
} else {
$authUser = true;
$route = 'fos_user_registration_confirmed';
}
$this->setFlash('fos_user_success', 'registration.flash.user_created');
$url = $this->container->get('router')->generate($route);
$response = new RedirectResponse($url);
if ($authUser) {
$this->authenticateUser($user, $response);
}
return $response;
}
But nothing happened, what did I missed ?
You are missing the part that add the Stream to the user (and not only set the user of the stream).
First, be sure your association contains cascade={"persist"} to avoid need of manually persist the Stream :
/**
* #ORM\OneToOne(targetEntity="Stream", cascade={"persist"},
*/
protected $stream;
Then, change your setStream to make it calling $stream->setUser automatically :
public function setStream(Stream $stream = null)
{
$this->stream = $stream;
$stream->setUser($this); // Setter calling
return $this;
}
Now you can replace the logic of your condition like this :
if($user->getIsStreamer()){
$stream = new Stream();
$user->setStream($stream);
}
The association should be correctly stored when calling $em->flush at the end of your method.
In the case of FOSUB registration it should be :
$this->get('fos_user.user_manager')->updateUser($user);.
It's done in the confirmAction where your user is redirected in success.

soap response in array

I am trying to get a soap response in php. It keeps coming as an object onto my web browser but not as xml. WSDL shows as XML but not the response received. Below is my server side code. The soap server is Zend Soap
ini_set("soap.wsdl_cache_enabled", 0);
if (isset($_GET['wsdl'])){
$wsdl = 'http://localhost/webservice/soap';
$autoDiscover = new AutoDiscover();
$autoDiscover->setOperationBodyStyle(
array('use' => 'literal',
'namespace' => 'http://localhost/webservice/soap')
);
$autoDiscover->setBindingStyle(
array('style' => 'rpc',
'transport' => 'http://schemas.xmlsoap.org/soap/http')
);
$autoDiscover->setComplexTypeStrategy(new ArrayOfTypeComplex());
// $service is the class that does the handling of functions
$autoDiscover->setClass($service);
$autoDiscover->setUri($wsdl);
$response->getHeaders()->addHeaderLine('Content-Type', 'text/xml');
$response->setContent($autoDiscover->toXml());
} else {
$server = new Server('http://localhost/webservice/soap?wsdl'
);
// $service is the class that does the handling of functions
$server->setObject($service);
$response->setContent($server->handle());
}
return $response;
}
Service class
class service
{
/**
*
* #param string $Email
* #return int $Credit
*/
public function checkCredits($Email)
{
$validator = new email();
if (!$validator->isValid($Email))
{
return new \SoapFault('5', 'Please Provide an Email');
}
$rowset = $this->tableGateway->select(array('EMAIL'=>$Email))
$row = $rowset->current();
$credits = $row->CREDITS;
return $credits;
}
}
Request is :
try{
$sClient = new SoapClient('http://localhost/webservice/soap?wsdl');
$params = "email";
$response = $sClient->checkCredits($params);
var_dump($response);
} catch(SoapFault $e){
var_dump($e);
}
This is an example of how I handle my functions with SoapClient:
$client = new SoapClient('http://url/Service.svc?wsdl');
$var = array('arg' => 10,
'VA' => 48);
$varresponse = $client->Function($var);
print_r( $varresponse->FunctionResult);
Hope this will help you out.
Your soapserver should look a bit like this:
<?php
if(!extension_loaded("soap")){
dl("php_soap.dll");
}
ini_set("soap.wsdl_cache_enabled","0");
$server = new SoapServer("hello.wsdl");
function doHello($yourName){
return "Hello, ".$yourName;
}
$server->AddFunction("doHello");
$server->handle();
?>
How did you set up yours? Do you return anything?
Now, your client should look like this:
<?php
try{
$sClient = new SoapClient('http://localhost/test/wsdl/hello.xml');
$params = "Name";
$response = $sClient->doHello($params);
var_dump($response);
} catch(SoapFault $e){
var_dump($e);
}
?>

Zend Framework not deleting table entry

I am trying to delete a post from my table but the code is deleting all table data and not just the one post.
delete.php
<?php
class Form_Delete extends Zend_Form
{
public function __construct()
{
#parent::__construct($options);
$this->setName('Delete');
$id = new Zend_Form_Element_Hidden('id');
$title = new Zend_Form_Element_Hidden('Title');
$description = new Zend_Form_Element_Hidden('Description');
$submit = new Zend_Form_Element_Submit('Delete');
$submit->setAttrib('id', 'submitbutton');
$cancel = new Zend_Form_Element_Submit('cancel');
$cancel->setAttrib('id', 'cancelbutton');
$this->addElements( array( $id, $title, $description, $submit, $cancel ));
}
}
and my controller code
public function deleteAction()
{
//action body
$request = $this->getRequest();
$postid = (int)$request->getParam('id');
$post = new Model_DbTable_Posts();
$result = $post->getPost($postid);
$this->view->post = $result;
if(!Zend_Auth::getInstance()->hasIdentity()) {
$this->_redirect('posts/view/id/'.$postid);
}
$identity = Zend_Auth::getInstance()->getIdentity();
$acl = new Model_Acl();
if( $acl->isAllowed( $identity['Role'] ,'posts','edit','delete') ) {
$deleteForm = new Form_Delete();
$deleteModel = new Model_DbTable_Posts();
if ($this->getRequest()->isPost()) {
if ($deleteForm->isValid($request->getPost())) {
$deleteModel->delete($dpostid);
$this->_redirect('index/index');
}
}
$this->view->deleteForm = $deleteForm;
}
I have tried for hours to get this working but can ether get it to delete all or nothing. Any help would be great!
You need to pass delete() the where clause to evaluate. Try:
$where = $deleteModel->getAdapter()->quoteInto('id = ?', $dpostid);
$deleteModel->delete($where);
Change 'id' to whatever your primary key is.
Also #parent::__construct($options); in your form class is a little odd. Change that to parent::__construct();. No need to supress the error if you don't generate one.

Why is Zend DB Update not posting?

Other modules in the application are updating, besides this one.
Here, I am using a model mapper in attempts to update a row set, as found in http://framework.zend.com/manual/en/learning.quickstart.create-model.html
public function SomeAction()
{
$mapper = new Application_Model_SomeMapper();
$model = new Application_Model_SomeModel(); //getters and setters
// action body
$request = $this->getRequest();
$data = $this->_request->getParams();
$someId = $data['someid'];
$get = $mapper->find($someId, new Application_Model_SomeModel, true); //find the row by id, and return array
/*
instantiating a form object and adding "submit"
*/
$form = new Module_Form_FormName();
$form->setAction("/module/controller/action/params/$someId");
$form->setMethod('post');
$form->setName('some_edit');
$submit = $form->createElement('button', 'submit');
$submit->setAttrib('ignore',true);
$submit->setLabel('Edit Something');
$form->addElement($submit);
if ($this->_request->isPost())
{
if($form->isValid($request->getPost()))
{
$data = $this->_request->getPost();
if(empty($data['some_id' ]))
{
$data['tier_models_id'] = NULL;
}
unset($data['submit']);
$setters = $model->setId($data['id'])
->setField1($data['field_1']);
if ($mapper->save($someId, $setters))
{
$this->_redirect("/index/");
}
}
}
$form->populate($tier);
$this->view->form = $get;
}
Here is an example of the save mapper function, except I've included an additional $id parameter
public function save(Application_Model_Guestbook $guestbook)
{
$data = array(
'email' => $guestbook->getEmail(),
'comment' => $guestbook->getComment(),
'created' => date('Y-m-d H:i:s'),
);
if (null === ($id = $guestbook->getId())) {
unset($data['id']);
$this->getDbTable()->insert($data);
} else {
$this->getDbTable()->update($data, array('id = ?' => $id)); //not happening, although the 'id' is passed as a param
}
}
Is there something missing?
Try this instead
$where = $this->getDbTable()->getAdapter()->quoteInto('id = ?', $id);
$this->getDbTable()->update($data, $where);

Categories