Accessing Symfony2 global parameter in entity class - symfony

I have a value stored in my parameters.ini file, and I need to access it during the prepersist method of my model.
Normally I use $this->container->getParameter('value');, but the container is not available in the entity.
Is there a way to get parameters within an entity class?
P.S. The value is an API key for a service I am pulling info from during prepersist. Best practice is to keep keys/passwords in parameters.ini

Best practice is to use a service to persist your entity. This one would inject the container and set your parameter when you call your updateMyEntity() service method.
Inside your controller (or whatever you want):
$user = new User('foo');
$user->setSomeProperty('bar');
$userService->update($user);
Inside the UserService:
public function update(User $user) {
$user->setSomeParameter($this->container->getParameter('value'));
$this->em->persist($user);
}

In addition to Florent's answer, Entities are meant to be purely data objects. They should not know about any other variables or services within your application. I'm more curious about why your entity needs to know anything about an API key that is system-wide. With very little background information, I'd say you should rethink what you are trying to do.
You need a service to interact with the API, ideally configured through the container. I don't see what that has to do with an entity.

Related

Does every class in symfony2 need to be a service?

Intro moved to the bottom:
Right now I'm working on a small system, that manages orders and products.
I'm trying to refactor chunks of code from the controller and into business and service classes, here's what I'm trying to pull
/src/domain/bundle/Business/
/src/domain/bundle/Services/
So in the Business, I will have an Order Class, that does some calculations, some of these calculations required data from the database (on the fly).
Here's exactly the problem I have:
The controller loads an array of Orders that needs processing
The controller sends orders that needs processing to the OrderBusiness class
The OrderBusiness class needs to get the product(s) price from the database
Now I'm stuck..
What I'm attempting to do, is I made a ProductsService class, that returns the required product and price from the database, but how can I call this class from my OrderBusiness class without defining my OrderBusiness class as a service and injecting it with the ProductsService class
Intro:
I'm quiet sorry if my questions seems to be a little general and ignorant.
I've been using Symfony2 for less than a year now, and some things I can't wrap my mind around, even after reading the documentations, and a lot of the questions.
You can do whatever you want but it's often better to stick to Symfony's default way:
Controller gets data from request, validates it, calls other classes, and renders request (usually using Twig or JsonResponse::create).
To get data from database there are repositories. It's good when they return plain old PHP objects (POPO). Usually are managed with Doctrine magic.
To process objects (aggregate, filter, connect to external services, etc) you can create services. You don't to suffix them with Service (any class name is OK) and put to Service folder.
When you create many simple classes that follow "Single responsibility principle" it's convenient to connect them with dependency injection. Then your classes don't stick to each other too much and it's easy to swap one class with another without changing code in all files, also good for testing.
Symfony: Dependency Injection
So, Symfony not requirements for define all classes as services! The service layer - DependencyInjection
You must register a new service in container for access to this service in another systems/services/business logic. Performance for this: the service will be created (new SomeService) only one time, and cache this object in inner cache layer.
If you want create a new service instance for each time, you can add scope: prototype to service definition
This system vary good for many references between services.
You problem/solution:
In best practices - in no way!
As solution: you can use singlton, or use static services.
But, i recommend use dependency injection pattern layer for this problem and create all classes for each logic. Reasons:
Single responsibility
Easy testing with PHPSpec/PHPUnit (because each class - one business logic).
You can inject common logic in __constructor without parameters $this->dependencyService = new SomeService()!
If you not want define service in container, but another service have reference, you can define dependency service as private public: false
Dynamical services (creates via factory) for any condition (request, user, scope, etc...)
In my case:
As example from my another project (Orders, Products, Variants...)
I have:
ProductRepository - for load products, variants.
PriceCalculator - for calculate price for product (I loads price from product property, but you can inject PriceLoader service for loads prices from another storages).
OrderProcessor - for processing order.
Controller:
class OrderProcessingController
{
private $productRepository;
private $orderProcessor;
public function __construct($productRepository, $orderProcessor)
{
$this->productRepository = $productRepository;
$this->orderProcessor = $orderProcessor;
}
public function processForProduct($product)
{
$product = $this->productRepository->find($productId = $product);
if (!$product) {
// Control for product not found
}
$this->orderProcessor->processForProduct($product);
return new Response('some html');
}
}
In this we only load product, control if not found and call to process. Vary simple and easy testing.
Order processor:
class OrderProcessor
{
private $priceCalculator;
private $priceLoader;
public function __construct($priceCalculator, $priceLoader)
{
$this->priceCalculator = $priceCalculator;
$this->priceLoader = $priceLoader;
}
public function processForProduct($product)
{
$price = $this->priceLoader->loadForProduct($product);
$price = $this->priceCalculator->calculateForProduct($price, $product);
// Some processing
return $order;
}
}
In this class - we load price for product, calculate, create order and call to another processing if necessary. Vary simple and easy testing.
P.S.
Right now I'm working on a small system, that manages orders and products.
Can use any microframework? Silex as example or Symfony Microframework, and completely unsubscribe from dependency injection layer?
Now I'm stuck.. What I'm attempting to do, is I made a ProductsService
class, that returns the required product and price from the database,
Use repository class for business queries. Don't mix application layers. You can also define the repository as a service.
When class represents the general interface or represents an algorithm (e.g. business) define it as service.

