How to override routes extending a Controller in Symfony2 - symfony

I created a BaseController to make generic REST Api calls, but in some cases, I need to extends it and change some code on it.
class BaseController extends Controller {
/**
* #Route("/api/{entity_name}")
* #Method({"GET"})
* #Template()
*/
public function indexAction($entity_name) {
$inflector = new Inflector();
$class_name = ucfirst($inflector->camelize($entity_name));
$entities = $this->getDoctrine()->getManager()->getRepository('AppApiBundle:' . $class_name)->findAll();
$serializer = $this->get('jms_serializer');
return new JsonResponse($serializer->serialize($entities, 'json'), 200);
}
/**
* #Route("/api/{entity_name}/{id}")
* * #Method({"GET"})
* #Template()
*/
public function getAction($entity_name, $id) {
$inflector = new Inflector();
$class_name = ucfirst($inflector->camelize($entity_name));
$entitiy = $this->getDoctrine()->getManager()->getRepository('AppApiBundle:' . $class_name)->find($id);
$serializer = $this->get('jms_serializer');
return new JsonResponse($serializer->serialize($entitiy, 'json'), 200);
}
/**
* #Route("/api/{entity_name}")
* #Method({"POST"})
* #Template()
*/
public function postAction($entity_name) {
return array(
// ...
);
}
/**
* #Route("/api/{entity_name}/{id}")
* #Method({"PUT"})
* #Template()
*/
public function putAction($entity_name, $id) {
return array(
// ...
);
}
/**
* #Route("/api/{entity_name}/{id}")
* #Method({"DELETE"})
* #Template()
*/
public function deleteAction($entity_name, $id) {
return array(
// ...
);
}
}
class CountryController extends BaseController {
/**
* #Route("/api/country")
* #Method({"GET"})
* #Template()
*/
public function getAllAction() {
/**
* Another business rules here
*/
return array();
}
}
Then, if I call "/api/country" Symfony2 calls the BaseController's "/api/{entity_name}" route instead of the overrided route CountryController's "/api/country".
Does someone know how to solve this issue?
Thanks in advance.

Symfony checks the routes in the order it encounters them. You'll need to change to order of the entries in your routing configuration file.
Alternatively add a requirement parameter to your #Route annotation that excludes 'country' as a possible match.

Related

Symfony 4 with Doctrine - save ManyToOne

