How can I select only the children attributes with querybuilder using symfony 4? - api

I have a class named "insured object" that have two children "car" and "house" and this "insured object" has a one to one relation to "contract". The idea is when the user wants to add a contract he must specify its type whether it's a car or a house and add it to the database according to its type. So while working on the APIs (the editing one) a problem occurred, which is when i want to select a car to edit it shows me this error the error when i execute the API
this is the car editing API.
/**
* #Route("/api/editVoiture/{id}", name="editVoiture", methods={"PUT"})
*/
public function editVoiture($id, Request $request, EntityManagerInterface $em,ObjetAssureRepository $objetAssureRepository, VoitureRepository $voitureRepo)
{
$request = Request::createFromGlobals();
$jsonRecu = $request->getContent();
try {
$donnees = json_decode($jsonRecu);
$voiture = $voitureRepo->findVoitureById($id);
if($voiture != null){
$voiture->setDateAcquisition($donnees->dateAcquisition);
$voiture->setDateProduction($donnees->dateProduction);
$voiture->setMarque($donnees->marque);
$voiture->setNumChassis($donnees->numChassis);
$voiture->setPuissance($donnees->puissance);
$voiture->setModele($donnees->modele);
$em->persist($voiture);
$em->flush();
$objAss = $objetAssureRepository->findObjet($voiture->getId(),"voiture");
$objAss->setDateAcquisition($donnees->dateAcquisition);
$objAss->setDateProduction($donnees->dateProduction);
$em->persist($objAss);
$em->flush();
return new Response('ok', 200);
} else {
return new Response('does not exist',404);
}
} catch (UniqueConstraintViolationException $e) {
return $this->json([
'status' => 400,
'message' => $e->getMessage(),
], 400);
}
}
and this is the repository code
/**
* #return Voiture
*/
public function findVoitureById($id): ?Voiture
{
return $this->createQueryBuilder('v')
->andWhere('v.id = :id')
->setParameter('id',$id)
->getQuery()
->getOneOrNullResult()
;
}

Related

Laravel not inserting into table

Basically I need to have a e-mail verification system. For clarity, I will post only needed chunks of code that have impact whatsoever. When user registers, a random 40 string token is generated and sent to them, that code is appended to the route like this:
Route::get('/user/verify/{token}', 'RegisterController#verifyUser');
So when user clicks on that link supposedly route should call this:
RegisterController:
public function verifyUser($token){
$verifyUser = new VerifyUser();
$verifyUser->token = $token;
$verifyUser->getByToken();
$user = new User();
$user->id = $verifyUser->user_id;
$user->get();
if(isset($verifyUser)){
if(!$user->verified){
$user->updateVerifiedStatus();
$status = "Uspešno ste verifikovali e-mail adresu. Sada se možete ulogovati";
} else{
$status = "Već ste se verifikovali.";
}
} else{
return redirect('/')->with('error', "Vaš e-mail ne postoji");
}
return redirect('/')->with('status', $status);
}
verify_user is table which has an id of the user, and the token field, and if user is not registered, there will be no instance of that user in the table, therefore -> if(isset($verifyUser)),
also, user table has an 'verified' field, which is a boolean and stores true and false values, therefore -> if(!$user->verified).
And here are models which are used in the above mentioned controller
VerifyUser:
class VerifyUser
{
public $user_id;
public $token;
public $created_at;
public $updated_at;
public function getByToken()
{
$result =
DB::table('verify_users')
->select('*')
->where('token', $this->token)
->first();
return $result;
}
public function create()
{
$result =
DB::table('verify_users')
->insert([
'user_id' => $this->user_id,
'token' => $this->token,
]);
return $result;
}
}
User
class User
{
public function get()
{
$result =
DB::table('users')
->select('*')
->where('id', $this->id)
->first();
return $result;
}
public function updateVerifiedStatus()
{
$data = [
'verified' => true,
];
$result =
DB::table('users')
->where('id', $this->id)
->update($data);
return $result;
}
}
So, when I click the link, everything passess, I get the success status, which tells me that $user->updateVerifiedStatus() funct is returned succesfully. But, when I check the table, the field is still false, and is not updated. Any ideas?

