Can Domain Driven Design Application layer have Models - php

Can an application layer in ddd have models?
To be more explicit, I have a credential entity in my system that is related to the authentication process which is outside of my domain layer, so where this entity will be? I'm new at Domain Driven Design.

The Application Layer can use its own data representations. If you wire it to the user interface, the Application Layer will have to translate Domain objects to view-able data.
But I wouldn't call this "model", except maybe in the sense of "view model."
Without more details, it's hard to say anything more useful, so I'll try to answer to your integration problem by example.
Vaughn Vernon's example app
Taking a look at Vernon's sample application, you can have an authentication service isolated from your consuming application. Vernon models three stand-alone Java applications for this.
Now there's the IdentityAccess service providing all the authentication. There, you can create Tenant Entities. Then there's the Collaboration app (forum etc.) which uses its own internal representation of Tenant.
So the client app obtains a TenantId and creates its own Tenant objects to associate forum threads with a tenant. Tenants aren't changed or persisted from within this app, only used.
Tying Domain objects to stuff outside it
Your point may be even simpler. If you have a Credential Entity (in your Domain) and some auth logic outside of it, make the "authenticator" implement a specialized interface of the Domain and inject it back into Domain objects if you really need to. (That's the Ports & Adapters approach: both sides may specify interfaces and wait for concrete implementations; the other side implements the interface and injects an object back in.)
I guess you don't really have to have access from within your Domain to the authentication logic, but we'd have to see more code to judge this.
Vernon uses an AuthenticationService inside the Domain to handle wrong login details.

Related

PHP - Structuring a Slim3 web application using MVC and understanding the role of the model

I’m trying to create an authentication system in php with the Slim3 framework along with the Twig template system, and for the database I’m using MySQL with PDO. I’m also trying to implement it using a model view controller design pattern. However I’m having difficulty understanding how to use an MVC structure for a web application. I’ve looked at a plethora of explanations on the web and there doesn’t seem to be a clear cut answer. A lot of people say to to use a php framework such as Laravel, Symfony or CodeIgniter as they apparently employ an MVC like structure. However I would much rather keep things simple and to write the code manually rather than using a framework.
Currently there are two interpretations of MVC that I see. The first one being depicted in this diagram:
The other interpretation I’ve seen is this: (which is taken from this YouTube video)
I have done my research. Questions and answers such as this and this have been helpful. But I’m still not sure how I might structure my own applications, specifically indentifying and understanding the model aspect of MVC. I’ll now explain the register process of my authentication app. So you have an idea how my code is works.
Firstly I have an SQLQueries class that simply puts a series of SQL statements into functions. I then have a SQLWrapper class that has functions that can for example store a new users details inside the database. This class also calls functions from the SQLQueries class. I also have a ValidateSanitize class that has functions that cleans user input as well as checking if user input is valid in the form. These three classes I think are part of the model aspect of MVC but I'm not sure. I see a lot of other tutorials using a ‘User Model class’ but I can’t find the need for one in my application.
My views are simply Twig templates that display html, such as the homepage, register, login etc. I then have controllers. I intend to have multiple controllers that do different things. For now I’ve only implemented the AuthController which is responsible for Registering and Signing a user in.
So the first thing the AuthController does is to display the register form in a function called getRegisterForm. Once the user has submitted the form the postRegisterForm function takes that user input and assigns it to tainted variables.
public function postRegisterForm($request, $response)
{
$arr_tainted_params = $request->getParsedBody();
$tainted_email = $arr_tainted_params['email']; it a variable
$tainted_username = $arr_tainted_params['username'];
$tainted_password = $arr_tainted_params['password'];
$tainted_password_confirm = $arr_tainted_params['password_confirm'];
Next all of the three previous classes as well as the database details are instantiated so their functions can be used in the AuthController:
$sanitizer_validator = $this->container->ValidateSanitize;
$sql_wrapper = $this->container->SQLWrapper;
$sql_queries = $this->container->SQLQueries;
$db_handle = $this->container->get('dbase');
The tainted user details are then cleaned with the sanitize_input function. The cleaned user details are then fed into the validate functions to make sure they don’t trigger any validation violations. The password is also hashed here:
$cleaned_email = $sanitizer_validator->sanitize_input($tainted_email, FILTER_SANITIZE_EMAIL);
$cleaned_username = $sanitizer_validator->sanitize_input($tainted_username, FILTER_SANITIZE_STRING);
$cleaned_password = $sanitizer_validator->sanitize_input($tainted_password, FILTER_SANITIZE_STRING);
$cleaned_password_confirm = $sanitizer_validator->sanitize_input($tainted_password_confirm, FILTER_SANITIZE_STRING);
$hashed_cleaned_password = password_hash($cleaned_password, PASSWORD_DEFAULT);
$sanitizer_validator->check_email_exists($cleaned_email);
$sanitizer_validator->validate_email($cleaned_email);
$sanitizer_validator->validate_username($cleaned_username);
$sanitizer_validator->validate_password($cleaned_password);
$sanitizer_validator→validate_password_confirm($cleaned_password_confirm);
Finally there is an if statement that checks to see if all validation error messages are empty. If they are we provide the SQLWrapper class with the database details as well as a SQLQueries class object. We then insert the users details into the database by calling the SQLWrapper classes store-details function. Finally we direct the user to the login page, so the user can sign into their newly registered account.
if ($sanitizer_validator->get_validate_messages('email_error') == ' ' && $sanitizer_validator->get_validate_messages('username_error') == ' '
&& $sanitizer_validator->get_validate_messages('password_error') == ' ' && $sanitizer_validator->check_passwords_match($cleaned_password, $cleaned_password_confirm ) == true
&& $sanitizer_validator->check_email_exists($cleaned_email) == false)
{
$sql_wrapper->set_db_handle($db_handle);
$sql_wrapper->set_sql_queries($sql_queries);
$sql_wrapper->store_details($cleaned_email, $cleaned_username, $hashed_cleaned_password);
return $response→withRedirect($this→container→router→pathFor('login'));
}
However if any of the validate error messages are not blank, then we call the SanitiseValidate display_validate_messages which simply sets the messages into a session to be displayed on the register twig template. We then redirect back to the register page so the user can see the validation error messages.
else
{
$sanitizer_validator->display_validate_messages();
return $response->withRedirect($this->container->router->pathFor('register'));
}
}
So based on this structure of a user registering an account. Does this adhere to a clean simple MVC structure or do some changes need to be made? Do any of my classes take the role of a model? Any suggestions and tips regarding my structure will be appreciated.
The full application can be seen on my GitHub if that would be helpful. Note that this version is slightly older than the sample code I used in this question.
Indeed, there are multiple approaches regarding how the MVC pattern should be applied in web applications. This multitude of variants is the result of the simple fact, that the original MVC pattern - developed for desktop applications (by Trygve Reenskaug, in 1979) - can not be applied as is to the web applications. Here is a little description. But, from this set of approaches, you can choose one which best complies with your requirements. Maybe you'll try more of them before you'll make your mind. Though, at some point, you'll know which one fits to your vision.
In the following diagrams I tried to present my chosen approach on the web MVC workflow - mainly inspired by Robert Martin's presentation Keynote: Architecture the Lost Years (licensed under a Creative Commons Attribution ShareAlike 3.0).
In general, you could think of a web MVC application as composed of the following parts:
Domain model (e.g. model, e.g. model layer);
Service layer (optional);
Delivery mechanism;
Other components (like own libraries, etc).
1) The domain model should consist of the following components:
Entities (e.g. domain objects) and value objects. They model the business rules in terms of properties and behavior and, being application-independent, can be used by multiple (types of) applications.
(Data) mappers and, optional, repositories. These components are responsible with the persistence logic.
External services. They are used to perform different tasks involving the use of external/own libraries (like sending emails, parsing documents, etc).
Further, the domain model could be split into two parts:
a) Domain model abstraction. This would be the only space of the model layer accessed by the components of the delivery mechanism, or by the services of the service layer - if one is implemented:
Entities and value objects;
(Data) mapper abstractions and, optional, repository abstractions;
Abstractions of external services.
Note: By abstractions I mean interfaces and abstract classes.
b) Domain model implementation. This space would be the one in which the implementations of the different domain model abstractions (see a) would reside. The dependency injection container (as part of the delivery mechanism) will be responsible with passing instances of these concrete classes as dependencies - as constructor arguments, for example - to the other components of the application (like controllers, views, services, etc).
2) Service layer (optional): Technically, the components of the delivery mechanism could directly interact with the elements of the domain model. Though such interactions involve (a lot of) operations, specific only to the model, not to the delivery mechanism. Therefore, a good choice is to defer the execution of these operations to service classes (e.g. services), as part of the so-called service layer. The delivery mechanism components will then use only these services to access the domain model components.
Note: The service layer can, actually, be seen as part of the model layer. In my diagrams bellow I preferred to display it as a layer residing outside the model. But, in the file system example, I put the corresponding folder in the domain space.
3) The delivery mechanism sums up the constructs used to assure the interaction between the user and the model layer's components. By user I don't mean a person, but an interface with which a person can interact - like a browser, a console (e.g. CLI), a desktop GUI, etc.
Web server: parses the user request through a single point of entry (index.php).
Dependency injection container: provides the proper dependencies to the different components of the application.
HTTP message (e.g. HTTP request and HTTP response) abstraction (see PSR-7: HTTP message interfaces).
Router: matches the request components (HTTP method and URI path) against the components of each route (HTTP method and pattern) in a predefined list of routes and returns the matched route, if found.
Front controller: matches the user request against a route and dispatches it to a certain controller and/or view action.
Controllers. They write (e.g. perform create, update and delete operations) to the model layer and (should) expect no results. This can happen by directly interacting with the components defined in the domain model, or, preferably, by only interacting with the service classes.
Views. They should be classes, not template files. They can receive a template engine as dependency. They only fetch data (e.g. perform read operations) from the model layer. Either by directly interacting with the components defined in the domain model, or, preferably, by only interacting with the service classes. Also, they decide which result (like a string), or template file content, will be displayed to the user. A view action should always return a HTTP response object (maybe as defined by the PSR-7 specification), whose body will be before-hand updated with the mentioned result or template file content.
Template files. Should be kept as simple as possible. The whole presentation logic should happen only in the view instances. So, the template files should contain only variables (be they pure PHP ones, or presented with the used template engine syntax) and, maybe, some simple conditional statements, or loops.
Response emitter: reads the body of the HTTP response instance returned by the view and prints it.
4) Other components. As wished. For example some libraries developed by your own. Like an implementation of the PSR-7 abstraction.
How I chose to dispatch the user request:
As you see in the diagrams above, the front controller dispatches the user request not only to a controller action (in order to update the domain model), but also to a view action (in order to read and display the updated state/data from the model layer). Kind of a splitted dispatch. This can be relatively easy achieved by assigning the controller action and the view action to each route (like bellow), and telling the front controller to call them successively:
<?php
use MyApp\UI\Web\Application\View;
use MyApp\UI\Web\Application\Controller;
// Note: $this specifies a RouteCollection to which the route is added.
$this->post('/upload', [
'controller' => [Controller\Upload::class, 'uploadFiles'],
'view' => [View\Upload::class, 'uploadFiles'],
]);
This approach gives flexibility in regard to the user request dispatch. For example, the name of the view action can be different from the name of the controller action. Or, in order to only fetch model layer data, you don't need to dispatch the user request to a controller, but only to a view. Therefore you don't need to assign a controller action in the route at all:
<?php
use MyApp\UI\Web\Application\View;
$this->get('/upload', [View\Upload::class, 'listFiles']);
File system structure example:
myapp/domain: folder containing the domain model classes and the services. This directory could be brought into the "myapp/web/src" folder, but it shouldn't, because the model layer and the service layer are not part of the delivery mechanism.
myapp/web: folder containing the delivery mechanism classes. Its name depicts the type of application - can be a web app, a cli app, etc.
myapp/web/src:
Resources:
*) Sandro Mancuso : An introduction to interaction-driven design
*) The ones listed in an older answer of mine.
*) The tutorials presented by Alejandro Gervasio:
Building a Domain Model – An Introduction to Persistence Agnosticism
Building a Domain Model – Integrating Data Mappers
Handling Collections of Aggregate Roots – the Repository Pattern
An Introduction to Services
*) The example on the Slim 3 page: Action-Domain-Responder with Slim.
There is a course where you get walked through making MVC with slim 3. Ill link it here : https://codecourse.com/courses/slim-3-authentication . Hope this helped, its a really easy to follow course and you learn alot.