I have problem with my symfony code:
My repository update method
/**
* #param MenuModel $menu
* #return MenuEntity|MenuModel
* #throws RepositoryException
*/
public function updateMenu(MenuModel $menu)
{
try {
$transformedMenu = $this->menuTransformer->transform($menu);
$transformedMenu = $this->getEntityManager()->merge($transformedMenu);
$this->getEntityManager()->flush($transformedMenu);
$this->getEntityManager()->detach($transformedMenu);
return $this->menuTransformer->transform($transformedMenu);
} catch (\Exception $e) {
throw new RepositoryException($e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine());
}
}
My Element entity:
/**
* Element.
*
* #ORM\HasLifecycleCallbacks
* #ORM\Table(name="element")
* #ORM\ChangeTrackingPolicy("DEFERRED_EXPLICIT")
* #ORM\Entity(repositoryClass="CP\API\Repository\ElementRepository")
*/
class Element extends \CP\RestBundle\Model\Element
{
use Traits\SystemObjectTrait;
use Traits\ChannelsTrait;
use Traits\PropertiesTrait;
use Traits\WorkflowTrait;
/**
* #ORM\ManyToOne(targetEntity="Menu", inversedBy="contents")
* #ORM\JoinColumn(name="menu_id", referencedColumnName="id")
*/
protected $menu;
/**
* Element constructor.
*/
public function __construct()
{
parent::__construct();
}
/**
* #param int $id
*
* #return Element
*/
public function setId(int $id): self
{
$this->id = $id;
return $this;
}
/**
* Update publication by modification when empty
* Update status according to publication, unpublication and archiving
*
* #ORM\PrePersist()
*/
protected function prePersist()
{
$this->updatePublication();
$this->updateStatus();
}
/**
* Update publication by modification when empty
* Update status according to publication, unpublication and archiving
*
* #ORM\PreUpdate()
*/
public function preUpdate()
{
$this->updatePublication();
$this->updateStatus();
}
/**
* Increases object version
*/
public function increaseVersion()
{
++$this->version;
}
/**
* #return mixed
*/
public function getMenu()
{
return $this->menu;
}
/**
* #param mixed $menu
*/
public function setMenu($menu): void
{
$this->menu = $menu;
}
}
My Menu entity
<?php
namespace CP\API\Entity;
use CP\API\Entity\Traits\TimestampableTrait;
use CP\Model\Configuration;
use CP\Model\Content;
use CP\Model\Language;
use CP\Model\MenuTranslation;
use CP\RestBundle\Model\Locator;
use Doctrine\ORM\Mapping as ORM;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\HasLifecycleCallbacks()
* #ORM\Table(name="custom_menu")
* #ORM\Entity(repositoryClass="CP\API\Repository\MenuRepository")
*/
class Menu
{
use TimestampableTrait;
/**
* #var int
*
* #ORM\Id()
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*/
protected $id;
/**
* #ORM\OneToMany(targetEntity="CP\API\Entity\Element",mappedBy="menu",cascade={"persist"})
*/
protected $contents;
public function __construct(Menu $parent = null)
{
$dateTime = new \DateTime();
$this->creation = $dateTime;
$this->modification === null && $this->setModification($dateTime);
$this->contents = new ArrayCollection();
}
/**
* #return int
*/
public function getId(): int
{
return $this->id;
}
/**
* #param int $id
*/
public function setId(int $id): void
{
$this->id = $id;
}
/**
* #return ArrayCollection
*/
public function getContents(): ArrayCollection
{
return $this->contents;
}
/**
* #param ArrayCollection $contents
*/
public function setContents(ArrayCollection $contents): void
{
$this->contents = $contents;
}
/**
* #param Element $element
* #return $this
*/
public function addContent(Element $element): self
{
if (!$this->contents->contains($element)) {
$this->contents[] = $element;
$element->setMenu($this);
}
return $this;
}
/**
* #param Element $element
* #return $this
*/
public function removeContent(Element $element): self
{
if ($this->contents->contains($element)) {
$this->contents->removeElement($element);
if ($element->getMenu() === $this) {
$element->setMenu(null);
}
}
return $this;
}
}
My menu model
<?php
namespace CP\Model;
use CP\RestBundle\Model\Element;
use CP\RestBundle\Model\Locator;
use CP\RestBundle\Model\Product;
use CP\RestBundle\Model\Traits\TimestampableTrait;
class Menu extends BaseModel
{
/** #var Content[] */
protected $content;
/**
* #return array|null
*/
public function getContent(): ?array
{
return $this->content;
}
/**
* #param Content[] $content
*/
public function setContent(array $content): void
{
$this->content = $content;
}
}
My transformer from model to entity
public function transform($object)
{
if ($object instanceof Menu) {
$menuData = new MenuEntity();
if ($object->getId())
$menuData->setId($object->getId());
if ($object->getContent() instanceof Content) {
$contentEntity = new ContentEntity();
$content = $object->getContent();
$contentEntity->setId($content->getId());
$menuData->addContent($this->attachToEntityManager($contentEntity));
}
return $menuData;
}
private function attachToEntityManager($object)
{
try {
$attachedObject = $this->entityManager->merge($object);
return $attachedObject;
} catch (ORMException $e) {
throw new ModelTransformationException(sprintf('Model transformation error, object could not be attached to Entity Manager: %s in %s',
$e->getMessage(), $e->getFile() . ':' . $e->getLine()));
}
}
When i try saved data then i don't have any error, but on database nothing change i.e. element entity don't have assign menu_id from relation. I don't know what is wrong, maybe i don't know how to use and save OneToMany relation.
Any idea?
Can you give us more context of what your code is doing ? The constructor of MenuEntity is strange, no use of $parent, a boolean comparaison isn't used. Why do you need to use detach and merge methods of entityManager
- Mcsky
Is right, I don't see the point of using detach and/or merge here.
Normally with a OneToMany relationship you use entity manager and persist both relations, flush and you should have an entity with a OneToMany relationship.
I hope this might be helpful, specifically this part: https://symfony.com/doc/current/doctrine/associations.html#saving-related-entities
example:
// relates this product to the category
$product->setCategory($category);
$entityManager = $this->getDoctrine()->getManager();
$entityManager->persist($category);
$entityManager->persist($product);
$entityManager->flush();

How to set controller for any route to get basic objects in all controllers

I am building my own CMS system. And i did a lot of work with symfony in the past, now i wanna do all a bit more pro :) I want to render basic controller for admin dashboard witch contains a menu, systemnotifications on route "/admin" and then i want to set another controller for example "test" on route "/admin/test" and my problem is that all object notifications from controller named AdminController are not available in this second route "/admin/test", only on route "/admin"
Here my adminControler controller:
class AdminController extends Controller
{
/**
* #Route("/admin", name="adminDashboard")
*/
public function adminDashboard()
{
$loggedUser = $this->getUser()->getId();
$systemnotifications = $this->forward('App\Controller\SystemNotificationController::notif', [
'loggedUser' => $loggedUser
]);
return $this->render('admin/index.html.twig', [
'systemnotifications' => $systemnotifications
]);
}
}
Here my test controller:
class TestController extends Controller
{
/**
* #Route("/admin/test", name="test")
*/
public function test()
{
return $this->render('admin/dashboard/index.html.twig', [
]);
}
}
In twig is set, that adminController extends base.html.twig, and Test controller extends index.html.twig (this one witch is rendered from adminController.
My question is how to handle it properly with Symfony best practice. How i should set the Admin Controller for get systemnotifications object where is another Test Controller launched ?
Please help :)
There are two ways to do that the first is inyect in the twig the variable. example see this doc.
# config/packages/twig.yaml
twig:
# ...
globals:
# the value is the service's id
user_management: '#App\DataProvider\UserDataProvider'
# config/services.yaml
services:
'App\DataProvider\UserDataProvider':
arguments:
- '#session'
autoconfigure: false
The other way is more complicate, if you for example wants the responsability to render specific part of the page, like ... the barnav or the messages
Add this piece of code to the default twig:
{% block user_control %}
{{ render(controller('LayoutCoreBundle:User:index')) }}
{% endblock %}
<?php
namespace App\Controller;
use App\Event\ShowUserEvent;
use App\Event\ThemeEvents;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use \stdClass;
class UserController extends EmitterController
{
/**
* #return \Symfony\Component\HttpFoundation\Response
*/
public function indexAction()
{
if (!$this->getDispatcher()->hasListeners(ThemeEvents::THEME_NAVBAR_USER)) {
return new Response();
}
/** #var ShowUserEvent $userEvent */
$userEvent = $this->triggerMethod(ThemeEvents::THEME_NAVBAR_USER, new ShowUserEvent());
$userClass = $userEvent->getUser();
$user = new stdClass();
$user->id = $userClass->getIdentifier();
$user->idEmployee = $userClass->getIdEmployee();
$user->setCompanyLogo = $userClass->getCompanyLogo();
$user->companyName = $userClass->getCompanyName();
$user->company = $userClass->getCompany();
$user->avatar = $userClass->getAvatar();
$user->fullName = $userClass->getName();
$user->menu = $userClass->getMenu();
$user->role = $userClass->getRolname();
return $this->render(
'header/index.html.twig',
[
'userJson' => $user,
]
);
}
}
<?php
namespace App\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\EventDispatcher\Event;
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
class EmitterController extends AbstractController
{
/**
* #var EventDispatcherInterface
*/
protected $eventDispatcher;
/**
* #param EventDispatcherInterface $dispatcher
*/
public function __construct(EventDispatcherInterface $dispatcher)
{
$this->eventDispatcher = $dispatcher;
}
/**
* #return EventDispatcherInterface
*/
protected function getDispatcher()
{
return $this->eventDispatcher;
}
/**
* #param string $eventName
*
* #return bool
*/
protected function hasListener($eventName)
{
return $this->getDispatcher()->hasListeners($eventName);
}
/**
* Will look for a method of the format "on<CamelizedEventName>" and call it with the event as argument.
*
*
* Then it will dispatch the event as normal via the event dispatcher.
*
* #param $eventName
* #param Event $event
*
* #return Event
*/
protected function triggerMethod($eventName, Event $event)
{
$method = sprintf('on%s', Container::camelize(str_replace('.', '_', $eventName)));
if (is_callable([$this, $method])) {
call_user_func_array([$this, $method], [$event]);
}
if ($event->isPropagationStopped()) {
return $event;
}
$this->getDispatcher()->dispatch($eventName, $event);
return $event;
}
}
interface ThemeEvents
{
/**
* Used to receive notification data
*/
public const THEME_NOTIFICATIONS = 'theme.notifications';
/**
* Used to receive message data
*/
public const THEME_MESSAGES = 'theme.messages';
/**
* Used to receive task data
*/
public const THEME_TASKS = 'theme.tasks';
/**
* Used to receive the current user for the navbar
*/
public const THEME_NAVBAR_USER = 'theme.navbar_user';
/**
* Used to receive breadcrumb data
*/
public const THEME_BREADCRUMB = 'theme.breadcrumb';
/**
* Used to receive the current user for the sidebar
*/
public const THEME_SIDEBAR_USER = 'theme.sidebar_user';
/**
* Used to receive the sidebar menu data
*/
public const THEME_SIDEBAR_SETUP_MENU = 'theme.sidebar_setup_menu';
}
class ShowUserEvent extends ThemeEvent
{
/**
* #var UserInterface
*/
protected $user;
/**
* #var bool
*/
protected $showProfileLink = true;
/**
* #var bool
*/
protected $showLogoutLink = true;
/**
* #var NavBarUserLink[]
*/
protected $links = [];
/**
* #param UserInterface $user
* #return ShowUserEvent
*/
public function setUser($user)
{
$this->user = $user;
return $this;
}
/**
* #return UserInterface
*/
public function getUser()
{
return $this->user;
}
/**
* #return NavBarUserLink[]
*/
public function getLinks()
{
return $this->links;
}
/**
* #param NavBarUserLink $link
* #return ShowUserEvent
*/
public function addLink(NavBarUserLink $link)
{
$this->links[] = $link;
return $this;
}
/**
* #return bool
*/
public function isShowProfileLink()
{
return $this->showProfileLink;
}
/**
* #param bool $showProfileLink
* #return ShowUserEvent
*/
public function setShowProfileLink($showProfileLink)
{
$this->showProfileLink = $showProfileLink;
return $this;
}
/**
* #return bool
*/
public function isShowLogoutLink()
{
return $this->showLogoutLink;
}
/**
* #param bool $showLogoutLink
* #return ShowUserEvent
*/
public function setShowLogoutLink($showLogoutLink)
{
$this->showLogoutLink = $showLogoutLink;
return $this;
}
}
class ThemeEvent extends Event
{
}
And then only you need a evensuscriber
class NavbarUserSubscriber implements EventSubscriberInterface
{
/**
* #var Security
*/
protected $security;
/**
* #param Security $security
*/
public function __construct(Security $security)
{
$this->security = $security;
}
/**
* #return array
*/
public static function getSubscribedEvents(): array
{
return [
ThemeEvents::THEME_NAVBAR_USER => ['onShowUser', 100],
ThemeEvents::THEME_SIDEBAR_USER => ['onShowUser', 100],
];
}
/**
* #param ShowUserEvent $event
* #throws \Exception
*/
public function onShowUser(ShowUserEvent $event)
{
if (null === $this->security->getUser()) {
return;
}
/** #var User $user */
$user = $this->security->getUser();
$event->setUser($user);
}
}
#templates/header/index.html.twig
<script type="text/javascript">
var user = {{ userJson | json_encode() | raw }};
</script>

