Symfony2 entity manager get not working all the time - php

I found a strange issue in symfony2 (maybe is not strange and i did a mistake somewhere):
i'm trying to call an entity manager method that i defined in the entity class:
//Entity/organisation.php
/**
* #return string
*/
public function getApiUrl(){
return $this->api_url;
}
and i don't always get a return value for the same object
the call is made from a controller method:
private function addApiLog($organisationId, $callType, $eventInfo){
$em = $this->getEntityManager();
$organisation = $em->find('\WebAgenda\Entity\Organisation', $organisationId);
if (null === $organisation) {
die();
}
$apiUrl = $organisation->getApiUrl();
$apiKey = $organisation->getApiKey();
$fc = fopen("debug_api_log.txt", "a");
fwrite($fc, date("Y-m-d H:i:s")." - ".$callType." - ".$organisationId." - ".$organisation->getName()." - ".$apiUrl."\n");
fclose($fc);
if(trim($apiUrl)!='' && $apiUrl!='-'){
the 'addApiLog()' methos is called from different methods depending on the action and even though the organisationId that is passed to it is the same and i get the organisation object, sometimes the $organisation->getApiUrl() method doesn't return anything and the $organisation->getName(), always return the correct value: http://screencast.com/t/HQ2NuNfWSG9
What am I missing? Why i don't get values?
Thank you!

Replace $em = $this->getEntityManager();
With this $em = $this->getDoctrine()->getManager();
And then use your repository
$myRepo = $em->getRepository('NamespaceMyBundle:Organisation');
$organisation = $myRepo->find($organisationId);

You said the addApiLog() method is called from different methods depending on the action.
Maybe not all your methods have access to the Context ?

Related

Symfony - findOneOrFail returns array message

In my Symfony service I wanted to add small edit so I decided it's better to do it inside the class.
In my controller I am getting storyId (it's not table ID, it's a string with different chars) from my Request like:
$story = json_decode($request->getContent(), true);
$storyId = $story['storyId'];
$freeStoryName = $this->storyRepo->findOneOrFail(['storyId' => $storyId]);
$story->freeStoryName($freeStoryName);
return $this->json(["message" => "SUCCESS"]);
And In my Entity class I handle it like:
public function freeStoryName(Story $story): Story
{
$this->setPreviousStoryName($story->getStoryName());
$story->setStoryName(null);
}
And I get the error message:
Call to a member function freeStoryName() on array
I know what the message means but do not get it? It's findOne() method..
And other question will be, do I need flush() method in the Entity class like I had in a service?
You are using freeStoryName on $story which is an array (json_decode($request->getContent(), true);)
You need to use your method with your result :
$story = json_decode($request->getContent(), true);
$storyId = $story['storyId'];
$freeStoryName = $this->storyRepo->findOneOrFail(['storyId' => $storyId]);
$freeStoryName->freeStoryName($freeStoryName);
return $this->json(["message" => "SUCCESS"]);
If you feel that it's a little weird to do it this way, you could change your method to:
public function freeStoryName()
{
$this->setPreviousStoryName($this->getStoryName());
$this->setStoryName(null);
}
And use it:
$freeStoryName->freeStoryName();

Symfony 3.3 - Validation without form

I am trying to perform some validation for some query string parameters that were passed in. I want to do 3 things:
Check if firstname was passed.
If it was passed, validate that it is a string. Otherwise, throw an error.
If it isn't passed, assign a default name.
I want to re-use as much of the built-in Symfony validator functionality to do this and so far have something like the code below (but it is not working). Would anyone have suggestions?
Relevant References:
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Validator\Constraints\Collection
use Symfony\Component\Validator\Constraints\Type
Code:
public function testingAction(Request $request)
{
$parameters = $request->query->all();
// for this example, assume that $parameters contains 'firstname'=>123
$collectionConstraint = new Collection(array(
'firstname' => new Type(array('type'=>'string'))
);
$errors = $this->container->get('validator')->validate($parameters, $collectionConstraint);
return new Response('<html><body><pre>' . print_r($errors, TRUE) . '</pre></body></html>');
}
Symfony validation works on entity class. You need to create an entity class for your data with validation annotations.
// src/Entity/Author.php
// ...
use Symfony\Component\Validator\Constraints as Assert;
class Author
{
/**
* #Assert\NotBlank()
*/
public $name;
}
//then use this class for your data
use src/Entity/Auther.php;
public function testingAction(Request $request)
{
$parameters = $request->query->all();
$auther = new Auther();
$auther->setName($paramater['name']);
$errors = $this->container->get('validator')->validate($auther);
return new Response('<html><body><pre>' . print_r($errors, TRUE) . '</pre></body></html>');
}
Please follow the symfony link https://symfony.com/doc/current/validation.html

Issue with Mockery when injecting multiple mocked objects into controller

I'm using Mockery in my Laravel based PHP project to help test a Laravel MVC controller. Below is the relevant part of my controller class I'm trying to test.
class DevicesController extends Controller
{
private $deviceModel;
private $rfDeviceModel;
private $userModel;
private $userDeviceModel;
public function __construct(Device $deviceModel, RFDevice $rfDeviceModel, User $userModel, UserDevice $userDeviceModel)
{
$this->middleware('guest');
$this->deviceModel = $deviceModel;
$this->rfDeviceModel = $rfDeviceModel;
$this->userModel = $userModel;
$this->userDeviceModel = $userDeviceModel;
}
...
public function add(Request $request)
{
$name = $request->input('name');
$description = $request->input('description');
$onCode = $request->input('onCode');
$offCode = $request->input('offCode');
$pulseLength = $request->input('pulseLength');
$type = 1;
$currentUserId = $this->currentUser()->id;
$newDeviceId = $this->deviceModel->add($name, $description, $type)->id;
$this->rfDeviceModel->add($onCode, $offCode, $pulseLength, $newDeviceId);
$this->userDeviceModel->add($currentUserId, $newDeviceId);
return redirect()->route('devices');
}
}
In particular, I'm writing several unit tests around the controller's add(Request $request) function to make sure that each of the three model add(...) functions are called. My test case to handle this looks like the following:
public function testAdd_CallsAddForModels()
{
$mockDeviceModel = Mockery::mock(Device::class);
$mockDeviceModel->shouldReceive('add')->withAnyArgs()->once();
$this->app->instance(Device::class, $mockDeviceModel);
$mockRFDeviceModel = Mockery::mock(RFDevice::class);
$mockRFDeviceModel->shouldReceive('add')->withAnyArgs()->once();
$this->app->instance(RFDevice::class, $mockRFDeviceModel);
$mockUserDeviceModel = Mockery::mock(UserDevice::class);
$mockUserDeviceModel->shouldReceive('add')->withAnyArgs()->once();
$this->app->instance(UserDevice::class, $mockUserDeviceModel);
$user = $this->givenSingleUserExists();
$this->addDeviceForUser($user->user_id);
}
private function givenSingleUserExists()
{
$user = new User;
$name = self::$faker->name();
$email = self::$faker->email();
$userId = self::$faker->uuid();
$user = $user->add($name, $email, $userId);
return $user;
}
private function addDeviceForUser($userId)
{
$this->withSession([env('SESSION_USER_ID') => $userId])
->call('POST', '/devices/add', [
'name' => 'Taylor',
'description' => 'abcd',
'onCode' => 1,
'offCode' => 2,
'pulseLength' => 3
]);
}
When I run this test, I get the following output in the console:
There was 1 error:
1) Tests\Unit\Controller\DeviceControllerTest::testAdd_CallsAddForModels
Mockery\Exception\InvalidCountException: Method add() from Mockery_1_App_RFDevice should be called
exactly 1 times but called 0 times.
But the funny and perplexing thing is that if I comment out and combination of 2 of the 3 mockery sections, my test pass. This means to mean, that my code is actually working correctly, but for some reason in this case, I can't inject multiple mocked model objects into my controller and test them all at once. I guess I could split this up into three separate tests that make sure each model's add(...) function is called, but I want to do it all in one test case if possible. I also know I could use a repository pattern to wrap all the business logic in the controller's add(...) function into a single call, but then I would run into the same problem while testing the repository class.
You're not mocking the return values of the methods so this line attempts to access an attribute (id) on a null.
$newDeviceId = $this->deviceModel->add($name, $description, $type)->id;
You can fix this by adding a return value to your Device model mock like so:
$mockDeviceModel = Mockery::mock(Device::class);
$device = new Device;
$mockDeviceModel->shouldReceive('add')->withAnyArgs()->once()->andReturn($device);
To make such problems easier to debug in the future, change your error handler to re-throw the exceptions in a testing environment instead of rendering a valid HTML response.

Phalcon framework, can't get data from modal to controller

public function searchStudent($student)
{
$db = Di::getDefault()->get('db');
$sql = 'SELECT * FROM students WHERE insurance_number = "'.$student['searchInsurenceNum'].'"';
$sth = $db->prepare($sql);
$sth->execute();
When i check here die(var_dump($sth->fetchAll())), i am getting array with data from database.
return $sth->fetchAll();
}
public function searchAction()
{
$request = new Request();
$response = new Response();
if ($request->isPost()) {
(new ContactsStorage())->searchStudent($request->getPost());
}
But in controller when i call fuction die(var_dump((new ContactsStorage())->searchStudent())), i am getting empty array .
$this->view->setVar('findData', (new ContactsStorage())->searchStudent());
}
Maybe your request is not a POST ? ($request->isPost())
by using this method you're allow to find your students only on POST request. Remove condition and try again.
If you have model Student which extends \Phalcon\Mvc\Model you can use magic static methods findBy{$FeildCamelCasedName} so there is no need to create extra repositories and even methods if you want to ge tsome entity by simple criteria:
$findData = Student::findByInsuranceNumber($in);
also you can find one element by such criteria by simply using magic method findFirstBy{$Field}

Tidy up controller in Laravel 5.1

I'm setting up a Laravel 5.1 project and I've been making good progress with it but have run in to something that I'm struggling to figure out.
Basically, I have been creating objects to insert in to the database in my controller methods. This hasn't been too bad because they're usually one-liners.
However, I've run in to a more complex db entry and my controller has become a little muddied. Let me show you:
/**
* Store a new ticket for the specified project.
*
* #param int $id
* #param TicketsRequest $request
* #return Response
*/
public function store_ticket($id, TicketsRequest $request)
{
$user_id = Auth::user()->id;
$project_id = $id;
$project_tickets = Ticket::whereProjectId($id);
$project_ticket_id = $project_tickets->count() + 1;
$ticket = new Ticket;
$ticket->user_id = $user_id;
$ticket->project_id = $project_id;
$ticket->project_ticket_id = $project_ticket_id;
$ticket->title = $request->title;
$ticket->save();
$ticket_update = new TicketUpdate;
$ticket_update->user_id = $user_id;
$ticket_update->ticket_id = $ticket->id;
$ticket_update->status_id = $request->status_id;
$ticket_update->priority_id = $request->priority_id;
$ticket_update->assigned_to = $request->assigned_to;
$ticket_update->description = $request->description;
$ticket_update->save();
return redirect('/projects');
}
So as you can see, I'm creating a ticket which gets saved to the database, then also creating a ticket update which is also saved to the database.
What I'd like to do is extract this code in to 'something' to clean up my controller.
On my travels, I've found that maybe creating repositories might be the way forward. Otherwise I was thinking about some kind of service but I'm not really convinced that that is the way forward.
I have a subscription to Laracasts and found the following video but it's a little outdated and I was sure if this would still be the 'right' way to do this in Laravel 5.1 (I've found that things seem to have a natural home in 5.1 compared to older versions).
https://laracasts.com/lessons/repositories-simplified
Any suggestions/links etc would be great. Thanks!
If you instantiate your objects often/always using the same set of attributes, you could easily extract that code into models constructors, e.g:
//in your model
public function __construct($user_id, $ticket_id, $request) {
$this->user_id = $user_id;
$this->ticket_id = $ticket_id;
$this->status_id = $request->status_id;
$this->priority_id = $request->priority_id;
$this->assigned_to = $request->assigned_to;
$this->description = $request->description;
}
// in your controller
$ticket_update = new TicketUpdate($user_id, $ticket->id, $request);
$ticket_update->save();
Nothing wrong with your implementation. I suggest you use try catch when calling the save() method in case something goes wrong and send a nice error to the user saying something like "something went wrong, contact your admin".

Categories