Git Product home page Git Product logo

last-wishes's People

Contributors

carlosbuenosvinos avatar hendore avatar keyvanakbary avatar mgonzalezbaile avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

last-wishes's Issues

Violation of Doctrine Rule about foreign keys

Hi,

you are mapping foreign keys to object properties which is forbidden from Doctrine point of view.

Foreign keys have no meaning whatsoever in an object model. Foreign keys are how a relational database establishes relationships. Your object model establishes relationships through object references. Thus mapping foreign keys to object fields heavily leaks details of the relational model into the object model, something you really should not do.

Could you comment it? How to deal with it without violation this rule?

Why do you need userId inside Wish entity if you have one-to-many through join table?

http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/best-practices.html#don-t-map-foreign-keys-to-fields-in-an-entity

Multiple Application Service Methods per Class

Hi, Thanks for your awesome book! I have a question:

On page 306 your say:

Using a dedicated class per Application Service makes the code more robust against external changes (Single Responsibility Principle). There are fewer reasons to change the class, as the Service does one and only one thing. The Application Service will be easier to test, seeing as it does less things. It’s easier to implement a common Application Service contract, making class decoration easier (check out the chapter on transactions in Repositories). This will also result in higher cohesion, as all dependencies are exclusively dedicated to a single use case.
The execution method could have a more expressive name, like signUp. However, the execute Command pattern186 format standardizes a common contract across Application Services, thereby enabling easy decoration, which comes in handy for transactions.

How would you handle viewing " one wish" vs e.g. "All whishes"? Would this be:

  1. Two separate classes for the two use cases
  2. One class; Two methods
  3. One class; logic handled in the execute method based on parameter / request obj
  4. Another option?

Thanks.

Low quality of the project

Hey,

I am DDD practitioner and I was doing DDD Lite and full DDD in few projects already.
I know how many PHP developers creating crappy code so I was really happy about the book and sample project. I've spend some time going through the code, because I wanted to see what advices, concepts are given and to contribute, if needed.
I've checked the book and need to say it's very good, but I can't say the same about the project.

Let's start from the beginning.
DDD should be used for non trivial domains to solve. The problem that is taken for the project is just a little bit more than CRUD. Looking at the code, we may see that it tries to hack reality by solving easy problem with a lot of layers and creating complexity in the places where it's not needed.
I am sure, that it will bring value for a lot of people, but possibility to learn solving non trival domains for PHP developers is lost in here.

Next thing. I've forked the project and I was pretty sure everything will work like a charm. It's sample project to show ideas from the book, so it had to work.
First I had configure the project, but I was okey with it. I checked what is needed and wasn't really happy to install dependencies on my host machine. So I spend a little time on automatic it with docker.
When I've finished I could run the app, but the app didn't worked. Application was just throwing exceptions on me. This is just really bad, that app that is about sharing the knowledge, can't be even run, because of exceptions. When I've fixed them (MR in queue), I had a chance to check out the code and I really didn't liked what I saw.

What I've faced except the not working application was:

1. No tests - I am really disappointed about this one. As this book is for developers who really want to learn they should be provided with best examples. Not having tests in the project is like waiting for catastrophe. The project has bugs in such simple domain and it's only, because of the lack of tests. There should be unit, integration, functional tests so people can know how to write them.
2. DomainEventPublisher in model - This makes the model untestable and coupled with higher level abstraction.
3. new DateTime throwed everywhere - Again makes the model untestable and breaks the SOLID.
4. High couplings between upper layers and domain. WishEmail extending Wish, now whenever domain object is changed infrastructure object need to be also changed. It also breaks the SOLID.
5. Configuration available within email sending class. Let's say the WishEmail is good solution. WishEmail doesn't receive info how to send email from outside, but is responsible for it.
The next problem with it is that login and password is provided within the class. (I hope you changed it btw). Such stuff should always be injected.
6. Lack of examples with Value Objects. The only one created within the project is Id. Email is like one of the most popular VO, why not use it?
7. Aggregate root should hold transaction boundaries. In here it doesn't. Why wish is connected with user?
8. Aggregate root is burden with all this php global functions like trim, strtolower. If it need to be used, use it within Value Object for example email.
9. No Docblocks. In PHP 5, we can just guess, what should be provided within function for example.
Having docblock, should be must in all projects and especially ones like this
10. The domain model is pretty anemic, but this may be because of lack of hard problem to solve

There are things, that I liked like translation services, repositories and well separated modules. But I just expect much, much more from DDD leading book for PHP.
Hope, my insights will give you some guidance to increase the value of the project. :)

How can I return with an array of users

In all of your examples in application services you illustrate how to return a DTO but with one user
so I need to know how to return a collection of users

this is what you did with one user, or in another example, you return a user transformer:

class SignUpUserService
{
    public function execute(SignUpUserRequest $request)
    {
// ...
        $user = // ...
        return new UserDTO($user);
    }
}

and what should to be done in pagination?

LoggerDomainEventSubscriber.php coupled to infrastructure at domain layer

The LoggerDomainEventSubscriber.php is located in the Domain layer. In addition, it uses functionalities specific to the Infrastructure layer, such as Monolog or Elastica.

Wouldn't it be more appropriate and consistent with the principles dictated by DDD to create a contract (interface) of the Logger in Domain layer, implement it in the Infrastructure layer and then create a subscriber of the domain events in the Application layer?

Thanks in advance 😊

Signup error DateTimeImmutable given

on submit the signup form I got

Type error: Argument 2 passed to Ddd\Domain\Event\StoredEvent::__construct() must be an instance of DateTime, instance of DateTimeImmutable given, called in /home/joey/workbench/git/last-wishes/vendor/carlosbuenosvinos/ddd/src/Infrastructure/Application/Notification/DoctrineEventStore.php on line 19



    in StoredEvent.php line 34
    at StoredEvent->__construct('Lw\Domain\Model\User\UserRegistered', object(DateTimeImmutable), '{"user_id":{"id":"f62b75a0-76a1-481b-88e9-cbff0d66d0f1"},"occurred_on":{}}') in DoctrineEventStore.php line 19
    at DoctrineEventStore->append(object(UserRegistered)) in PersistDomainEventSubscriber.php line 21
    at PersistDomainEventSubscriber->handle(object(UserRegistered)) in DomainEventPublisher.php line 56
    at DomainEventPublisher->publish(object(UserRegistered)) in User.php line 64
    at User->__construct(object(UserId), '[email protected]', '123456') in SignUpUserService.php line 42
    at SignUpUserService->execute(object(SignUpUserRequest)) in TransactionalApplicationService.php line 42
    at TransactionalApplicationService->Ddd\Application\Service\{closure}(object(EntityManager))
    at call_user_func(object(Closure), object(EntityManager)) in EntityManager.php line 233
    at EntityManager->transactional(object(Closure)) in DoctrineSession.php line 32
    at DoctrineSession->executeAtomically(object(Closure)) in TransactionalApplicationService.php line 45
    at TransactionalApplicationService->execute(object(SignUpUserRequest)) in index.php line 45
    at {closure}(object(Request))
    at call_user_func_array(object(Closure), array(object(Request))) in HttpKernel.php line 139
    at HttpKernel->handleRaw(object(Request), '1') in HttpKernel.php line 62
    at HttpKernel->handle(object(Request), '1', true) in Application.php line 586
    at Application->handle(object(Request)) in Application.php line 563
    at Application->run() in index.php line 242

I'm using php7, please update https://github.com/dddinphp/ddd/blob/master/src/Domain/Event/StoredEvent.php#L34 thanks.

`makeWishAggregateVersion` and more than 3 wishes

Hi, thank you for the book. Just reading through the chapters.

In the book it was mentioned that there is a possibility that we end up with 3+ wishes in a rare case of parallel requests, although the business rule states there shouldn't be more than 3 wishes.

By moving the business logic to the user domain entity we do keep the logic in the domain which seems correct, but does it solve the problem above?

Also if the problem is to be solved somehow at the persistence layer, there the issue does not seem obvious without looking at the domain logic?

Maybe I'm missing something :)

https://github.com/dddinphp/last-wishes/blob/47cf7c5950734d8d90cd405432d5d20b2c897df3/src/Lw/Application/Service/Wish/AggregateVersion/AddWishService.php#L15

Error When Trying to signup

ContextErrorException in StoredEvent.php line 34:
Catchable Fatal Error: Argument 2 passed to Ddd\Domain\Event\StoredEvent::__construct() must be an instance of DateTime, instance of DateTimeImmutable given, called in /var/www/html/last-wishes/vendor/carlosbuenosvinos/ddd/src/Infrastructure/Application/Notification/DoctrineEventStore.php on line 20 and defined

Unable to generate a URL for the named route "login" as such route does not exist.

This happened after registering.

RouteNotFoundException in UrlGenerator.php line 130:
in UrlGenerator.php line 130
at UrlGenerator->generate('login') in index.php line 50
at {closure}(object(Request))
at call_user_func_array(object(Closure), array(object(Request))) in HttpKernel.php line 139
at HttpKernel->handleRaw(object(Request), '1') in HttpKernel.php line 62
at HttpKernel->handle(object(Request), '1', true) in Application.php line 586
at Application->handle(object(Request)) in Application.php line 563
at Application->run() in index.php line 239

ERROR: manifest for kibana:latest not found

when run : docker-compose up -d
report :