Symfony handle form request logic

Sorry if this question is too messy, but is there a common way to handle form request in Symfony ? (I use SF 4).
For now, I have the logic in my controller :
$formBooking = $this->createForm(BookingType::class);
$formBooking->handleRequest($request);
if ($formBooking->isSubmitted() && $formBooking->isValid()) {
// perform actions ...
I have several forms on the same page, so my controller gets bigger and bigger.
I wanted to creation a new folder like Action and put the logical here.
And do in my controller :
$formBooking = $this->createForm(BookingType::class);
// $bookingAction = new App\Action\BookingAction
$bookingAction->handleRequest($formBooking, $request);
I just want to know if there any "official" way for this ?
You can create an abstract "BaseController", and inherit your other controller. I don't think this is an "official" way, but it seems proper.
In my example, I have set my entity manager, my form factory and my routing as services. Also, it's called BaseManager, as all my logic are in manager file, while my controller doesn't have code (kind of just calling my manager, except for specific cases)
To do so, simply reference your service, and let your controller be the master, but a clean and simple one.
## Controller##
<?php
namespace AppBundle\Controller;
use AppBundle\Entity\Category;
use AppBundle\Form\CategoryType;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Template;
use Symfony\Component\Form\Extension\Core\Type\SubmitType;
use Symfony\Component\HttpFoundation\Request;
/**
* #Route("/admin/category")
*/
class CategoryController extends Controller
{
/**
* #Template()
* #Route("/", name="category_index")
* #return array
*/
public function indexAction()
{
$categories = $this->get('app.category.manager')->find();
return array('categories' => $categories);
}
/**
* #Template()
* #Route("/", name="category_menu")
* #return array
*/
public function menuAction()
{
$categories = $this->getDoctrine()->getRepository('AppBundle:Category')->findAllOrdered("ASC");
return array('categories' => $categories);
}
/**
* #Template()
* #Route("/icones/glyficones", name="category_icones_glyficones")
* #return array
*/
public function fontawesomeAction()
{
return array();
}
/**
* #Template()
* #Route("/icones/fontawesome", name="category_icones_fontawesome")
* #return array
*/
public function glyficoneAction()
{
return array();
}
/**
* #Template()
* #Route("/new", name="category_create")
* #param Request $request
* #return array
*/
public function newAction(Request $request)
{
return $this->get('app.category.manager')->save($request);
}
/**
* #Template()
* #Route("/{id}/edit", name="category_edit")
* #param Request $request
* #param $id
* #return array
*/
public function editAction(Request $request, $id)
{
return $this->get('app.category.manager')->edit($request, $id);
}
/**
* #Template()
* #Route("/{id}/delete", name="category_delete")
* #param Request $request
* #param $id
* #return array
*/
public function deleteAction(Request $request, $id)
{
return $this->get('app.category.manager')->delete($request, $id);
}
}
Base Manager
<?php
namespace AppBundle\Manager;
use AppBundle\Form\CategoryType;
use Symfony\Bundle\FrameworkBundle\Routing\Router;
use Symfony\Component\Form\Form;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
abstract class BaseManager
{
protected $em;
protected $formFactory;
protected $router;
/**
* CategoryManager constructor.
* #param $em
* #param $formFactory
* #param Router $router
*/
public function __construct($em, $formFactory, Router $router)
{
$this->em = $em;
$this->formFactory = $formFactory;
$this->router = $router;
}
/**
* #param $entity
*/
protected function persistAndFlush($entity)
{
$this->em->persist($entity);
$this->em->flush();
}
/**
* #param $entity
*/
protected function removeAndFlush($entity)
{
$this->em->remove($entity);
$this->em->flush();
}
/**
* #param Request $request
* #param Form $form
* #param $entity
* #param $path
* #return array|RedirectResponse
*/
protected function handleBaseForm(Request $request, Form $form, $entity, $path)
{
$form->handleRequest($request);
if ($form->isSubmitted() && $form->isValid()) {
$this->persistAndFlush($entity);
return new RedirectResponse($this->router->generate($path));
}
return array('form' => $form->createView());
}
/**
* #param $route
* #return RedirectResponse
*/
protected function redirect($route)
{
return new RedirectResponse($this->router->generate($route));
}
}
And here an example, a simple crud froma "Category" entity.
Specific Entity Manager
<?php
namespace AppBundle\Manager;
use AppBundle\Entity\Category;
use AppBundle\Form\CategoryType;
use Symfony\Bundle\FrameworkBundle\Routing\Router;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
/**
* Class CategoryManager
* #package AppBundle\Manager
*/
class CategoryManager extends BaseManager
{
/**
* CategoryManager constructor.
* #param $em
* #param $formFactory
* #param Router $router
*/
public function __construct($em, $formFactory, Router $router)
{
parent::__construct($em, $formFactory, $router);
}
/**
* #return mixed
*/
public function find()
{
return $this->em->getRepository('AppBundle:Category')->findAll();
}
/**
* #param Request $request
* #return array
*/
public function save(Request $request)
{
$category = new Category();
return $this->handleForm($request, $category);
}
/**
* #param Request $request
* #param $id
* #return array|RedirectResponse
*/
public function edit(Request $request, $id)
{
$category = $this->em->getRepository('AppBundle:Category')->find($id);
return $this->handleForm($request, $category);
}
/**
* #param Request $request
* #param $id
* #return RedirectResponse
*/
public function delete(Request $request, $id)
{
$category = $this->em->getRepository('AppBundle:Category')->find($id);
$this->persistAndFlush($category);
return $this->redirect('category_index');
}
/**
* #param Request $request
* #param Category $category
* #return array|RedirectResponse
*/
public function handleForm(Request $request, $category)
{
$form = $this->formFactory->create(CategoryType::class, $category);
return $this->handleBaseForm($request, $form, $category, "category_index");
}
}
Just if needed, here are my services.yaml file
services:
app.category.manager:
class: AppBundle\Manager\CategoryManager
arguments: [ '#doctrine.orm.entity_manager', '#form.factory', '#router' ]
fos_user.doctrine_registry:
alias: doctrine
Hope it may help solving your issue, and get a cleaner code. Please, note that this is a personnal solution, and there are probably better solutions. But this one is a working one, which seems, for me, cleaner than just let the controller have all the logic

Create records in separate table when user registers new account

Im creating a WebBrowser game with Symfony2. What I want to achieve is:
I have a table with Users. When new user registers in the game, new record is added to table fos_user. When new user is registered I also want to put records in the table that stores users resources in the game with starting quantity.
I have read about event listeners but I'm not sure if they are the best way to resolve my problem.
This is the Entity that holds User, type of material and its quantity
/**
* #var int
*
* #ORM\Column(name="quantity", type="bigint")
*/
private $quantity;
/*
* connection material->MaterialStock<-User
*/
/**
*#ORM\ManyToOne(targetEntity="Material", inversedBy="userMaterial")
*
*/
private $material;
/**
*
* #ORM\ManyToOne(targetEntity="User", inversedBy="userMaterial")
*/
private $user;
function getId() {
return $this->id;
}
function getQuantity() {
return $this->quantity;
}
function getMaterial() {
return $this->material;
}
function getUser() {
return $this->user;
}
function setQuantity($quantity) {
$this->quantity = $quantity;
}
function setMaterial($material) {
$this->material = $material;
}
function setUser($user) {
$this->user = $user;
}
}
User entity looks like this
<?php
// src/AppBundle/Entity/User.php
namespace FactoryBundle\Entity;
use FOS\UserBundle\Model\User as BaseUser;
use Doctrine\ORM\Mapping as ORM;
use FactoryBundle\Entity\Factory;
use Doctrine\Common\Collections\ArrayCollection;
/**
* #ORM\Entity
* #ORM\Table(name="fos_user")
*/
class User extends BaseUser
{
/**
* #ORM\Id
* #ORM\Column(type="integer")
* #ORM\GeneratedValue(strategy="AUTO")
*
*/
protected $id;
public function __construct()
{
parent::__construct();
$this->productionOrders = new ArrayCollection();
}
/**
* #ORM\OneToOne(targetEntity="Factory", mappedBy="user")
*/
private $factory;
/*
* connecting User->materialStock<-Material
*/
/**
*
* #ORM\OneToMany(targetEntity="MaterialStock", mappedBy="user")
*/
private $userMaterial;
/**
* #ORM\OneToMany(targetEntity="ProductionOrders", mappedBy="user")
*/
private $productionOrders;
/** #ORM\OneToMany(targetEntity="ToyStock", mappedBy="user") */
private $userToyStock;
function getId() {
return $this->id;
}
function getFactory() {
return $this->factory;
}
function getUserMaterial() {
return $this->userMaterial;
}
function getProductionOrders() {
return $this->productionOrders;
}
function getUserToyStock() {
return $this->userToyStock;
}
function setId($id) {
$this->id = $id;
}
function setFactory($factory) {
$this->factory = $factory;
}
function setUserMaterial($userMaterial) {
$this->userMaterial = $userMaterial;
}
function setProductionOrders($productionOrders) {
$this->productionOrders = $productionOrders;
}
function setUserToyStock($userToyStock) {
$this->userToyStock = $userToyStock;
}
}
You can use an event subscriber.
<?php
namespace ...;
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\FilterUserResponseEvent;
use Steora\Api\UserBundle\Entity\User;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use ...\EntityThatHoldsUserTypeOfMaterialAndQuantity;
/**
* ...
*/
class RegistrationCompletionListener implements EventSubscriberInterface
{
/** #var EntityManager */
private $em;
/**
* #param EntityManager $em
*/
public function __construct(EntityManager $em)
{
$this->em = $em;
}
/**
* {#inheritdoc}
*/
public static function getSubscribedEvents()
{
return array(
FOSUserEvents::REGISTRATION_COMPLETED => 'onRegistrationCompletionSuccess',
);
}
/**
* #param FilterUserResponseEvent $event
*/
public function onRegistrationCompletionSuccess(FilterUserResponseEvent $event)
{
// you can modify response here, but you can remove this line if there is no need to touch response...
$response = $event->getResponse();
$user = $event->getUser();
$entityThatHoldsUserTypeOfMaterialAndQuantity = new EntityThatHoldsUserTypeOfMaterialAndQuantity();
$entityThatHoldsUserTypeOfMaterialAndQuantity->setUser($user);
$entityThatHoldsUserTypeOfMaterialAndQuantity->setQuantity(...);
...
$this->em->persist($entityThatHoldsUserTypeOfMaterialAndQuantity);
$this->em->flush();
}
}
Register your service in service.yml
services:
...
steora.api.user.registration_confirmation:
class: YourBundle\..\RegistrationCompletionListener
arguments: ['#doctrine.orm.default_entity_manager']
tags:
- { name: kernel.event_subscriber }
So, you are listening for some event, and when that event happens, you do stuff that you need :)
Here you can find more events, maybe some other than FOSUserEvents::REGISTRATION_COMPLETED is more suitable for you: https://github.com/FriendsOfSymfony/FOSUserBundle/blob/master/FOSUserEvents.php
Here is an example from the official docs: http://symfony.com/doc/current/bundles/FOSUserBundle/controller_events.html
This is workflow:
1) A user is filling a registration form and submits his data.
2) If the form is valid, this is what happens:
// friendsofsymfony/user-bundle/Controller/RegistrationController.php
if ($form->isSubmitted()) {
if ($form->isValid()) {
$event = new FormEvent($form, $request);
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_SUCCESS, $event);
$userManager->updateUser($user);
if (null === $response = $event->getResponse()) {
$url = $this->generateUrl('fos_user_registration_confirmed');
$response = new RedirectResponse($url);
}
// This is event you are listening for!!!!
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_COMPLETED, new FilterUserResponseEvent($user, $request, $response));
return $response;
}
$event = new FormEvent($form, $request);
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_FAILURE, $event);
if (null !== $response = $event->getResponse()) {
return $response;
}
}
3) Your listener reacts on event, and in onRegistrationCompletionSuccess() you do your stuff, and after that everything continues as usual :)
Matko Đipalo
Thank you for your answer. If I understood you correctly the workflow of your approach is:
FOSUser:RegistrationController.php creates an event when registration is completed
$dispatcher->dispatch(FOSUserEvents::REGISTRATION_COMPLETED, new FilterUserResponseEvent($user, $request, $response));
in your class RegistrationCompletionListener in line:
public static function getSubscribedEvents()
{
return array(
FOSUserEvents::REGISTRATION_COMPLETED => 'onRegistrationCompletionSuccess',
);
}enter code here
Im specifieing to what events I want my app to listen too and on line:
public function onRegistrationCompletionSuccess(FilterUserResponseEvent $event)
{
$response = $event->getResponse();
//... make needed actions
$this->yourDependencies->doSomeStufff()...
}
I can tell me script what to do when that event will accour. In my case get the user object and create for him records in database.