ddd - Where should synchronization with remote API go?

In order for my application to work, I need to synchronize regularly data from an outside service (could be an API, or a simple text file, but for now it is an API).
Since this would require creating / updating many entities at once, I need to create a Domain Service. However, I also need to create some DTOs that will contain the response of the remote API right ?
Where should this logic go ? Should I have the following directory structure:
Domain -
Model - // my set of entities and repository interfaces are here
....
Synchronization -
RunSynchronizationService.php // domain service
Application
Synchronization -
SynchronizeData.php // application service
SynchronizationDataSourceInterface.php // used by application service
MySpecificRemoteApiDataSource.php // this implements the interface above
SynchronizationDataSourceResponse.php // this would be returned by each call of SynchronizationDataSourceInterface method, and would contain data normalized, but not validated.
Infrastructure -
MyConcreteImplementationOfModelEntityRepository.php
And when I want to synchronize the data, I smply call Application\Synchronization\SynchronizeData's sync method, wich will take a concrete implementation of SynchronizationDataSourceInterface, call its methods, and validate the returned SynchronizationDataSourceResponse objects before transferring them to Domain\Model\Synchronization\RunSynchronizationService ?
Or should I remove RunSynchronizationService (the Domain Service) and let the Application Service (SynchronizeData.php) create / update the domain entities at each step of the synchronization process ?
Generally when presented with the question as to where an external service interface should live, I try to think of it in terms of it being another repository. The level of abstraction I choose here will depend highly on who will use the service (just the domain/app layers of this project? other projects?), if there are different versions/vendors of the service, and how which service to use is determined.
For your example, I'm going to assume that this application is the only one using the sync service directly. Shared services require common end points (such as the interface and output objects) to be isolated even further to avoid spilling unnecessary objects into other projects.
But in this case, to treat the service as another repository, I'd place the interface for it and standard output the domain expects and uses in the domain.
What is meant by "validation" is a little vague in your description, so I'll try to attack the different views of that here. One or all may apply.
If validation requires you to compare against domain data, it should probably reside in the RunSynchronizationService.php module. That module appears to be responsible for taking the sync data and applying it to your domain.
If validation is on the data coming back from the sync service call, and doesn't require direct access to the domain object graph, I would put that validation on the service implementation of the interface, and expose that validation call on the service interface. To handle the situation of that validation being the same across several versions of the sync service (such as VersionA, VersionB, etc), you can use inheritance and overrides, or common helper functions to the sync service, etc. In my example below, I used inheritance.
It could be you need to do both kinds of validation. First check for sync data problems agnostic to the domain (on the implemented classes), and then against business rules in the domain (in RunSynchronizationService). But likely both of those calls would occur in the RunSynchronizationService as you'd expose the sync data validation call on the interface.
The application layer should be responsible for creating the instance of the service (MySpecificRemoteApiDataSource), and passing it into the RunSynchronizationService.php module as SynchronizationDataSourceInterface. If there are multiple versions, the application layer would likely be responsible for choosing which one (from a configuration, perhaps), and using a factory.
But this again highly depends on the scope of that sync service. If you have external projects relying on it, you might want that factory part of the service layer itself so each of the other projects operate with the same choosing method.
Domain -
Model - // my set of entities and repository interfaces are here
....
Synchronization -
RunSynchronizationService.php // domain service
SynchronizationDataSourceInterface.php // used to define the contract associated with a sync service
SynchronizationDataSourceResponse.php // this would be returned by each call of SynchronizationDataSourceInterface method, and would contain data normalized, but not validated.
Application -
Synchronization -
SynchronizeData.php // application service - Uses a factory or some means of determining which version to use and introduce the domain to the data point.
Infrastructure -
MyConcreteImplementationOfModelEntityRepository.php
Synchornization -
VersionA -
MySpecificRemoteApiDataSource.php // Implements SynchronizationDataSourceInterface.php, inherits from SyncApiDataSourceBase.php
SyncApiDataSourceBase.php // Common logic for sync goes here, such as validation.

