Right use about command handlers in ddd - command

I'm creating an application in DDD. I want to know two things:
1- Is it correct to create the value objects (id, email, password) in the RegisterUserHandler? or I have to create a specific class that make that?
2- It is necessary to create a factory to a simple entity creation. I use userfactory to create the user, but I can put directly the next line: "$ user = User :: register ($ id, $ email, $ password);" in the RegisterUserHandler and delete the userFactory?
//class RegisterUserHandler
public function handle(CommandInterface $command)
{
$id = Id::create();
$email = Email::create($command->email());
$password = Password::create($command->password());
$this->userFactory->create($id, $email, $password);
}
//class userfactory
public function create(Id $id, Email $email, Password $password)
{
$user = User::register($id, $email, $password);
return $user;
}

You don't necesarily need to use a factory to create value objects or entities if the creation is as simple as a constructor call. The principle that applies in this case is KISS.
If the process contains some algorithm then you could extract it into a factory to move the responsibility elsewhere.

Related

In CQ(R)S, is it OK to use a Command as a parameter of a model constructor?

Say I have a CreateUser command:
class CreateUser
{
public string $email;
public string $password;
public string $firstName;
public string $lastName;
public LocalDate $dateOfBirth;
public ?string $location;
}
Is it OK if my User model accepts this command as a constructor parameter?
i.e. instead of having this:
class User
{
public function __construct(
string $email,
string $password,
string $firstName,
string $lastName,
LocalDate $dateOfBirth,
?string $location
) {
...
and have the command handler map the command data to the model(s), I could just simply make the model constructors accept the command as a parameter and extract the data they need:
class User
{
public function __construct(CreateUser $command)
{
...
}
Is this a correct approach, or are there drawbacks?
Is this a correct approach, or are there drawbacks?
Small drawbacks.
Drawback #1 - you've added a (small) extra step of work. If I want a User, I first have to get a CreateUser command. So there's an extra step that gets in the way.
Drawback #2 - because you need a CreateUser, you need values for all of the fields of User and all of the extra fields that User doesn't care about.
For example, suppose you later decide that CreateUser should have a messageId. Now the code paths that want a User need to invent a messageId that they don't want in order to construct a CreateUser that they don't want so that they can construct the User that they do want.
Wanting to have a function that accepts a CreateUser and returns a User is perfectly reasonable. It's even reasonable that you would want that function to be close to User.
You probably don't want that function to be __construct, though. A static helper method would probably be a healthier long term solution.

Laravel one to many relationship save method empty attributes

I am trying to save a relationship with the Laravel save method:
public function storeContact(Request $request)
{
$user = User::firstOrNew(['email' => $request->input('email')]);
$user->save();
$message = new App\Message([
'message' => $request->input('remarks')
]);
$user->message()->save($message);
}
var_dump($request->all) confirms both fields are available in the request.
All relations work. hasOne, belongsTo are configured in the models. The relation is saved like expected (but message field is empty)
When I var_dump($message), there are no attributes in the collection.
I already tried fillable and guarded on the models without any effect. These should not be necessary for the save method though because this uses a full Eloquent model instance.
What am I missing here??
I think I found the culprit.
When I use a __construct on a model it fails. When I instantiate a model with a __construct no variables are passes as attributes. Even if the __construct is empty.
Test with __construct method
class Message extends Model
{
protected $connection = 'system';
public function __construct()
{
}
// ...
}
$message = new App\Message(['remarks' => 'Test remarks']);
var_dump(message) // does NOT contain attributes!
Test2 without __construct method
class Message extends Model
{
protected $connection = 'system';
// ...
}
$message = new App\Message(['remarks' => 'Test remarks']);
var_dump(message) // does contain attributes!
This looks like a bug in Laravel to me.

capturing the login event in zendframework 2

I want to capture the loggin event in zendframework2 and then update the database when the user last logged in.
i am aware that if i do the following in the onBootstrap(MVCEvent $e) of my module i will be able to capture the event etc:
$eventManager = $e->getApplication()->getEventManager();
$em = $eventManager->getSharedManager();
$em->attach(
'ZfcUser\Authentication\Adapter\AdapterChain',
'authenticate',
function($e)
{
$id = $e->getIdentity();
}
);
this will give me the Id of the user. however, the confusion is how i can then update my database from the bootstrap. i mean, i dont have access to the entity manager in my bootstrap and i am not sure how to transport it there. the entity manager is held in the service config file.
i.e
getServiceConfig()
'Members\Model\WorkerTable' => function($sm) {
$db = $sm->get('doctrine.entitymanager.orm_default');
$table = new Model\MemberTable($db);
return $table;
},
.
with the above settings i am able to access the entity manager in my MemberTable class
so, a simple solution would be to transfer the loggin event manager to my
** MemberTable class** where i would use my entity manager to update the database.
issue, i am not sure how to set this up:
$eventManager = $e->getApplication()->getEventManager();
$em = $eventManager->getSharedManager();
i mean, i dont know how to get the variable $e into the MemberTable class so that i can access the eventManger and the sharedManager.
in summary; the issues are twofold.
how do i get the entity manager into the bootstrap function
alternatively
how do i get the eventManager and shared eventmanager into a normal class so that i can call the eventmanger in a class that already contains the entity manager
Well, all you have to do is to retrieve the service manager this way:
$serviceManager = $e->getApplication()->getServiceManager();
and then get your entity manager like this:
$entityManager = $serviceManager->get('Members\Model\WorkerTable');
Does it solve your problem?
The answer to the second question
To bring a variable into the closure from outside you can use "use" operator like so:
function() use ($myVar){
// some code
}
So, in your case I would do:
$eventManager = $e->getApplication()->getEventManager();
$em = $eventManager->getSharedManager();
$em->attach(
'ZfcUser\Authentication\Adapter\AdapterChain',
'authenticate',
function($e) use ($entityManager){
$id = $e->getIdentity();
}
);
If you are planning to have a lot of code inside your closure I would suggest to put it into a separate class and make it invokable. For instance,
class YourClosureCode
{
private $entityManager;
public function __construct($eventManager)
{
$this->eventManager = $eventManager;
}
public function __invoke(EventInterface $e)
{
// put your closure code here
}
}
Then a slight modification here:
$eventManager = $e->getApplication()->getEventManager();
$em = $eventManager->getSharedManager();
$em->attach(
'ZfcUser\Authentication\Adapter\AdapterChain',
'authenticate',
new YourClosureCode($entityManager);
);

In Zend, is there a better way to check if a user hasIdentity()?

Currently, I am using Zend_Auth::getInstance()->hasIdentity() to check if my user is logged in in every controller that requires a login. I feel like I am practicing Zend horribly, so I wanted to ask the more experienced and know if this is the proper way to do this? If not, could you please tell me what is?
We use a Controller plugin (bootstrapped in application.ini config file) that handles our authentications. It checks the requested controller/action in the preDispatch() phase and matches against ACL objects (could be fetched out of DB, config files, XML, etc.). If the user does not have the privilege to access the target controller/action, the a message is stored in the session and user is redirected to another page, displaying the access forbidden message.
If the user needs to have authentication to access the target controller/action, user is redirected to the login action by modifying the request object.
Using this plugin there is no need to check for user authentication/ACL in each controller and so all the "Access" code would be enclosed in one file, the "Access Plugin".
In order to check for user identity we mostly use the same method of "Zend_Auth::getInstance()->hasIdenity()", but this just shows if the user is authenticated or not. the '''getIdentity()''' method of Zend_Auth returns the current user identity, but again just the identity and not more. However if you would need more information of the user, you could store the user information in a session.
We implement our users as data models, so each user is defined as an object. after a user is authenticated on the login action, we create the appropriate user object and store it in the user session, like this:
// This could be a sample code in AuthController/processloginAction()
// suppose $username is validated before and stores the username
$user = new Default_Model_User($username);
// now $user is our user object, suppose $log is a Zend_Log instance
$log->info("user id '{$user->getId()}' username: '{$user->getUsername()}' logged in");
$sess = Zend_Session_Namespace('auth');
$sess->user = $user;
From now one, the $user property of the session namespace of 'auth' is the user object with all the information you would need about, not just the identity. and whenever you wanted to check if user is logged in (beside using Zend_Auth) you could check for availability of this value on the user session:
$sess = Zend_Session_Namespace('auth');
if (!isset($sess->user) || !$sess->user) {
// user is not logged in, redirect to login page
}
$user = $sess->user;
/*#var $user Default_Model_User*/
$email = $user->getEmail();
now we checked for authentication, and have access to user information (email, phone, etc.).
I use a method similar to the method described by Herman Radtke in his blog at http://www.hermanradtke.com/blog/more-reliable-authentication-in-zend-framework/. Basically create a controller plugin as farzad mentioned:
class My_Authentication extends Zend_Controller_Plugin_Abstract
{
private $_whitelist;
public function __construct()
{
$this->_whitelist = array(
'index/login'
);
}
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
$controller = strtolower($request->getControllerName());
$action = strtolower($request->getActionName());
$route = $controller . '/' . $action;
if (in_array($route, $this->_whitelist)) {
return;
}
$auth = Zend_Auth::getInstance();
if ($auth->hasIdentity()) {
return;
}
self::setDispatched(false);
// handle unauthorized request...
}
}
and then register that plugin in your bootstrap:
public function run() {
$front->registerPlugin(new My_Authentication());
}
I generally take this approach a little farther and integrate the Zend_Acl into the system as well. To do that I would define the plugin below:
class My_Acl_Authentication extends Zend_Controller_Plugin_Abstract
{
private $_acl;
public function __construct($acl)
{
$this->_acl = $acl
}
public function preDispatch(Zend_Controller_Request_Abstract $request)
{
$controller = strtolower($request->getControllerName());
$action = strtolower($request->getActionName());
$route = $controller . '/' . $action;
if (in_array($route, $this->_whitelist)) {
return;
}
$auth = Zend_Auth::getInstance();
$role = 'anonymous';
if ($auth->hasIdentity()) {
$role = $auth->getStorage->read()->role;
}
if ($this->_acl->isAllowed($role, $route)) {
return;
}
self::setDispatched(false);
// handle unauthorized request...
}
}
If you go this route there is some more work to be done, specifically you have to setup the ACL and then you also have to store the user's role in the auth storage.
Thats perfectly ok to do so but to save you from repeating that code you can extend all your controllers from a class A which is subclass of Zend_Controller_Action . Then inside this class declare a method
protected function hasIdentity()
{
return Zend_Auth::getInstance()->hasIdentity();
}
Now in your controller which is subclass of A you can simply do $this->hasIdentity(); instead

Can (and should?) Zend_Auth return class as the Identity?

I have a class R00_Model_User, which, curiously enough, represents user as he is. Can $result->getIdentity() return me an object of this class? (Or maybe it's stupid?)
(There is a factory method in R00_Model_User which prevents from duplicating objects. I'd like Zend_Auth to use it instead of creating a new object, if it can)
Two options:
write your own authentication adapter subclassing the out-of-the-box-adapter that matches your scenario best
class R00_Auth_Adapter extends Zend_Auth_Adapter_*
{
/**
* authenticate() - defined by Zend_Auth_Adapter_Interface. This method is called to
* attempt an authentication. Previous to this call, this adapter would have already
* been configured with all necessary information to successfully connect to a database
* table and attempt to find a record matching the provided identity.
*
* #throws Zend_Auth_Adapter_Exception if answering the authentication query is impossible
* #return Zend_Auth_Result
*/
public function authenticate()
{
$result = parent::authenticate();
if ($result->isValid() {
return new Zend_Auth_Result(
$result->getCode(),
R00_Model_User::load($result->getIdentity()),
$result->getMessages()
);
} else {
return $result;
}
}
}
This will allow you to code
$adapter = new R00_Auth_Adapter();
//... adapter initialisation (username, password, etc.)
$result = Zend_Auth::getInstance()->authenticate($adapter);
and on successfull authentication your user-object is automatically stored in the authentication storage (session by default).
or use your login-action to update the stored user identity
$adapter = new Zend_Auth_Adapter_*();
$result = $adapter->authenticate();
if ($result->isValid()) {
$user = R00_Model_User::load($result->getIdentity());
Zend_Auth::getInstance()->getStorage()->write($user);
}
In one of my applications, I have getIdentity() return a user object, and it works pretty well for me. To use your factory method, do like this:
$auth = Zend_Auth::getInstance();
$user = R00_Model_User::getInstance(...);
$auth->getStorage()->write($user);
Then when you call getIdentity(), you will have your user object.