{"id":18000807,"url":"https://github.com/josecelano/ddd-laravel-sample","last_synced_at":"2025-10-28T07:39:13.823Z","repository":{"id":37547103,"uuid":"94704483","full_name":"josecelano/ddd-laravel-sample","owner":"josecelano","description":"A Laravel DDD sample application using CQRS and persisting entities serialized without ORM","archived":false,"fork":false,"pushed_at":"2022-06-21T17:43:25.000Z","size":2262,"stargazers_count":279,"open_issues_count":16,"forks_count":57,"subscribers_count":15,"default_branch":"master","last_synced_at":"2025-10-11T13:48:34.031Z","etag":null,"topics":["cqrs","ddd","laravel","php"],"latest_commit_sha":null,"homepage":null,"language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/josecelano.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2017-06-18T18:09:16.000Z","updated_at":"2025-08-15T15:51:43.000Z","dependencies_parsed_at":"2022-07-09T16:16:53.703Z","dependency_job_id":null,"html_url":"https://github.com/josecelano/ddd-laravel-sample","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/josecelano/ddd-laravel-sample","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/josecelano%2Fddd-laravel-sample","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/josecelano%2Fddd-laravel-sample/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/josecelano%2Fddd-laravel-sample/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/josecelano%2Fddd-laravel-sample/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/josecelano","download_url":"https://codeload.github.com/josecelano/ddd-laravel-sample/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/josecelano%2Fddd-laravel-sample/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":281403399,"owners_count":26495042,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-10-28T02:00:06.022Z","response_time":60,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cqrs","ddd","laravel","php"],"created_at":"2024-10-29T23:14:11.505Z","updated_at":"2025-10-28T07:39:13.795Z","avatar_url":"https://github.com/josecelano.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Laravel DDD sample application\n\nBy [Jose Celano](http://josecelano.com/)\n\nA Laravel DDD sample application.\n\nThe purpose: build a simple DDD Laravel application to be compared with the CRUD approach.\n\nYou can find the CRUD approach here: https://github.com/josecelano/my-favourite-appliances.\n\nI have read a lot of posts saying that DDD is ony valid for complex domains. But sometimes I also have read some of them \nsaying DDD can also be applied for simple problems. I think I would use a CRUD approach for prototypes and refactor\nlater to DDD as soon as the project becomes a long term project. But on the other hand I do not think that the DDD approach\ncan be much more expensive than the CRUD one. With this sample I want to test both solutions for the same simple problem,\nin order to compare them.\n\nIn this example I have used CQRS. Domain entities are stored in a serialized object in the database. The idea was to do something\nas what Vaughn Vernon describes here:\n\nThe Ideal Domain-Driven Design Aggregate Store?\nhttps://vaughnvernon.co/?p=942 \n\nOn the other hand Read Models are created using Eloquent models.\n\n* Write model -\u003e Table with to columns: id, data (serialized object)\n* Read model -\u003e Eloquent models\n\nPlease, see \"Problems\" section if you want to know what kind of drawbacks I had for this architecture.\n\n## Specifications\n\nCreate a website where users will be able to see a variety of home appliances, creating a wishlist of their favourite ones \nwhich can be shared with friends.\n\nThe application will use another site as a primary data source: https://www.appliancesdelivered.ie .\nThe new site should contain products from both the small appliances and dishwashers categories:\n\n* https://www.appliancesdelivered.ie/search/small-appliances\n* https://www.appliancesdelivered.ie/dishwashers\n\nUsers will be able to see the data for these products presented in a clean and attractive format, regardless of the \ndevice they're using to view the site. \n\n* Users can order the data by title or price.\n* When on the site, a user can create an account to save their favourite appliances to their wishlist.\n* Their wishlist can then be shared with other friends.\n* Their friends may not like the appliances the user has selected, so the user may also need to quickly remove items \nfrom their wishlist!\n\nWe'll want our new site to have good data, so need the ability to regularly sync new data from\nAppliancesDelivered.ie to our great new site. But keep in mind that if our new site gets very popular, we don't want\nto kill the source site with increased requests and server load, so we need to think carefully about how we handle this \nsyncing process (how often it's run, when it's triggered, what we do with the resulting data etc).\n\nWe also need to allow for the case that AppliancesDelivered.ie may be down for maintenance, but we want our site \nto stay alive, so keep that in mind also when thinking about your approach here. The more confidence we can have in \nthe continued operation of the site, the better! At some point in the future, if this site is successful the data source \nmay be migrated from this crawler approach to a more formal API-based approach, so keep that path in mind when \nstructuring your code.\n\nThe above are the main points of the application, but if you feel the application can be improved or any interesting \nother features implemented, then feel free to go wild!\n\n## Installation\n\n```bash\nmysqladmin -u homestead -psecret create dddlaravelsample\ngit clone git@github.com:josecelano/ddd-laravel-sample.git\ncd dddlaravelsample\nphp -r \"file_exists('.env') || copy('.env.example', '.env');\"\ncomposer install\nphp artisan storage:link\nphp artisan migrate\nphp artisan db:seed\nphp artisan serve\n```\n\n## Run crawler\n\n```bash\nphp artisan import:dishwashers\nphp artisan import:small-appliances\n```\n\nScheduler is set to execute import hourly:\n\n```bash\nphp artisan schedule:run\n```\n\n## Reset all application data\n\n```\nphp artisan migrate:refresh --seed\nphp artisan import:dishwashers\nphp artisan import:small-appliances\n```\n\n## Live demo\n\n* Url: http://my-favourite-appliances.hyve.software\n* Demo accounts: https://github.com/josecelano/ddd-laravel-sample/blob/master/database/seeds/Access/UserTableSeeder.php\n\nOpen localhost:8000 in the browser.\n\n## TODO\n\n* Dispatch events with static service when they are produced instead of storing them in the entity and distpactching them\n  in the command handler.\n* Use JSON instead of serialized object in database.\n* Remove appliances not updated in the last 24 hours.\n* Enable more social authentication providers.\n* Order list by title and price.\n* Dislike button on each wishlist item (ReactJS component). Show different icon if user has already clicked.\n* Dislikes counter (ReactJS component).\n* Add username to user profile and change permalink for users' wishlist (http://localhost:8000/1/wishlist to http://localhost:8000/username/wishlist)\n* Store events.\n* REST API for events.\n* Add tests.\n\n## Problems\n\n* Since we only query from read model tables, even when we want to get a domain entity we could not find domain entities \neven if they exist, if the read model does not exist. For example: if there is an error after creating a domain entity,\n and the app can not create the read model, then the entity can not be found. The only way to fix this problem is using \n a database which supports queries using filtering by JSON attributes in JSON column types.\n\n* Since we store entities serialized with all attributes instead of JSON format, we also store events if we do not\nrelease the events before persisting the entity, in other words we have to call `save` method always after releasing events:\n\n```\n$this-\u003eemitter-\u003eemitGeneratedEvents($appliance);\n$this-\u003eapplianceRepository-\u003esave($appliance);\n```\n\nIf we do not do that events will be trigger again every time we load the entity from database. This could be solve by \nstoring entities in JSON without the events. We could also dispatch events before saving in the repository, or finally\nwe could use a static method to dispatch events where there are produced without storing them in the entity. \n\nMore info about different approaches here:\nhttps://youtu.be/dXcHRcvgcUc?list=PLfgj7DYkKH3Cd8bdu5SIHGYXh_bPV2idP\u0026t=338 (Spanish)\n\n## Acknowledgment\n\nI have used this boilerplate: https://github.com/rappasoft/laravel-5-boilerplate\n\n## Links\n\n* http://codebetter.com/gregyoung/2010/02/15/cqrs-is-more-work-because-of-the-read-model/ (by https://github.com/gregoryyoung?)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjosecelano%2Fddd-laravel-sample","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjosecelano%2Fddd-laravel-sample","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjosecelano%2Fddd-laravel-sample/lists"}