Where to place autorisation code

I have a PHP MVC application. The business logic is implemented in a service layer and a domain model. My question is, where should I implement authorisation checks? In the service layer? Or the domain model?
In a discussion on the service layer pattern, http://martinfowler.com/eaaCatalog/serviceLayer.html, Martin Fowler prefers to separate 'application logic' from 'business logic'. The former goes in the service layer, the latter in the domain objects.
Some of my authorisation rules are complex. Authorisation can depend on the current user, their roles, the state of many otherwise unrelated objects, etc. These seem to belong in the domain objects, or in some cases the factories for these objects.
But in other cases, the rules are quite simple. For example, "only a supervisor can approve a new noticeboard post". In these cases I am tempted to check authorisation in the service layer. It obviates the security requirements, and by putting them in a (mock-able) service layer listener, my code becomes easier to test.
So, the question is should I put simple authorisation checks in the service layer, and more complex ones in the domain objects? Or am I asking for trouble by splitting it across two layers?
OK, So I moved the authentication code to the service layer and found that there were only a couple of instances where I still needed to do additional checks in the model. For consistency, I could pull these checks into the service layer too, at the expense of performance, but so far I have not felt the need.

How to store model state when model is a layer

How are you meant to store the state of the model in MVC when the model is a layer, and accessed via services. Do you give the service class a state? How would that state be communicated to the View, when the View may or may not use that specific service?
I currently have a model entity to store different states, all my services log their issues, successes and state in this entity. I store this entity in the session, but the whole thing feels wrong...
I am considering that state is more than error/success.
If your views never know which service has been used by controller to alter the state of model layer, then your best approach would be instead implement classical MVC (or close to it) with current view observing the model. In that case each used service would inform the view, when it has been acted upon by controller. If that's the case, then content below does not apply.
The bad idea ..
The views and controllers should share the factory, which is responsible for initializing the services. this means that if you controller has used a particular service, then you can add an ability to query this factory about services that it has initialized already.
if ( $this->serviceFactory->hasCached('recongnition') )
But that should not be necessary and IMHO, that would be a really harmful thing to do. You would be forcing the factory to become a vital part of UI logic.
Note: the factory in this case enforces, that each service is create only once, without dependence on global state.
Different approach/perspective
For some reason, you start out with a premise, that every view has to be omniscient. That's what causing you current confusion.
Instead of knowing everything about everything the two fictional services:
Accounting: for dealing with invoices
Library: for managing documents
When you are looking at the page, which list the current document, why would the view care, that there is an error state in Accounting service? How would you actually achieve that error state?
Would an error state in any of those services affect how the "login page" looks like?
So. The bottom line here is this: even if controller does something, which causes an error state somewhere in the model layer, the view should only know about it, only if the view needs that particular service.
Note:Of course since in web applications the views and controllers tend to form pairs (if there is controller for handling "Document List", then there probably will also be a corresponding view), it will be and extremely rare occasion, when controller utilizes some service of which the current view is not aware of ... I actually cannot think of a use-case for such occurrence.
P.S.
Actually the state of model layer is not held in the services themselves, but in the domain objects which they manipulate.
If you use a shared factory, which can make sure that each service is initialized only once, then the service, that view uses, will be the same. It also means, that the domain objects, with which service worked, can still be there (depends on your implementation, of course).
For example, if you try to create user account, with an email that already exists, the domain object for representing the account details will acquire an error state, when storage abstraction gets an exception about violating UNIQUE constraint. To show a good "registration failed" page, the service will need that domain object with both its data and its error state.
I hope it helps

