Subscribe Us

Services in PHP - an Introduction

 





Services : 

when there are operations that need to be represented, but Entities and Value Objects aren't the best place, you should consider modeling these operations as Services. In Domain-Driven Design, there are typically three different types of Services you'll encounter:

Application Services: Operate on scalar types, transforming them into Domain types. A scalar type can be considered any type that's unknown to the Domain Model. This includes primitive types and types that don't belong to the Domain. 

 Domain Services: Operate only on types belonging to the Domain. They contain meaningful concepts that can be found within the Ubiquitous Language. They hold operations that don't fit well into Value Objects or Entities. 

Infrastructure Services: Are operations that fulfill infrastructure concerns, such as sending emails and logging meaningful data. In terms of Hexagonal Architecture, they live outside the Domain boundary.



Application Services

Application Services are the middleware between the outside world and the Domain logic. The purpose of such a mechanism is to transform commands from the outside world into meaningful Domain instructions. 

Let's consider the User signs up to our platform use case. Starting with an outside-in approach: from the delivery mechanism, we need to compose the input request for our Domain operation. Using a framework like Symfony as the delivery mechanism, the code would look something like this:

class SignUpController extends Controller

{

public function signUpAction(Request $request)

{

$signUpService = new SignUpUserService(

$this->get('user_repository')

);

try {

$response = $signUpService->execute(new SignUpUserRequest(

$request->request->get('email'),

$request->request->get('password')

));

} catch (UserAlreadyExistsException $e) {

return $this->render('error.html.twig', $response);

}

return $this->render('success.html.twig', $response);

}

}

 

As you can see, we create a new instance of our Application Services, passing all dependencies needed — in this case, a UserRepository. UserRepository is an interface that can be implemented with any specific technology (Example: MySQL, Redis,  Elasticsearch). Then, we build a request object for our Application Service in order to abstract the delivery mechanism — in this example, a web request — from the business logic. Last, we execute the Application Service, get the response, and use that response for rendering the result. On the Domain side, let's check a possible implementation for the Application Service that coordinates the logic that fulfills the User signs up use case:

class SignUpUserService

{

private $userRepository;

public function __construct(UserRepository $userRepository)

{

$this->userRepository = $userRepository;

}

public function execute(SignUpUserRequest $request)

{

$user = $this->userRepository->userOfEmail($request->email);

if ($user) {

throw new UserAlreadyExistsException();

}

$user = new User(

$this->userRepository->nextIdentity(),

$request->email,

$request->password

);

$this->userRepository->add($user);

return new SignUpUserResponse($user);

}

}

Everything in the code is about the Domain problem we want to solve, and not about the specific technology we're using to solve it. With this approach, we can decouple the high level policies from the low-level implementation details. The communication between the delivery mechanism and the Domain is carried by data structures called DTOs.

 

Domain Services

Throughout conversations with Domain Experts, you'll come across concepts in the Ubiquitous Language that can't be neatly represented as either an Entity or a Value Object,  such as: Users being able to sign into systems by themselves A shopping cart being able to become an order by itself The preceding example are two concrete concepts, neither of which can naturally be bound to either an Entity or a Value Object. Further highlighting this oddity, we can attempt to model the behavior as follows:

class User

{

public function signUp($aUsername, $aPassword)

{

// ...

}

}

class Cart

{

public function createOrder()

{

// ...

}

}

In the case of the first implementation, we're not able to know that the given username and password relate to the invoked-upon user instance. Clearly, this operation doesn't suit this Entity; instead, it should be extracted out into a separate class, making its intention explicit. With this in mind, we could create a Domain Service with the sole responsibility of authenticating users:

class SignUp

{

public function execute($aUsername, $aPassword)

{

// ...

}

}

Similarly, as in the case of the second example, we could create a Domain Service specialized in creating orders from a supplied cart:

class CreateOrderFromCart

{

public function execute(Cart $aCart)

{

// ...

}

}

A Domain Service can be defined as an operation that fulfills a Domain task and  naturally doesn't fit into either an Entity or a Value Object. As concepts that represent operations in the Domain, Domain Services should be used by clients regardless of their run history.

Domain Services don't hold any kind of state by themselves, so Domain Services are stateless operations.

 

Domain Services and Infrastructure Services

It's common to encounter infrastructural dependencies when modeling a Domain Service 

— for example, in the case where an authentication mechanism that handles  password hashing is required. In this instance, you could use a Separated Interface, which allows for multiple hashing mechanisms to be defined. Using this pattern still provides you with a clear Separation of Concerns between the Domain and the Infrastructure: 

namespace Ddd\Auth\Domain\Model;

interface SignUp

{

public function execute($aUsername, $aPassword);

}

Using the preceding interface found in the Domain, we could create an implementation in the Infrastructure layer, like the following:

namespace Ddd\Auth\Infrastructure\Authentication;

class DefaultHashingSignUp implements Ddd\Auth\Domain\Model\SignUp