"There are no registered paths for namespace "App"." FosRestBundle, Symfony, POST/DELETE

I receive such a message "There are no registered paths for namespace "App"" while doing post or delete requests to my API. GET works. I use FosUserBundle.
config.yml
...
fos_rest:
body_converter:
enabled: true
validate: true
validation_errors_argument: validationErrors
exception:
enabled: true
exception_controller: 'AppBundle\Controller\ExceptionController::showAction'
param_fetcher_listener: true
routing_loader:
default_format: json
include_format: false
serializer:
serialize_null: true
view:
view_response_listener: force
...
PersonRestController.php
...
class PersonRestController extends AbstractController {
use ControllerTrait;
/**
* #Rest\View()
*/
public function getPersonsAction() {
$data = $this->getDoctrine()
->getRepository(Person::class)
->findAll();
return $data;
}
/**
* #Rest\View(statusCode=201)
* #ParamConverter("person", converter="fos_rest.request_body")
* #Rest\NoRoute()
*/
public function postPersonsAction(Person $person, ConstraintViolationListInterface $validationErrors) {
if (count($validationErrors) > 0) {
throw new ValidationException($validationErrors);
}
$em = $this->getDoctrine()->getManager();
$em->persist($person);
$em->flush();
return $person;
}
/**
* #Rest\View()
*/
public function deletePersonsAction(?Person $person) {
if($person === null) {
return $this->view(null, 404);
}
$em = $this->getDoctrine()->getManager();
$em->remove($person);
$em->flush();
return null;
}
/**
* #Rest\View()
*/
public function getPersonAction(?Person $person) {
if($person === null) {
return $this->view(null, 404);
}
return $person;
}
}
...
Error:
I've checked my config.yml. It shows no duplicate.
The POST method still works despite the error, DELETE doesn't however.
It seems like you used App\ instead of AppBundle\ in a use statement (check also your configuration files).
Make sure that you have include the following lines in config.yml :
templating:
engines: ['twig']
You should also extend FOSRestController instead of using the Trait (FOSRestBundle Step 2: The view layer)
NB : I'm assuming that you use AppBundle as the main bundle because your using it in config.xml for key exception_controller.

Zend Framework 2 - Service method require as parameter InputFilter

