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();
}
}
Related
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.
In my ASP.NET Web API controller, I want to restrict access to those in the User role. The common way to do this is to extend the AuthorizeAttribute (example, example) and then sprinkle my controllers with my custom attribute (e.g. [AuthorizeUser]).
Another way to do this is to add a function in the controller's constructor. The constructor is required anyway because I'm using dependency injection.
Here's some code:
public class MyController: ApiController
{
private IUnitOfWork unitOfWork;
private IAccountUtils accountUtils;
// Constructor
public MyController(
IUnitOfWork unitOfWork,
IAccountUtils accountUtils)
{
this.unitOfWork = unitOfWork;
this.accountUtils = accountUtils;
// Restrict access to 'User' role
accountUtils.ThrowExceptionIfUserNotInRole(User.Identity, "User");
}
// More code
}
Because there are countless tutorial and examples of using a filter to authorize users I assumed that was the best way to go. However, when I stepped through my code in the debugger I found that the constructor method gets fired BEFORE the filter.
To optimize code, it makes sense to break as soon as possible if the user is not authorized to access the controller. If I'm not mistaken, then, it should be more efficient to perform authorization in the constructors instead of in a filter. Am I correct or am I missing something here?
It seems like your main concern is optimizing your code, and you're correct to note that the controller constructor runs before the authorization filter. But the difference in performance between those two solutions is extremely small and shouldn't really impact your service.
While throwing from a constructor might work, it's not the most elegant solution because it requires you to authorize in code rather than declaratively with an attribute. It also forces you to mix object instantiation logic with authorization logic which isn't as clean.
So I'd recommend just sticking to using an authorization filter for this one.
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.
I've seen a lot about UnitOfWork and Repo Pattern on the web but still don't have a clear understanding of why and when to use -- its somewhat confusing to me.
Considering I can make my repositories testable by using DI thru the use of an IoC as suggested in this post What are best practices for managing DataContext. I'm considering passing in a context as a dependency on my repository constructor then disposing of it like so?:
public interface ICustomObjectContext : IDisposable {}
public IRepository<T> // Not sure if I need to reference IDisposable here
public IMyRepository : IRepository<MyRepository> {}
public class MyRepository : IMyRepository
{
private readonly ICustomObjectContext _customObjectContext;
public MyRepository(ICustomObjectContext customObjectContext)
{
_customObjectContext = customObjectContext;
}
public void Dispose()
{
if (_customObjectContext != null)
{
_customObjectContext.Dispose();
}
}
...
}
My current understanding of using UnitOfWork with Repository Pattern, is to perform an operation across multiple repositories -- this behavior seems to contradict what #Ladislav Mrnka recommends for web applications:
For web applications use single context per request. For web services use single context per call. In WinForms or WPF application use single context per form or per presenter. There can be some special requirements which will not allow to use this approach but in most situation this is enough.
See the full answer here
If I understand him correctly the DataContext should be shortlived and used on a per request or presenter basis (seen this in other posts as well). In this case it would be appropriate for the repo to perform operations against the context since the scope is limited to the component using it -- right?
My repos are registered in the IoC as transient, so I should get a new one with each request. If that's correct, then I should be getting a new context (with code above) with each request as well and then disposing of it -- that said...Why would I use the UnitOfWork Pattern with the Repository Pattern if I'm following the convention above?
As far as I understand the Unit of Work pattern doesn't necessarily cover multiple contexts. It just encapsulates a single operation or -- well -- unit of work, similar to a transaction.
Creating your context basically starts a Unit of Work; calling DbContext.SaveChanges() finishes it.
I'd even go so far as to say that in its current implementation Entity Framework's DbContext / ObjectContext resembles both the repository pattern and the unit of work pattern.
I would use a simplified UoW if i wanted to push context's SaveChanges away from the repositories when they share the same instance of context across one web request.
I imagine you have sth like Save() method on your repositories that looks similiar to _customObjectContext.SaveChanges(). Now lets assume you have two methods containing business logic and using repos to persist changes in DB. For the sake of simplicity we'll call them MethodA and MethodB, both of them containing a fair amount of logic for performing some activities. MethodA is used separately in the system but also it is called by MethodB for some reason. What happens is MethodA saves changes on some repository and since we are still in the same request changes made in MethodB, before it called MethodA, will also be saved regardless of whether we want it or not. So in such case we unintentionally break the transaction inside MethodB and make the code harder to understand.
I hope i described this clear enough, it wasn't easy. Anyway other than that i cannot see why UoW would be helpful in your scenario. As Dennis Traub pointed quite correctly ObjectContext and DbContext are in fact an implementation of a UoW so you'd be probably reinventing the wheel while implementing it on your own.
The ObjectContext/DbContext is an implementation of the UnitOfWork pattern. It encapsulates several operations and makes sure they are submitted in one transaction to the database.
The only thing you are doing is wrapping it in your own class to make sure you're not depending on a specific implementation in the rest of your code.
In your case, the problem lies in the fact that your Context shouldn't be disposed of by your Repository. The Repository is not the one that instantiates the Context, so it shouldn't dispose of it either. The UnitOfWork that encapsulates multiple repositories is responsible for creating and disposing the Context and you will call a Save method on your UnitOfWork.
Code can look like this:
using (IUnitOfWork unitOfWork = new UnitOfWork())
{
PersonRepository personRepository = new PersonRepository(unitOfWork);
var person = personRepository.FindById(personId);
ProductRepository productRepository = new ProductRepository(unitOfWork);
var product= productRepository.FindById(productId);
p.CreateOrder(orderId, product);
personRepository.Save();
}
I am new to the MVC way of programming so please bear with my basic question !
I have a Status class with a default constructor (in an ASP.NET MVC application).
public Status()
{
this.DatePosted = DateTime.Now;
}
I noticed Fluent NHibernate calls this constructor each time it fetched a list of existing Status objects from the database. Hence, the constructor does not seem like the right place to initialize the date.
Where should I move this initialization ? Moving it to the Controller (Add action of Status controller) also seems to violate the principle that the Controller should not make any business decisions. Should I move it to the Status DAO then ? (In traditional ASP.NET Web Form applications I worked with, a DAO simply accepted a business object and saved it to the database and did not contain any logic)
I would like to know the right way to accomplish this. Is there another layer I am missing here where this initialization should take place?
I noticed Fluent NHibernate calls this
constructor each time it fetched a
list of existing Status objects from
the database. This does not seem right
This is exactly what is supposed to be happening. Why wouldn't an ORM call the default constructor for an object? I think every hand rolled DAL and ORM in the world would trigger DatePosted to be reset because thats just how constructors work.
Your DatePosted property should probably set via ModelBinding or manually in the controller and not be part of a constructor.