{

private $userRepository;

public function __construct(UserRepository $userRepository)

{

$this->userRepository = $userRepository;

}

public function execute($aUsername, $aPassword)

{

if (!$this->userRepository->has($aUsername)) {

throw UserDoesNotExistException::fromUsername($aUsername);

}

$aUser = $this->userRepository->byUsername($aUsername);

if (!$this->isPasswordValidForUser($aUser, $aPassword)) {

throw new BadCredentialsException($aUser, $aPassword);

}

return $aUser;

}

private function isPasswordValidForUser(

User $aUser, $anUnencryptedPassword

) {

 

}

}

Here is another implementation based instead on the MD5 algorithm:

namespace Ddd\Auth\Infrastructure\Authentication;

use Ddd\Auth\Domain\Model\SignUp

class Md5HashingSignUp implements SignUp

{

const SALT = 'S0m3S4lT' ;

private $userRepository;

public function __construct(UserRepository $userRepository)

{

$this->userRepository = $userRepository;

}

public function execute($aUsername, $aPassword)

{

if (!$this->userRepository->has($aUsername)) {

throw new InvalidArgumentException(

sprintf('The user "%s" does not exist.', $aUsername)

);

}

$aUser = $this->userRepository->byUsername($aUsername);

if ($this->isPasswordInvalidFor($aUser, $aPassword)) {

throw new BadCredentialsException($aUser, $aPassword);

}

return $aUser;

}

private function salt()

{

return md5(self::SALT);

}

private function isPasswordInvalidFor(

User $aUser, $anUnencryptedPassword

) {

$encryptedPassword = md5(

$anUnencryptedPassword . '_' .$this->salt()

);

return $aUser->hash() !== $encryptedPassword;

}

}

Opting for this choice allows us to have multiple implementations of the Domain  Service interface at the Infrastructure layer. In other words, we end up with several Infrastructure Domain Services. Each Infrastructure service will be responsible for handling a different hash mechanism. Depending on the implementation, the use can easily be managed through a Dependency Injection container — for example, through Symfony's Dependency Injection component:

 

<?xml version="1.0"?>

<container

xmlns="http://symfony.com/schema/dic/services"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="

http://symfony.com/schema/dic/services

http://symfony.com/schema/dic/services/services-1.0.xsd">

<services>

<service id="sign_in" alias="sign_in.default" />

<service id="sign_in.default"

class="Ddd\Auth\Infrastructure\Authentication

\DefaultHashingSignUp">

<argument type="service" id="user_repository"/>

</service>

<service id="sign_in.md5"

class="Ddd\Auth\Infrastructure\Authentication

\Md5HashingSignUp">

<argument type="service" id="user_repository"/>

</service>

</services>

</container>

Share:

0 Comments:

Post a Comment

If you have any doubts . Please let me know.

Powered by Blogger.

Ad Code

Responsive Advertisement

Ad Code

Responsive Advertisement

Featured post

Search This Blog

Recently added book names

THE HTML AND CSS WORKSHOP   | MICROSOFT POWER BI COOKBOOK   | MongoDB in Action, 2nd Edition  | ADVANCED DEEP LEARNING WITH PYTHON   | Cracking Codes with Python An Introduction to Building and Breaking  | Moris Mano Degital Design 3rd Edition  | Beginning App Development with Flutter by Rap Payne  |react hooks in Action - John Larsen   | Artificial Intelligence A Modern Approach Third Edition Stuart Russel  | Data Structures and Algorithms - Narasimha Karumanchi   | Thomas S.M. - PostgreSQL High Availability Cookbook - 2017  | Gunnard Engebreth PHP 8 Revealed Use Attributes the JIT Compiler   | ICSE Class X Computer Application Notes   | INTERNET OF THINGS PROJECTS WITH ESP32   | 100 aptitude trick(102pgs)s   | OBJECT_ORIENTED_PROGRAMMING Question & Answer   | C questions and answer   | Full_Book_Python_Data_Structures_And_Algorithm   | Jira 8 Administration Cookbook Third Edition  | KALI LINUX WIRELESS PENETRATION TESTING BEGINNERS GUIDE THIRD EDITION - Cameron Buchanan, Vivek Ramachandran  HTML5 & javascript By :- Jeanine Meyer   | Python For Beginners Ride The Wave Of Artificial Intelligence   | HackingTheXbox   | Introduction to Algorithms 3rd.Edition - (CLRS)   | The C++ Programming Language - Bjarne Stroustrup   | Modern C++ Programming Cookbook - Marius Bancila   | Java The Complete Reference Eleventh Edition   Data_Communications and Networking 4th Ed Behrouz A Forouzan   | DevOps with Kubernetes - Hideto Saito   | The-Linux-Command-Line-A-Complete-Introduction   | Assembly Language for X86 Processors KIP R. Irvine   | Effective_Modern_C++ - Scott Meyer

Contact Form

Name

Email *

Message *

Followers

Mobile Logo Settings

Mobile Logo Settings
image

Computer Training School Regd. under Govt. of West Bengal Society Act 1961

Header Ads Widget

Responsive Advertisement

Hot Widget

random/hot-posts

Recent in Sports

Popular Posts

Labels

Blog Archive

Blogger templates