I have a bit OOD question.
I have service:
namespace Front\Service\Course;
use Front\ORM\EntityManagerAwareInterface;
use Zend\Http\Request;
use Zend\InputFilter\InputFilter;
use Front\InputFilter\Course\CreateFilter;
class Create implements EntityManagerAwareInterface
{
/**
* #var \Doctrine\Orm\EntityManager
*/
protected $entityManager = null;
public function create(CreateFilter $createFilter)
{
if (!$createFilter->isValid()) return false;
/* #var $courseRepository \Front\Repositories\CourseRepository */
$courseRepository = $this->getEntityManager()->getRepository('Front\Entities\Course');
$course = $courseRepository->findByName($createFilter->getCourse());
}
/* (non-PHPdoc)
* #see \Front\ORM\EntityManagerAwareInterface::getEntityManager()
*/
public function getEntityManager()
{
return $this->entityManager;
}
/* (non-PHPdoc)
* #see \Front\ORM\EntityManagerAwareInterface::setEntityManager()
*/
public function setEntityManager(\Doctrine\ORM\EntityManager $entityManager)
{
$this->entityManager = $entityManager;
return $this;
}
}
And controller :
class CreateController extends \Zend\Mvc\Controller\AbstractController
{
public function onDispatch(MvcEvent $e)
{
$jsonModel = new JsonModel();
/* #var $courseCreateService \Front\Service\Course\Create */
$courseCreateService = $this->getServiceLocator()->get('Front\Service\Course\Create');
$courseCreateFilter = new CreateFilter();
$courseCreateFilter->setData($this->params()->fromPost());
if (!$courseCreateFilter->isValid()) {
$jsonModel->setVariable('status', 0);
$jsonModel->setVariable('message', $courseCreateFilter->getMessages());
return;
}
$courseCreateService->create($courseCreateFilter);
}
}
By service method declaration :
public function create(CreateFilter $createFilter)
i force user of the Service to use CreateFilter container which derived from Zend/InputFilter every time when he want to create new Course.
My question is: Might it be better when i will send to the service layer not the Typed object but simple value?
On example in my case it is might looks like:
public function create($courseName)
My CreateFilter looks like:
class CreateFilter extends InputFilter
{
public function __construct()
{
$input = new Input('name');
$validatorChain = new ValidatorChain();
$validatorChain->addValidator(new StringLength(array('max'=>60)))
->addValidator(new NotEmpty());
$input->setRequired(true)->setValidatorChain($validatorChain);
$this->add($input);
}
/**
* #return string | null
*/
public function getCourse()
{
return $this->getValue('name');
}
}
If you provide a concrete class name as you're doing now, you're forever tied to a concrete implementation of the class or one derived from it. If you decide later that you want to use a different class entirely, you have to refactor your service class code, whereas with an interface, you only need to implement it in your new class and your service will continue to work without any changes.
Without any interface at all, your service class would have to do extra checks to first see if it's an object and then if it implements the method you're expecting before it can even begin doing its job. By requiring an interface you remove the uncertainty, and negate the need for checks.
By providing an interface you create a contract between your methods and the classes they're expecting as arguments without restricting which classes may enter into the contract. All in all, contract by interface is preferable to contract by class name, but both are preferable to no contract at all.
I usually bind my entities to my form, so they are populated with the data from the form. This way, you inject the entity to your service and imho that's much cleaner. The service should not be aware of how you got your data.
My "admin" controller for an entity Bar usually is injected with three objects: the repository (to query objects), the service (to persist/update/delete objects) and the form (to modify objects for the user). A standard controller is then very CRUD based and only pushes entities to the service layer:
<?php
namespace Foo\Controller;
use Foo\Repository\Bar as Repository;
use Foo\Form\Bar as Form;
use Foo\Service\Bar as Service;
use Foo\Entity\Bar as Entity;
use Foo\Options\ModuleOptions;
use Zend\Mvc\Controller\AbstractActionController;
class BarController extends AbstractActionController
{
/**
* #var Repository
*/
protected $repository;
/**
* #var Service
*/
protected $service;
/**
* #var Form
*/
protected $form;
/**
* #var ModuleOptions
*/
protected $options;
public function __construct(Repository $repository, Service $service, Form $form, ModuleOptions $options = null)
{
$this->repository = $repository;
$this->service = $service;
$this->form = $form;
if (null !== $options) {
$this->options = $options;
}
}
public function getService()
{
return $this->service;
}
public function getRepository()
{
return $this->repository;
}
public function getForm()
{
return $this->form;
}
public function getOptions()
{
if (null === $this->options) {
$this->options = new ModuleOptions;
}
return $this->options;
}
public function indexAction()
{
$bars = $this->getRepository()->findAll();
return array(
'bars' => $bars,
);
}
public function viewAction()
{
$bar = $this->getBar();
return array(
'bar' => $bar,
);
}
public function createAction()
{
$bar = $this->getBar(true);
$form = $this->getForm();
$form->bind($bar);
if ($this->getRequest()->isPost()) {
$data = $this->getRequest()->getPost();
$form->setData($data);
if ($form->isValid()) {
// Bar is populated with form data
$this->getService()->create($bar);
return $this->redirect()->toRoute('bar/view', array(
'bar' => $bar->getId(),
));
}
}
return array(
'form' => $form,
);
}
public function updateAction()
{
$bar = $this->getBar();
$form = $this->getForm();
$form->bind($bar);
if ($this->getRequest()->isPost()) {
$data = $this->getRequest()->getPost();
$form->setData($data);
if ($form->isValid()) {
$this->getService()->update($bar);
return $this->redirect()->toRoute('bar/view', array(
'bar' => $bar->getId(),
));
}
}
return array(
'bar' => $bar,
'form' => $form,
);
}
public function deleteAction()
{
if (!$this->getRequest()->isPost()) {
$this->getRequest()->setStatusCode(404);
return;
}
$bar = $this->getBar();
$this->getService()->delete($bar);
return $this->redirect()->toRoute('bar');
}
protected function getBar($create = false)
{
if (true === $create) {
$bar = new Entity;
return $bar;
}
$id = $this->params('bar');
$bar = $this->getRepository()->find($id);
if (null === $bar) {
throw new Exception\BarNotFoundException(sprintf(
'Bar with id "%s" not found', $id
));
}
return $bar;
}
}
I made a gist file on Github with this full code (it's better readable) and the service. The service relies on the interface, so you can even swap out the entity object by another one having the same interface.
Check the full thing out here: https://gist.github.com/juriansluiman/5472787
Thanks all for answering, owing to answers and analyzing, i have reached conclusion which most applicable for my situation. I agree that Service in my case should not wait concrete object, it is should wait an abstraction with getCourse method.
And i completely agree with "Crisp" answer:
All in all, contract by interface is preferable to contract by class name, but both are preferable to no contract at all.
So i need to extract Interface with one method
getCourse
or
getName
, and remove
if (!$createFilter->isValid()) return false;
so Interface:
interface CourseInterface
{
/**
* #return String
**/
public function getName();
}
and Service:
class Create implements EntityManagerAwareInterface
{
/**
* #var \Doctrine\Orm\EntityManager
*/
protected $entityManager = null;
/**
* #param CourseInterface $course
* #param UserInterface $creator
*/
public function create(CourseInterface $course)
{
$courseEntity = new Course();
$courseEntity->setName($course->getName());
$this->entityManager->persist($courseEntity);
$this->entityManager->flush();
.....
Thanks all.

Extra Attribute Disappears after it is set successfully

I am trying to get all records that are tied to a parent object through a lookup table, and insert them directly into the model. I have an object, Role, that hasMany() RoleEndpoints. RoleEndpoints belongs to Role and hasMany() Endpoints. All the data is being retrieved exactly as I expect, however, it seems to disappear after I set it.
<?php
class ACL {
private $_di;
public function __construct($di) {
$this->_di = $di;
}
public function createACL() {
if(!$this->_acl) {
$this->_acl = new stdClass();
$roles = $possibleRoles = Roles::find();
/**
* Check if there is at least one role out there
*/
if($roles->count() > 0) {
/**
* Iterate over all of the records
*/
while($roles->valid()) {
$endpoints = array();
/**
* Grab each role's endpoints through the relationship
*/
foreach($roles->current()->getRoleEndpoints() as $roleEndpoint) {
$endpoints[] = Endpoints::findFirst($roleEndpoint->endpoint_id);
}
/**
* At this point, the endpoints exist in the current Role model;
I tried several different approaches; this seemed the best
*/
$roles->current()->endpoints = $endpoints;
}
/**
* Set object to loop through from the beginning
*/
$roles->rewind();
/**
* Here is where my issue lies.
*
* The endpoints attribute, which is set as a public attribute in the model class
* gets unset for some reason
*/
while($roles->valid()) {
echo '<pre>';
var_dump($roles->current());
exit;
}
As the comments say, during the second iteration of the result set, the endpoints attribute drops becomes null for some reason. Am I doing something wrong here? Am I missing a step?
Any help would be appreciated. Thank you!
There is a missing next() in the iterator traversing:
while ($roles->valid()) {
$endpoints = array();
/**
* Grab each role's endpoints through the relationship
*/
foreach ($roles->current()->getRoleEndpoints() as $roleEndpoint) {
$endpoints[] = Endpoints::findFirst($roleEndpoint->endpoint_id);
}
/**
* At this point, the endpoints exist in the current Role model;
* I tried several different approaches; this seemed the best
*/
$roles->current()->endpoints = $endpoints;
//Missing next
$roles->next();
}
Also, you don't need to iterate the cursor in that way, just a foreach is easy to read and maintain:
$roles = Roles::find();
$roleEndpoints = array();
if (count($roles)) {
foreach ($roles as $role) {
$endpoints = array();
/**
* Grab each role's endpoints through the relationship
*/
foreach ($role->getRoleEndpoints() as $roleEndpoint) {
$endpoints[] = Endpoints::findFirst($roleEndpoint->endpoint_id);
}
/**
* At this point, the endpoints exist in the current Role model;
* I tried several different approaches; this seemed the best
*/
$roleEndpoints[$role->id] = $endpoints;
}
}
//Get the endpoints
foreach ($roleEndpoints as $roleId => $endpoint) {
//...
}
Also, If this is a common task you can add a method to your model to reuse that logic:
class Roles extends Phalcon\Mvc\Model
{
public function getEndpoints()
{
$endpoints = array();
foreach ($this->getRoleEndpoints() as $roleEndpoint) {
$endpoints[] = Endpoints::findFirst($roleEndpoint->endpoint_id);
}
return $endpoints;
}
public function initialize()
{
//...
}
}
So you can get your endpoints:
$roles = Roles::find();
if (count($roles)) {
foreach ($roles as $role) {
$endpoints = $role->getEndpoints();
}
}

Yii: Catching all exceptions for a specific controller

I am working on a project which includes a REST API component. I have a controller dedicated to handling all of the REST API calls.
Is there any way to catch all exceptions for that specific controller so that I can take a different action for those exceptions than the rest of the application's controllers?
IE: I'd like to respond with either an XML/JSON formatted API response that contains the exception message, rather than the default system view/stack trace (which isn't really useful in an API context). Would prefer not having to wrap every method call in the controller in its own try/catch.
Thanks for any advice in advance.
You can completely bypass Yii's default error displaying mechanism by registering onError and onException event listeners.
Example:
class ApiController extends CController
{
public function init()
{
parent::init();
Yii::app()->attachEventHandler('onError',array($this,'handleError'));
Yii::app()->attachEventHandler('onException',array($this,'handleError'));
}
public function handleError(CEvent $event)
{
if ($event instanceof CExceptionEvent)
{
// handle exception
// ...
}
elseif($event instanceof CErrorEvent)
{
// handle error
// ...
}
$event->handled = TRUE;
}
// ...
}
I wasn't able to attach events in controller, and I did it by redefinition CWebApplication class:
class WebApplication extends CWebApplication
{
protected function init()
{
parent::init();
Yii::app()->attachEventHandler('onError',array($this, 'handleApiError'));
Yii::app()->attachEventHandler('onException',array($this, 'handleApiError'));
}
/**
* Error handler
* #param CEvent $event
*/
public function handleApiError(CEvent $event)
{
$statusCode = 500;
if($event instanceof CExceptionEvent)
{
$statusCode = $event->exception->statusCode;
$body = array(
'code' => $event->exception->getCode(),
'message' => $event->exception->getMessage(),
'file' => YII_DEBUG ? $event->exception->getFile() : '*',
'line' => YII_DEBUG ? $event->exception->getLine() : '*'
);
}
else
{
$body = array(
'code' => $event->code,
'message' => $event->message,
'file' => YII_DEBUG ? $event->file : '*',
'line' => YII_DEBUG ? $event->line : '*'
);
}
$event->handled = true;
ApiHelper::instance()->sendResponse($statusCode, $body);
}
}
In index.php:
require_once(dirname(__FILE__) . '/protected/components/WebApplication.php');
Yii::createApplication('WebApplication', $config)->run();
You can write your own actionError() function per controller. There are several ways of doing that described here
I'm using the following Base controller for an API, it's not stateless API, mind you, but it can serve just aswell.
class BaseJSONController extends CController{
public $data = array();
public $layout;
public function filters()
{
return array('mainLoop');
}
/**
* it all starts here
* #param unknown_type $filterChain
*/
public function filterMainLoop($filterChain){
$this->data['Success'] = true;
$this->data['ReturnMessage'] = "";
$this->data['ReturnCode'] = 0;
try{
$filterChain->run();
}catch (Exception $e){
$this->data['Success'] = false;
$this->data['ReturnMessage'] = $e->getMessage();
$this->data['ReturnCode'] = $e->getCode();
}
echo json_encode($this->data);
}
}
You could also catch dbException and email those, as they're somewhat critical and can show underlying problem in the code/db design.
Add this to your controller:
Yii::app()->setComponents(array(
'errorHandler'=>array(
'errorAction'=>'error/error'
)
));