Where should EntityManager::persist() and EntityManager::flush() be called

I'm developing a medium scale application using Symfony2 and Doctrine2. I'm trying to structure my code according to the SOLID principles as much as possible. Now here is the question:
For creating new Entities, I use Symfony Forms with proxy objects i.e: I don't bind the form directly to my Entity, but to some other class that will passed to some service which will take the needed action based on the received data, i.e: the proxy class serves as a DTO to that service which I will call the Handler. Now considering the Handler doesn't have a dependency on the EntityManager, where should I do calls to EntityManager::persist() and EntityManager::flush()? I am usually comfortable with putting flush in the controller but I'm not so sure about persist since the controller shouldn't assume anything about what the Handler does, and maybe Handler::handle (the method that the form data is passed to) does more than just persist a new Entity to the database. One Idea is to create some interfaces to encapsulate flush and persist and pass them around, which will act as wrappers around EntityManager::flush() and EntityManager::persist(), but I'm not so sure about it since EntityManager::flush() might create unwanted consequences. So Maybe I should just create an interface around persist.
So My question is where and how to make the call to persist and flush, in order to get the most Solid code? Or am I just overcomplicating things in my quest of best practices?
If you have a service that will handle tasks upon your entities, to me, the right way is to inject EntityManager into your service definition and do persist and flush operation inside it.
Another way to proceed, if you want to keep separate that logic, is to create an EventSubscriber and raise a custom event from your "entity service" when you're ready to do persist and flush operations
My 2 cents:
about flush, as it calls the DB, doing it like you already do when needed in your controllers sounds good to me.
about presist, it should be called in your Handler when your entity is in a "ready to be flushed" state. A Persister interface with only the persist method as a dependency of your Handlers, and a DoctrinePersister implementation injected in them looks OK.
Another option here - you can implement save() method in your entity repository class and make persistence there. Inject your entity repository as dependency into your Handler class.
If you don't want to couple your service and business logic to the EntityManager (good job), SOLID provides a perfect solution to separate it from your database logic.
//This class is responsible for business logic.
//It knows nothing about databases
abstract class CancelOrder
{
//If you need something from the database in your business logic,
//create a function that returns the object you want.
//This gets implemented in the inherited class
abstract protected function getOrderStatusCancelled();
public function cancel($order)
{
$order->setOrderStatus($this->getOrderStatusCancelled());
$order->setSubmittedTime(new DateTime());
//and other business logic not involving database operations
}
}
//This class is responsible for database logic. You can create a new class for any related CRUD operations.
class CancelOrderManager extends CancelOrder
{
public function __construct($entityManager, $orderStatusRepository)...
public function getOrderStatusCancelled()
{
return $this->orderStatusRepository->findByCode('cancelled');
}
public function cancel($order)
{
parent::cancel($order);
$this->entityManager->flush();
}
}

Doctrine2 , generate on a fly the value of a Entity's attribute that depends on symfony2 container