symfony2 custom annotation translation

Please help me to translate custom annotation.
I'm trying to translate #Render(title="Page"). Translate generator not found this, and title not traslate.
I try to understand how it is done in the component validation Symfony but nothing happens.
<?php
namespace Shooos\ProductBundle\Controller\Admin;
use Sensio\Bundle\FrameworkExtraBundle\Configuration as PRS;
use Shooos\CoreBundle\Controller\BaseController;
use Aft\RenderParkingBundle\Annotations as CA;
use Gedmo\Mapping\Annotation\Translatable;
/**
* #PRS\Route("/admin")
* Class CategoryController
* #package Shooos\ProductBundle\Controller\Admin
*/
class CategoryController extends BaseController
{
/**
* #CA\Render(title="Categories")
* #PRS\Route("/categories", name="admin.categories")
*/
public function indexAction()
{
}
}
<?php
namespace Aft\RenderParkingBundle\Annotations\Driver;
use Doctrine\Common\Annotations\Reader;
use Sensio\Bundle\FrameworkExtraBundle\Templating\TemplateGuesser;
use Symfony\Component\HttpKernel\Event\FilterControllerEvent;
use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
use Aft\RenderParkingBundle\Annotations;
use Symfony\Component\Translation\TranslatorInterface;
class AnnotationDriver
{
/**
* #var Reader
*/
private $reader;
/**
* #var TemplateGuesser
*/
private $guesser;
/**
* #var TranslatorInterface
*/
private $translator;
public function __construct(Reader $reader, TemplateGuesser $guesser, TranslatorInterface $translator)
{
$this->reader = $reader;
$this->guesser = $guesser;
$this->translator = $translator;
}
/**
* This event occurs when call any controller
*/
public function onKernelController(FilterControllerEvent $event)
{
/** Controller exists */
if (!is_array($controller = $event->getController())) {
return;
}
/**
* Controller
* #var \ReflectionObject $object
*/
$object = new \ReflectionObject($controller[0]);
$method = $object->getMethod($controller[1]);
foreach ($this->reader->getMethodAnnotations($method) as $configuration) {
if ($configuration instanceof Annotations\Render) {
$request = $event->getRequest();
$title = $this->translator->trans($configuration->getTitle());
$request->attributes->set('_page_title', $title);
if (null === $configuration->getTemplate()) {
$configuration->setTemplate(
$this->guesser->guessTemplateName(
$controller,
$request
));
}
$request->attributes->set('_page_template', $configuration->getTemplate());
}
}
}
}
On your annotation to object converter, where you inject the annotation reader, inject the translator service and translate the value at the transformation process, from annotation to object.
$description = $this->translator->trans($transformedAnnotationObject->getDescription());

Resources