root@laber-System-Product-Name:~/last-wishes# docker-compose up -d
Creating network "last-wishes_default" with the default driver
Pulling queues (rabbitmq:management)...
management: Pulling from library/rabbitmq
f17d81b4b692: Pull complete
02fe1bd1a85c: Pull complete
66c15a50f4da: Pull complete
771c4c62018c: Pull complete
05e166e2684c: Pull complete
5eb4efce3466: Pull complete
9b5d77af0f63: Pull complete
f7fc14f8eeeb: Pull complete
31e1448101d9: Pull complete
196612f40314: Pull complete
8cd7ab5c5659: Pull complete
aae6dd0bf4aa: Pull complete
c8f2ac2cd4e8: Pull complete
98e5c73758c4: Pull complete
Digest: sha256:3eb2fa0f83914999846f831f14b900c0c85cea8e5d2db48ff73cf7defa12fe96
Status: Downloaded newer image for rabbitmq:management
Pulling kibana (kibana:)...
ERROR: manifest for kibana:latest not found

orm:schema-tool:create not working

Running the following cli command to build the schema ends up like this.

php bin/doctrine orm:schema-tool:create
PHP Warning:  Missing argument 1 for Lw\Infrastructure\Persistence\Doctrine\EntityManagerFactory::build(), called in /home/tworzenieweb/projekty/last-wishes/cli-config.php on line 7 and defined in /home/tworzenieweb/projekty/last-wishes/src/Lw/Infrastructure/Persistence/Doctrine/EntityManagerFactory.php on line 13
PHP Stack trace:
PHP   1. {main}() /home/tworzenieweb/projekty/last-wishes/vendor/doctrine/orm/bin/doctrine:0
PHP   2. include() /home/tworzenieweb/projekty/last-wishes/vendor/doctrine/orm/bin/doctrine:4
PHP   3. require() /home/tworzenieweb/projekty/last-wishes/vendor/doctrine/orm/bin/doctrine.php:55
PHP   4. Lw\Infrastructure\Persistence\Doctrine\EntityManagerFactory->build() /home/tworzenieweb/projekty/last-wishes/cli-config.php:7
PHP Notice:  Undefined variable: conn in /home/tworzenieweb/projekty/last-wishes/src/Lw/Infrastructure/Persistence/Doctrine/EntityManagerFactory.php on line 19
PHP Stack trace:
PHP   1. {main}() /home/tworzenieweb/projekty/last-wishes/vendor/doctrine/orm/bin/doctrine:0
PHP   2. include() /home/tworzenieweb/projekty/last-wishes/vendor/doctrine/orm/bin/doctrine:4
PHP   3. require() /home/tworzenieweb/projekty/last-wishes/vendor/doctrine/orm/bin/doctrine.php:55
PHP   4. Lw\Infrastructure\Persistence\Doctrine\EntityManagerFactory->build() /home/tworzenieweb/projekty/last-wishes/cli-config.php:7
PHP Fatal error:  Uncaught exception 'InvalidArgumentException' with message 'Invalid argument: ' in /home/tworzenieweb/projekty/last-wishes/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php:847
Stack trace:
#0 /home/tworzenieweb/projekty/last-wishes/src/Lw/Infrastructure/Persistence/Doctrine/EntityManagerFactory.php(21): Doctrine\ORM\EntityManager::create(NULL, Object(Doctrine\ORM\Configuration))
#1 /home/tworzenieweb/projekty/last-wishes/cli-config.php(7): Lw\Infrastructure\Persistence\Doctrine\EntityManagerFactory->build()
#2 /home/tworzenieweb/projekty/last-wishes/vendor/doctrine/orm/bin/doctrine.php(55): require('/home/tworzenie...')
#3 /home/tworzenieweb/projekty/last-wishes/vendor/doctrine/orm/bin/doctrine(4): include('/home/tworzenie...')
#4 {main}
  thrown in /home/tworzenieweb/projekty/last-wishes/vendor/doctrine/orm/lib/Doctrine/ORM/EntityManager.php on line 847

What is a difference between this two methods?

In User aggregate there are two different methods for creating wishes. What are the use cases for each?

As I guess the first one is perfect for persisting as a single.

    public function makeWishNotBeingAnAggregate(WishId $wishId, $address, $content)
    {
        $newWish = new Wish(
            $wishId,
            $this->id(),
            $address,
            $content
        );
        DomainEventPublisher::instance()->publish(
            new WishWasMade(
                $newWish->id(),
                $newWish->userId(),
                $newWish->address(),
                $newWish->content()
            )
        );
        return $newWish;
    }
    public function makeWish(WishId $wishId, $address, $content)
    {
        if (count($this->wishes) >= self::MAX_WISHES) {
            throw new NoMoreWishesAllowedException();
        }
        $this->wishes[] = new Wish(
            $wishId,
            $this->id(),
            $address,
            $content
        );
    }

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.