I have an API, with an API call GET /users which returns me a list of users that all have a avatar_url field
in database this field is just the image name, and in the controller i'm then putting the base URL of my static domain serving images. So that it's only one URL to change in my conf , so the code works in staging/production etc.
but things start to get tricky with GET /comments etc. that all have sub-resource users that needs to have the url, so it means that currently every single point using users needs to have this logic, which is not very DRY
I would like to have something like that
// in my entity
use JMS\Serializer\Annotation as Serializer;
/**
* #Serializer\VirtualProperty
* #Serializer\SerializedName("url")
*/
public function getUrl()
{
return $this->container->getParameter('IMG_URL').$this->imgName;
}
so that regardless on how deeply nested my entity is, I will be able to seralize it with the property.
It seems to me it is possible to achieve something like as there's a bundle
https://github.com/KnpLabs/DoctrineBehaviors
which seems to achieve something similar
Check this out. http://jmsyst.com/libs/serializer/master/handlers
From what I understand you could create your own handler for the url serializer. By having the handler as a service written by you, then you can inject anything you want in it.
More info can be found at Creating a JMS Serializer handler in symfony2

Possible to use Entity getters in custom repository?

I am in need of grabbing a few fields of an entity, running them through some processing, and returning the processed data. I am wondering if it is possible to call the getters of the Entity for which the custom repository is being built inside that custom repository? The only way I thought of so far seems like it would create an infinite loop by calling the entity's repository, which would include a call to the very custom repository being used as well.
I can write the actual queries, but I figured it it would be cleaner to access the data through existing methods, then why not?
Update: So I built a method in the custom repository that I pass the entity object to that I want to work with. Seems a little weird that I would have to pass the entity to it's own custom repository so that it would know what to act on, but I can't seem to find any other way. So in my Controller right now I am calling the entity, then calling up the repository for the entity, and passing the previously called entity to the repository. Is that right?
$user = $this->get('security.context')->getToken()->getUser();
$user_repository = $this->getDoctrine()->getRepository('AppBundle:User');
$profiles = $user_repository->getAllUsersProfiles($user);
It turns out I had the whole concept of Custom Repositories incorrect. I was using them to store methods that would pull out data relevant to the entity, but only relevant in the sense that the entity was being used to filter something else.
Prior to this epiphany my User Custom Repository had methods like getAllUsersProfiles($user) and getAllUsersCampaigns($user). My previously incorrect understanding was that because the User entity was the thing that was central to filtering the Profiles and Campaigns, that these belonged in the User Custom Repository.
What I have now come to understand is that getAllUserProfiles($user) belongs in the Profiles Custom Repository, and would be more appropriately named getAllByUser($user). Now when I need to use it, I pull up the Profiles Repository and call the appropriate method:
$profile_repository = $this->getDoctrine()->getRepository('AppBundle:Profile');
$all_profiles = $profile_repository->getAllByUser($user);

Symfony2: Access Request object in Entity

I'd like to know how to access the Request object in an entity (Symfony2) to modify the user locale.
If someone has found a solution for my problem, please let me know.
It's not possible. This is by design: the entity is just a simple object that should know nothing about the request - it's the responsibility of the controller to interpret the request, and manipulate the entity based on that.
Something like:
//inside your controller:
public function fooBarAction(Request $request)
{
$entity = // get entity
$entity->setLocale($request->getSession()->getLocale());
}
The above is just example code, it won't work if you just copy and paste it. It's just to demonstrate the general idea. The entity should just be a very simple object, who's only responsibility is to hold some data. It shouldn't know where the data is coming from - that keeps it flexible (if you want to set the locale based on something else, you only have to change your controller, not all your entities).
It is possible, but...
What you can but never should do is inject the Request object into the entity (Practically turning your entity into service, see here). Also, even worse idea (but which people still do), you could inject the whole container and get Request from there. The reason why you shouldn't do it is you never should have any code that deals with business rules or any system code in your entities.
You can switch your locale directly in your routes by using _locale custom variable (accessible also from the Request). Or you can create a kernel listener, which will do the required functionality for you. This way you keep your code testable and decoupled.

Resources