I'm trying to work effectively with DDD and Doctrine2 on a project with lot of business logic.
I understand that we need decouple the domain objects from other concepts related to the system, i.e. in a layered architecture, "the domain layer" must be isolate from other layers, like the persistence layer/service (Doctrine2 for me).
But there is one thing it's hard to understand for me: in several code examples of DDD with Doctrine 2, aggregates in domain entities are managed with Doctrine ArrayCollection, I found this kind of code :
namespace Acme\Domain\Model\Users;
use Doctrine\Common\Collections\ArrayCollection;
class User {
//...
/**
* Collection of Roles
*
* #var Collection of Roles
*/
protected $roles;
/**
* Constructor.
*/
public function __construct()
{
$this->createdAt = new \DateTime();
$this->roles = new ArrayCollection();
}
public function getRoles()
{
return $this->roles;
}
//...
}
For me, this implementation create a high coupling between domain models and the persistence service, Doctrine2.
On the other hand, if DDD Entity and Doctrine Entity classes are decoupled, there is to many layers/classes, in my opinion.
What do you think? Is there a better way to avoid/handle this?
Don't be alarmed by the use of ArrayCollections. Notice that is in the Doctrine/Common namespace. It's just a little utility array wrapper with no particular ties to the Doctrine persistence layer. You could easily replace it with another array class.
The manual addresses this issue: https://www.doctrine-project.org/projects/doctrine-orm/en/latest/reference/association-mapping.html#collections.
As far as decoupling goes, it is possible to do DDD modeling while limiting yourself to doctrine entities. It is very limiting and generally discouraged. So yep, you will probably need another layer.
It's difficult to justify the overhead of a pure DDD implementation in PHP.
Related
Without scrutinizing why I want this (it may sound like a bad approach, but I have good reason) I want to know if there is a way in the standard-framework-edition 3.1+ to create a relational association to an entity that may not exist...
Firstly I do realize this determines the schema and that's fine. So if an entity does not exist, it doesn't create a foreign key and the field is always null, or if the target entity does exist, it creates the foreign key and the field works like a normal association...
Secondly, this only changes project to project, and may change down the line as an update to which I realize a manual schema update could be necessary.
Preferably without 3rd party bundle dependencies... hoping for the standard framework to do this,
Anybody?
Thanks in advance
Edit
I am using annotations in my entities with doctrine ORM
Furthermore
The simplest version of why I am doing this is because certain bundles are optional project-to-project, and bundle A may make use of entities in bundle B only if it is present. I have considered using services and if container->has then container->get, or the XML on-invalid="null" approach, but that doesn't address property persistence. I was happy with storing a non-mapped value as a custom relational field, which is fine, just lengthier and wondered if perhaps there was a way Doctrine could ignore a missing targetEntity...
Hm, perhaps I misunderstand your question, but this sounds like a normal 'nullable' association to me?
Create your assocation via annotation:
/**
*
* #var Child
* #ORM\ManyToOne(targetEntity="Child")
*/
private $child;
and use
setChild(Child $child = null)
{
$this->child = $child;
}
as a Setter to allow nullable values.
And your getter might look like:
getChild()
{
return $this->child;
}
In case there isn't any child it will return null.
I will keep the other answer as it responds to the question for a 'nullable association target' live data.
This is the answer for a 'nullable association target' meta data which is a different thing.
OP asks to provide a targetEntity in the metadata which cannot exist in his case, e.g. is not there in a different bundle (or whatever OP's mysterious reason might be).
In that case I recommend to build upon Doctrine's TargetEntityListener which is able to resolve the targetEntity during runtime and targetEntity can be set to an Abstract Class or an Interface:
/**
* #ORM\ManyToOne(targetEntity="Acme\InvoiceBundle\Model\InvoiceSubjectInterface")
* #var InvoiceSubjectInterface
*/
protected $subject;
InvoiceSubjectInterface will then be replaced during runtime by a specific class provided by config e.g.:
# app/config/config.yml
doctrine:
# ...
orm:
# ...
resolve_target_entities:
Acme\InvoiceBundle\Model\InvoiceSubjectInterface: AppBundle\Entity\Customer
So this should be eiter an extendable behaviour for providing no class or implementing an own solution.
I've been reading a lot about this stuff and I am currently in the middle of the development of a larger web-application and its corresponding back-end.
However, I've started with a design where I ask a Repository to fetch data from the database and map it into a DTO. Why DTO? Simply because until now basically everything was simple stuff and no more complexity was necessary. If it got a bit more complex then I started to map e.g. 1-to-n relations directly in the service layer. Something like:
// This is Service-Layer
public List<CarDTO> getCarsFromOwner(Long carOwnerId) {
// Entering Repository-Layer
List<CarDTO> cars = this.carRepository = this.carRepository.getCars(carOwnerId);
Map<Long, List<WheelDTO>> wheelMap = this.wheelRepository.getWheels(carId);
for(CarDTO car : cars) {
List<WheelDTO> wheels = wheelMap.get(car.getId());
car.setWheels(wheels);
}
return cars;
}
This works of course but it turns out that sometimes things are getting more complex than this and I'm starting to realize that the code might look quite ugly if I don't do anything about this.
Of course, I could load wheelMap in the CarRepository, do the wheel-mapping there and only return complete objects, but since SQL queries can sometimes look quite complex I don't want to fetch all cars and their wheels plus taking care of the mapping in getCars(Long ownerId).
I'm clearly missing a Business-Layer, right? But I'm simply not able to get my head around its best practice.
Let's assume I have Car and a Owner business-objects. Would my code look something like this:
// This is Service-Layer
public List<CarDTO> getCarsFromOwner(Long carOwnerId) {
// The new Business-Layer
CarOwner carOwner = new CarOwner(carOwnerId);
List<Car> cars = carOwner.getAllCars();
return cars;
}
which looks as simple as it can be, but what would happen on the inside? The question is aiming especially at CarOwner#getAllCars().
I imagine that this function would use Mappers and Repositories in order to load the data and that especially the relational mapping part is taken care of:
List<CarDTO> cars = this.carRepository = this.carRepository.getCars(carOwnerId);
Map<Long, List<WheelDTO>> wheelMap = this.wheelRepository.getWheels(carId);
for(CarDTO car : cars) {
List<WheelDTO> wheels = wheelMap.get(car.getId());
car.setWheels(wheels);
}
But how? Is the CarMapper providing functions getAllCarsWithWheels() and getAllCarsWithoutWheels()? This would also move the CarRepository and the WheelRepository into CarMapper but is this the right place for a repository?
I'd be happy if somebody could show me a good practical example for the code above.
Additional Information
I'm not using an ORM - instead I'm going with jOOQ. It's essentially just a type-safe way to write SQL (and it makes quite fun using it btw).
Here is an example how that looks like:
public List<CompanyDTO> getCompanies(Long adminId) {
LOGGER.debug("Loading companies for user ..");
Table<?> companyEmployee = this.ctx.select(COMPANY_EMPLOYEE.COMPANY_ID)
.from(COMPANY_EMPLOYEE)
.where(COMPANY_EMPLOYEE.ADMIN_ID.eq(adminId))
.asTable("companyEmployee");
List<CompanyDTO> fetchInto = this.ctx.select(COMPANY.ID, COMPANY.NAME)
.from(COMPANY)
.join(companyEmployee)
.on(companyEmployee.field(COMPANY_EMPLOYEE.COMPANY_ID).eq(COMPANY.ID))
.fetchInto(CompanyDTO.class);
return fetchInto;
}
Pattern Repository belongs to the group of patterns for data access objects and usually means an abstraction of storage for objects of the same type. Think of Java collection that you can use to store your objects - which methods does it have? How it operates?
By this defintion, Repository cannot work with DTOs - it's a storage of domain entities. If you have only DTOs, then you need more generic DAO or, probably, CQRS pattern. It is common to have separate interface and implementation of a Repository, as it's done, for example, in Spring Data (it generates implementation automatically, so you have only to specify the interface, probably, inheriting basic CRUD operations from common superinterface CrudRepository).
Example:
class Car {
private long ownerId;
private List<Wheel> wheels;
}
#Repository
interface CarRepository extends CrudRepository<Car,Long> {
List<Car> findByOwnerId(long id);
}
Things get complicated, when your domain model is a tree of objects and you store them in relational database. By definition of this problem you need an ORM. Every piece of code that loads relational content into object model is an ORM, so your repository will have an ORM as an implementation. Typically, JPA ORMs do the wiring of objects behind the scene, simpler solutions like custom mappers based on JOOQ or plain JDBC have to do it manually. There's no silver bullet that will solve all ORM problems efficiently and correctly: if you have chosen to write custom mapping, it's still better to keep the wiring inside the repository, so business layer (services) will operate with true object models.
In your example, CarRepository knows about Cars. Car knows about Wheels, so CarRepository already has transitive dependency on Wheels. In CarRepository#findByOwnerId() method you can either fetch the Wheels for a Car directly in the same query by adding a join, or delegate this task to WheelRepository and then only do the wiring. User of this method will receive fully-initialized object tree. Example:
class CarRepositoryImpl implements CarRepository {
public List<Car> findByOwnerId(long id) {
// pseudocode for some database query interface
String sql = select(CARS).join(WHEELS);
final Map<Long, Car> carIndex = new HashMap<>();
execute(sql, record -> {
long carId = record.get(CAR_ID);
Car car = carIndex.putIfAbsent(carId, Car::new);
... // map the car if necessary
Wheel wheel = ...; // map the wheel
car.addWheel(wheel);
});
return carIndex.values().stream().collect(toList());
}
}
What's the role of business layer (sometimes also called service layer)? Business layer performs business-specific operations on objects and, if these operations are required to be atomic, manages transactions. Basically, it knows, when to signal transaction start, transaction commit and rollback, but has no underlying knowledge about what these messages will actually trigger in transaction manager implementation. From business layer perspective, there are only operations on objects, boundaries and isolation of transactions and nothing else. It does not have to be aware of mappers or whatever sits behind Repository interface.
In my opinion, there is no correct answer.
This really depends upon the chosen design decision, which itself depends upon your stack and your/team's comfort.
Case 1:
I disagree with below highlighted sections in your statement:
"Of course, I could load wheelMap in the CarRepository, do the wheel-mapping there and only return complete objects, but since SQL queries can sometimes look quite complex I don't want to fetch all cars and their wheels plus taking care of the mapping in getCars(Long ownerId)"
sql join for the above will be simple. Additionally, it might be faster as databases are optimized for joins and fetching data.
Now, i called this approach as Case1 because this could be followed if you decide to pull data via your repository using sql joins. Instead of just using sql for simple CRUD and then manipulating objects in java. (below)
Case2: Repository is just used to fetch data for "each" domain object which corresponds to "one" table.
In this case what you are doing is already correct.
If you will never use WheelDTO separately, then there is no need to make a separate service for it. You can prepare everything in the Car service.
But, if you need WheelDTO separately, then make different services for each. In this case, there can be a helper layer on top of service layer to perform object creation. I do not suggest implementing an orm from scratch by making repositories and loading all joins for every repo (use hibernate or mybatis directly instead)
Again IMHO, whichever approach you take out of the above, the service or business layers just complement it. So, there is no hard and fast rule, try to be flexible according to your requirements. If you decide to use ORM, some of the above will again change.
I am using Apache CXF (apache-cxf-2.5.0) to create Web Services using a bottom-up approach (Java first approach). I want to return some data/records (for example, username, email) from a database table. I can write a Java class which returns a simple response. But I am not able to find way to return a response such as data/records extracted from a database table. How to do that?
You don't mention how you are accessing the database, but the basic idea is that you ensure that the classes that you return have JAXB annotations (notably #XmlRootElement or #XmlType) on them, which allows CXF to convert the instances of those classes into XML document fragments. The classes which you annotate this way probably should not have lots of functionality in them; they should exist just to hold data. (I find anything else too confusing given the complex lifecycle they'll have.) Once the annotations are in place, just return the relevant objects and all the conversions will happen automatically.
I'm talking a simple class like this:
#XmlRootElement // <---- THIS LINE HERE!
public class UserInfo {
public String username;
public String email;
}
You can use this in conjunction with other annotations (e.g., for your ORM) as necessary. Of course, if you're talking straight JDBC to the DB to get the information out, you won't need to worry about that.
The one tricky bit is that the objects being returned will have a lifespan that goes beyond that of the database transaction you're using; you may need to detach (i.e., do some copying, though the ORM layer might provide assistance) the objects extracted from the DB for that to work. This won't be much of a concern in this case as the DB you're describing is very simple (one table, no inter-row relations) but could be an issue if you make things more complex.
I created yaml configuration for Doctrine. When I'm trying doctrine orm:generate-entities, it creates php files with getters and setters in camel case. So, is_public field transforms into setIsPublic and getIsPublic methods. It's owful. How can I get set_is_public and get_is_public? I can manually edit generated php files, but I don't know what will happen when I change the schema.
You can choose a naming strategy that Doctrine will use to generate the items using:
Using a naming strategy you can provide rules for automatically
generating database identifiers, columns and tables names when the
table/column name is not given. This feature helps reduce the
verbosity of the mapping document, eliminating repetitive noise (eg:
TABLE_).
For your specific case, I think you're looking at something like:
$namingStrategy = new \Doctrine\ORM\Mapping\UnderscoreNamingStrategy(CASE_LOWER);
$configuration()->setNamingStrategy($namingStrategy);
The linked topic goes on to show you how you can write your own custom naming strategy.
If you're using Symfony, it's even easier (like most things are with Symfony, but that's just my opinion) via config.yml:
doctrine:
orm:
naming_strategy: doctrine.orm.naming_strategy.underscore
Symfony's coding standards encourage Symfony users to use camelCase:
Naming Conventions
Use camelCase, not underscores, for variable,
function and method names, arguments
Personal advice - do not generate entities by doctrine orm:generate-entities.
Use plain PHP to create class. Why?
Orm uses reflection on privates to communicate with database. You dont need to generate setters and getters. I recomend You to use design patterns such as factory or constructor to achive Your goal. Decorators also should work fine.
<?php
class MyClass
{
private $id;
private $name;
public function __construct(int $id, string $name)
{
$this->id = $id;
$this->name = $name;
}
}
$camelCase is not only Symfony's recomendation for code standard. It's based on PSR2. I highly recomend using PSR2, code gets clean and standarized.
Standard ORM naming strategy is $camelCase private var to snake_case column name. If you want to change it otherwise, consider: other naming stategies
How/would you test super-simple methods that are built on a persistence engine. I'm going to use JPA but any persistence mechanism I'm sure has its equivelents.
For example...
#Entity
public class Category {
#Id #GeneratedValue
private long id;
#NotNull #NotEmpty
private String name;
#NotNull
#ManyToOne
private User user;
//...Getters/Setters...
}
#Stateless
public void CategoryServiceImpl implements CategoryService {
#PersistenceContext EntityManager entityManager;
public void addCategory(Category input) {
entityManager.persist(input);
}
}
What kind of tests would be useful for addCategory. I can see the usefulness of TDD and unit testing but I'm just not sure what kinds of tests to do for simple methods like that. Not really looking for "how" to create the tests but "what" to test.
One philosophy is to be very hard-nosed about unit testing (before I explain what I mean, let me say that I rarely follow this philosophy myself). You are testing that this unit does what it is supposed to do, not that any depedent software (such the the persistence mechanism) works.
So this method of your receives a parameter "input" and passes it to entityManager.persist. That's it's job. So we use a mocking framework of some sort to get a mock entityManager, and we verify that indeed the parameter passed to the call of addCategory is received my the entityManager. That's it. We've tested all the responsibilities of the method.
In more complex scenarios this appraoch is pretty useful, you test all the conditionals in the method and pick up all sorts of "off-by-one" and misuse of null reference errors etc.
For something like this example I'm not convinced that we are going to find the interesting bugs.
So I'd be setting up little suites of tests using a real EntityManager, which push the boundaries of the data. And yes, this isn't truly "Unit" testing, but I don't care - I want to find defects!
For example:
Create a category object with an empty name
Call Add Category
What should happen? I assume that we intend that an exception be thrown? So we test that indeed that's what happens.
Some more tests:
Insert, then retrieve - verify all fields
Insert, then insert a duplicate, what error do we expect
and so on.
Instead of integration testing against an existing database you can perform decent unit tests by running your tests against an embedded in memory database like h2 which has been configured to create all its tables based on the annotations on connection. This works well for us for a database of about two hundred tables.