Service layer and model associations with Domain-Driven Design

I'm in the process of designing the base architecture of a web application. The project follows the Domain-Driven Design approach because the business model and logic is very complex.
The project also aims to be a SOA project (Service Oriented Architecture). So I'm learning a lot about Services and how to construct the project around it.
Following a previous question of mine, I have a question regarding associations in model classes.
I understand that model classes shouldn't know and do anything related to persistence. However I have trouble deciding for situations with association between model classes.
For example:
class Person
class Car has one driver (for the example)
Where should the getDriver and getCars be?
in the model classes: $car->getDriver()
in the service layer with primitive types: $personService->getPerson($car->getDriverId())
in the service layer using OOP: $carService->getDriver($car)
Solution 1. seems the more natural. I'm using Doctrine 2, so the model associations are handled with DB mapping annotations. That way, the model doesn't do anything related to persistence (even though it does through Doctrine actually). It's my favorite solution, but then what's the point of the Service except load the list of "cars" to start with?
Solution 2. seems just stupid because it throws away OOP and the Model/Service user has to know about the Database model to fetch association (he has to know that this ID is a "Person" id). And he has to do the association himself.
Solution 3. is a bit better than solution 2, but still where is the OOP in that?
So, for me solution 1. is the best. But I have seen Solution 2. and Solution 3. used in real projects (sometimes mixed together), and so I have doubts.
And the question becomes more complex when there are additional parameters, for example:
$person->getCars($nameFilter, $maxNumberOfResults, $offset);
(in this case, it really looks like a SQL query/persistence query)
So, which one should be used for a Model/Service architecture on a project following the Domain-Driven Design approach? With SOA, should my model be only "dumb" data container with no logic? If so, then where is the DDD approach?
In the context of DDD, this is a problem of deciding whether a relationship between entities is expressed via direct object association vs. repository. Both approaches can be valid and depend on the nature of the relationship. For example, in your domain, a person may have a lot of cars associated with them, and it doesn't really make sense to have a direct association to the set of cars from the person entity. Remember, the job of the entity, or more specifically the aggregate root, is to protect invariants and enforce business rules. If the set of cars associated with a person isn't required for any behavior that exists on the person class, then there is no reason to put the association on the person entity. Further more, as your example shows, the query for cars may need to be filtered. To answer your question, I would place the responsibility of representing the person-to-cars relationship in a repository. SOA is orthogonal to DDD and is more focused on how business functionality is accessed and deployed. It is informative to consider the interplay between DDD and SOA from the perspective of hexagonal architecture also called onion architecture. Your domain is at the core, encapsulated by a set of application services which form an API facade around your domain. These are different from services in SOA, which are ports/adapters in the hexagonal/onion architecture and they serve ti expose these application services as SOA services.
If your project is DDD I don't get it why you want a Model/Service architecture. IMO this creates an anemic model and everything is pretty much procedural .
Now, being DDD it means you don't care for the db. You have though (at least logically) 2 models: the domain and the persistence. The Domain model deals with the associations in the most natural way, best suitable to represent the business case. 'Has one driver' or has many it's a db centric thinking that has no place in DDD. The Persistence model handles the way the Aggregate Root will be stored in the db (here's where you define the ORM entities and their relationships et all).
About your questions, first of all it matters the context and the purpose. If it's strictly for queries (to display to a user) then a simple model can be used, no need for DDD and business rules. The controller can ask directly the specialised query repository for the data, returned as a DTO.
If you want to update the Person or a car, then in the Application Layer (I'm usually using a command based approach so in my case all these happen in a command handler, but architecturally it's still part of the Application Layer) you can retreieve the AR best suited for the task from the (domain) repository. The domain repository knows that getPerson($id) should return a domain entity as opposed to the query repository which returns a simple DTO.
$person=$repo->getPerson($id);
//do stuff
$repo->save($person);
//optionally raise event (if you're using the domain events apprach)
But what's tricky is to decide what is the AR in what context. A car has one driver in what context? A driver really belongs to a car? Is there the concept of the owner? You have the Person class, but a person can be the driver or the owner (or not if it's a rental company). As you see, it pretty much depends on the domain and only after you have a clear image of the domain you can start thinking about how do you store data and what object (entity) is returned by the repository.
When thinking about what goes where, consider the purpose of both the service and the model. Services reside in the application layer while models reside in the domain layer. So, what does your application need to know about a Person? Not much, probably. The UI will likely send some ids to process with a requested action.
Here, the AR is a Driver model. Keep in mind that services may contain other services and that Doctrine entites are POPOs and do not need to be anemic. Also, try to decouple the development thought-processes away from the persistence. For example, a $driverId does not need to be an integer, it can be any unique identifier that is relevant to the domain.
// DriverService
// If more parameters are needed, consider passing in a command object
public function beginTrip($driverId, $carId, $fromLocationId, $toLocationId)
{
$driver = $this->repository->find($driverId);
$car = $this->carService->getAvailableCar($carId, $driverId);
$withItenerary = $this->locationService->buildItenerary(
[$fromLocationId, $toLocationId]
);
$driver->drive($car, $withItenerary); // actual 'driving' logic goes here
$this->eventService->publish(new BeginTripEvent($driver, $car, $withItenerary));
}
OK first I understand I mixed SOA and application services.
True. You are mixing Domain Layer (DDD) methods with Domain Objects and Service Layer (SOA) methods with Data Transfer Objects in the question.
Domain Layer objects are different objects than Service Layer objects! For example, Service Layer may have a CarDTO object instead of Car object and DriverDTO object instead of Driver object.
$car->getDriver() is a perfectly correct way to access Driver in Domain Layer, and can also be used in a Service Layer with a restriction that wherever Service consumer requests Car data, Service always returns a Car with a Driver.
$personService->getPerson($car->getDriverId()) is valid only in Service Layer and invalid in Domain Layer. The reason for this method is Driver data is too large and complex to be always returned with a Car. Thus Service provides a separate method to request Driver data.
$carService->getDriver($car) is invalid in Domain Layer and strange to see in Service Layer, because this construction means that Service consumer must send all Car data to the a CarService to get Driver data. It is better to send only CarID and maybe to a PersonService, not to a CarService (Variant 2).
A more complex example $person->getCars($nameFilter, $maxNumberOfResults, $offset); looks strange in Domain Layer, since it doesn't contain much Business Logic. But if changed into $CarService->getCars($nameFilter, $maxNumberOfResults, $offset); it becomes suitable in Service Layer for partial requests.

Categories