![Page 1: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/1.jpg)
This talk is clocked at 1 slide per 12.8 seconds and features unsafe amounts of code. Presenter is a registered Class 3 Fast Talker (equal to 1 Gilmore Girls episode).
Viewing is not recommended for those hungover, expected to become hungover or consuming excessive amounts of caffeine. Do not watch and operate motor vehicles.
If you accidentally consume this talk, flush brain with kitten pictures and seek emergency help in another talk. No hard feelings, seriously. It's almost the end of the conference, after all. Why are we even here?
Surgeon General's Warning
Notice in accordance with the PHP Disarmament Compact of 1992. Void where prohibited.
![Page 2: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/2.jpg)
ZendCon 2014
Models & Service Layers
Hemoglobin & Hobgoblins
Ross Tuck
![Page 3: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/3.jpg)
Freerange CodemonkeyKnow-It-All
Hot-Air Balloon
![Page 5: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/5.jpg)
About Today
![Page 6: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/6.jpg)
Hemoglobin
![Page 7: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/7.jpg)
Anemia.
![Page 8: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/8.jpg)
![Page 9: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/9.jpg)
Objects can too.
![Page 10: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/10.jpg)
class TodoList {
function setName($name);
function getName();
function setStatus($status);
function getStatus();
function addTask($task);
function setTasks($tasks);
function getTasks();
}
Model
![Page 11: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/11.jpg)
array(
'name' => '',
'status' => '',
'tasks' => ''
);
Model
![Page 12: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/12.jpg)
Bad Thing TM
![Page 13: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/13.jpg)
“In essence the problem with anemic domain models is that they incur all of the costs of a
domain model, without yielding any of the benefits.”
-Martin Fowler
![Page 14: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/14.jpg)
Our industry standard is an antipattern.
![Page 15: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/15.jpg)
Ouch.
![Page 16: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/16.jpg)
Important Note
![Page 17: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/17.jpg)
![Page 18: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/18.jpg)
![Page 19: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/19.jpg)
![Page 20: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/20.jpg)
Models
Stuf
![Page 21: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/21.jpg)
Integration over implementation
![Page 22: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/22.jpg)
Our Setup
![Page 23: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/23.jpg)
class TodoList {
function setName($name);
function getName();
function setStatus($status);
function getStatus();
function addTask($task);
function setTasks($tasks);
function getTasks();
}
Model
![Page 24: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/24.jpg)
class Task {
function setDescription($desc);
function getDescription();
function setPriority($priority);
function getPriority();
}
Model
![Page 25: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/25.jpg)
An ORM that's not Doctrine 2.A framework that's not Symfony2.
I promise.
![Page 26: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/26.jpg)
CRUD
![Page 27: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/27.jpg)
function addTaskAction($req) {
$task = new Task();
$task->setDescription($req->get('desc'));
$task->setPriority($req->get('priority'));
$list = $this->todoRepo->findById($req->get('id'));
if (!$list) { throw new NotFoundException(); }
$task->setTodoList($list);
$this->repository->save($task);
$this->auditLog->logNewTask($task);
$this->mailer->sendMessage('New thingy!');
return $this->redirect('edit_page');
}
Controller
![Page 28: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/28.jpg)
![Page 29: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/29.jpg)
function addTaskAction($req) {
$task = new Task();
$task->setDescription($req->get('desc'));
$task->setPriority($req->get('priority'));
$list = $this->todoRepo->findById($req->get('id'));
if (!$list) { throw new NotFoundException(); }
$task->setTodoList($list);
$this->repository->save($task);
$this->auditLog->logNewTask($task);
$this->mailer->sendMessage('New thingy!');
return $this->redirect('edit_page');
}
Controller
![Page 30: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/30.jpg)
Anemic ModelHard to Maintain
TestabilitySRP wha?
![Page 31: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/31.jpg)
In Defense Of CRUD.No, seriously.
![Page 32: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/32.jpg)
Low Barrier to Entry.
![Page 33: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/33.jpg)
Easy to follow.If you can keep it in your head.
![Page 34: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/34.jpg)
Sometimes it really is just data entry.(but it usually isn't)(but sometimes it is)
![Page 35: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/35.jpg)
Not entirely a technical issue.
![Page 36: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/36.jpg)
Service Layer
![Page 37: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/37.jpg)
• Service Layer• Service Container• Web Service• Service Oriented Architecture• Domain Service• Stateless Service• Software-as-a-service• Platform-as-a-service• Whatever-as-a-service meme• Delivery Service• Laundry Service
![Page 38: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/38.jpg)
Application Service
![Page 39: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/39.jpg)
![Page 40: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/40.jpg)
Model
Controller
View
![Page 41: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/41.jpg)
Model
Service Layer
Controller
View
![Page 42: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/42.jpg)
Why?
![Page 43: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/43.jpg)
![Page 44: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/44.jpg)
1) Multiple User InterfacesWeb + REST API
+ CLI+ Workers
![Page 45: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/45.jpg)
2) “In between” Logic
![Page 46: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/46.jpg)
3) Decouple from frameworks
![Page 47: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/47.jpg)
Model
Service Layer
Controller
View
![Page 48: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/48.jpg)
Just Build The Stupid Thing
![Page 49: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/49.jpg)
ServiceLayer
![Page 50: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/50.jpg)
function addTaskAction($req) {
$task = new Task();
$task->setDescription($req->get('desc'));
$task->setPriority($req->get('priority'));
$list = $this->todoRepo->findById($req->get('id'));
if (!$list) { throw new NotFoundException(); }
$task->setTodoList($list);
$this->repository->save($task);
$this->auditLog->logNewTask($task);
$this->mailer->sendMessage('New thingy!');
return $this->redirect('edit_page');
}
Controller
![Page 51: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/51.jpg)
class TodoService {
function addTask(TodoList $list, $desc, $priority) {
$task = new Task();
$task->setDescription($desc);
$task->setPriority($priority);
$task->setTodoList($list);
$this->repository->save($task);
$this->auditLog->logNewTask($task);
$this->mailer->sendMessage('New thingy!');
}
}
Service
![Page 52: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/52.jpg)
class TodoService {
function findById($id) {
return $this->repository->findById($id);
}
}
Service
![Page 53: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/53.jpg)
function addTaskAction($req) {
$list = $this->todoService->findById($req->get('id'));
if (!$list) { throw new NotFoundException(); }
$this->todoService->addTask(
$list, $req->get('desc'), $req->get('priority')
);
return $this->redirect('edit_page');
}
Controller
![Page 54: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/54.jpg)
function addTaskAction($req) {
$list = $this->todoService->findById($req->get('id'));
if (!$list) { throw new NotFoundException(); }
$this->todoService->addTask(
$list, $req->get('desc'), $req->get('priority')
);
return $this->redirect('edit_page');
Controller
CLI
function addTaskCommand($id, $desc, $priority) {
$list = $this->todoService->findById($id);
if (!$list) { throw new NotFoundException(); }
$this->todoService->addTask($list, $desc, $priority);
![Page 55: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/55.jpg)
function addTaskAction($req) {
$list = $this->todoService->findById($req->get('id'));
if (!$list) { throw new NotFoundException(); }
$this->todoService->addTask(
$list, $req->get('desc'), $req->get('priority')
);
return $this->redirect('edit_page');
Controller
function addTaskCommand($id, $desc, $priority) {
$list = $this->todoService->findById($id);
if (!$list) { throw new NotFoundException(); }
$this->todoService->addTask($list, $desc, $priority);
CLI
![Page 56: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/56.jpg)
function addTaskAction($req) {
$list = $this->todoService->findById($req->get('id'));
if (!$list) { throw new NotFoundException(); }
$this->todoService->addTask(
$list, $req->get('desc'), $req->get('priority')
);
return $this->redirect('edit_page');
Controller
CLI
function addTaskCommand($id, $desc, $priority) {
$list = $this->todoService->findById($id);
if (!$list) { throw new NotFoundException(); }
$this->todoService->addTask($list, $desc, $priority);
![Page 57: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/57.jpg)
class TodoService {
function findById($id) {
return $this->repository->findById($id);
}
}
Service
![Page 58: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/58.jpg)
class TodoService {
function findById($id) {
$todo = $this->repository->findById($id);
if (!$todo) {
throw new TodoNotFoundException();
}
return $todo;
}
}
Service
not http exception
![Page 59: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/59.jpg)
function addTaskAction($req) {
$list = $this->todoService->findById($req->get('id'));
$this->todoService->addTask(
$list, $req->get('desc'), $req->get('priority')
);
return $this->redirect('edit_page');
Controller
CLI
function addTaskCommand($id, $desc, $priority) {
$list = $this->todoService->findById($id);
$this->todoService->addTask($list, $desc, $priority);
![Page 60: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/60.jpg)
function addTaskAction($req) {
$list = $this->todoService->findById($req->get('id'));
$this->todoService->addTask(
$list, $req->get('desc'), $req->get('priority')
);
return $this->redirect('edit_page');
Controller
CLI
function addTaskCommand($id, $desc, $priority) {
$list = $this->todoService->findById($id);
$this->todoService->addTask($list, $desc, $priority);
![Page 61: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/61.jpg)
function addTaskAction($req) {
$list = $this->todoService->findById($req->get('id'));
$this->todoService->addTask(
$list, $req->get('desc'), $req->get('priority')
);
return $this->redirect('edit_page');
Controller
CLI
function addTaskCommand($name, $desc, $priority) {
$list = $this->todoService->findByName($name);
$this->todoService->addTask($list, $desc, $priority);
![Page 62: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/62.jpg)
![Page 63: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/63.jpg)
function addTaskAction($req) {
$list = $this->todoService->findById($req->get('id'));
$this->todoService->addTask(
$list, $req->get('desc'), $req->get('priority')
);
return $this->redirect('edit_page');
Controller
CLI
function addTaskCommand($name, $desc, $priority) {
$list = $this->todoService->findByName($name);
$this->todoService->addTask($list, $desc, $priority);
![Page 64: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/64.jpg)
function addTaskAction($req) {
$list = $this->todoService->findById($req->get('id'));
$this->todoService->addTask(
$list, $req->get('desc'), $req->get('priority')
);
return $this->redirect('edit_page');
Controller
CLI
function addTaskCommand($name, $desc, $priority) {
$list = $this->todoService->findByName($name);
$this->todoService->addTask($list, $desc, $priority);
![Page 65: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/65.jpg)
function addTaskAction($req) {
$list = $this->todoService->findById($req->get('id'));
$this->todoService->addTask(
$list, $req->get('desc'), $req->get('priority')
);
return $this->redirect('edit_page');
Controller
CLI
function addTaskCommand($name, $desc, $priority) {
$listId = $this->todoService->findIdByName($name);
$this->todoService->addTask($listId, $desc, $priority);
![Page 66: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/66.jpg)
class TodoService {
public function findLatestLists() {
return $this->repository->findLatestLists();
}
}
Service
![Page 67: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/67.jpg)
class TodoService {
public function findLatestLists() {
if ($this->cache->has('latest:lists')) {
return $this->cache->get('latest:lists');
}
$results = $this->repository->findLatestLists();
$this->cache->set('latest:lists', $results);
return $results;
}
}
Service
![Page 68: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/68.jpg)
Indirect Advantages
![Page 69: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/69.jpg)
Readability
![Page 70: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/70.jpg)
Interface Protection
![Page 71: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/71.jpg)
Discoverability
![Page 72: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/72.jpg)
class TodoService {
function findById($id);
function addTask($todo, $desc, $priority);
function prance();
}
Service
![Page 73: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/73.jpg)
Mission Accomplished
![Page 74: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/74.jpg)
class TodoList {
function setName($name);
function getName();
function setStatus($status);
function getStatus();
function setTasks($tasks);
function getTasks();
}
Model
![Page 75: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/75.jpg)
Dumb as a box of rocks.
![Page 76: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/76.jpg)
class TodoList {
function setName($name);
function getName();
function setStatus($status);
function getStatus();
function setTasks($tasks);
function getTasks();
}
Model
Where's mah logic?
![Page 77: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/77.jpg)
class TodoListService {
function addTask(TodoList $list, $desc, $priority) {
$task = new Task();
$task->setDescription($desc);
$task->setPriority($priority);
$task->setTodoList($list);
$this->repository->save($task);
$this->auditLog->logNewTask($task);
$this->mailer->sendMessage('New thingy!');
}
}
Service
![Page 78: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/78.jpg)
![Page 79: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/79.jpg)
“Organizes business logic by procedures where each procedure handles a single
request from the presentation.”-Fowler
![Page 80: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/80.jpg)
Transaction Scripts
![Page 81: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/81.jpg)
Simple
![Page 82: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/82.jpg)
More flexibleThan CRUD, at least
![Page 83: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/83.jpg)
Don't scale quite as well
![Page 84: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/84.jpg)
What does belong in a service layer?
![Page 85: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/85.jpg)
class TodoListService {
function addTask(TodoList $list, $desc, $priority) {
$task = new Task();
$task->setDescription($desc);
$task->setPriority($priority);
$task->setTodoList($list);
$this->repository->save($task);
$this->auditLog->logNewTask($task);
$this->mailer->sendMessage('New thingy!');
}
}
Service
![Page 86: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/86.jpg)
Orchestration
![Page 87: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/87.jpg)
TransactionsSecurity
NotificationsBulk operations
![Page 88: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/88.jpg)
Facade
![Page 89: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/89.jpg)
Fat Model, Skinny Controller
![Page 90: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/90.jpg)
Fat Model, Skinny Service Layer
![Page 91: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/91.jpg)
(re)Thinking
![Page 92: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/92.jpg)
addTask()
findById()
findLatestLists()
Service
writereadread
![Page 93: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/93.jpg)
Remodeling our Reading
by
Refactoring our Repository
Redux
![Page 94: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/94.jpg)
class TodoService {
function findById($id) {
$todo = $this->repository->findById($id);
if (!$todo) {
throw new TodoNotFoundException();
}
return $todo;
}
}
Service
![Page 95: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/95.jpg)
interface TodoRepository {
public function findById($id);
public function findLatestLists();
}
Repository
![Page 96: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/96.jpg)
class TodoDbRepository implements TodoRepository {
public function findById($id) {
$todo = $this->db->select(...);
if (!$todo) {
throw new TodoNotFoundException();
}
return $todo;
}
}
Repository
![Page 97: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/97.jpg)
class TodoDbRepository implements TodoRepository {
public function findById($id) {
$todo = $this->db->select(...);
if (!$todo) {
throw new TodoNotFoundException();
}
return $todo;
}
}
Repository
raw db connection
![Page 98: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/98.jpg)
class TodoDbRepository implements TodoRepository {
public function findById($id) {
$todo = $this->repository->find($id);
if (!$todo) {
throw new TodoNotFoundException();
}
return $todo;
}
}
Repository
FIXED
![Page 99: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/99.jpg)
interface TodoRepository {
public function findById($id);
public function findLatestLists();
}
Repository
![Page 100: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/100.jpg)
interface EntityRepository {
public function createQueryBuilder($alias);
public function createResultSetMappingBuilder($alias);
public function createNamedQuery($queryName);
public function createNativeNamedQuery($queryName);
public function clear();
public function find($id, $lockMode, $lockVersion);
public function findAll();
public function findBy($criteria, $orderBy, $limit, $offset);
public function findOneBy($criteria, $orderBy);
public function __call($method, $arguments);
public function getClassName();
public function matching(Criteria $criteria);
}
Repository
![Page 101: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/101.jpg)
interface TodoRepository {
public function findById($id);
public function findLatestLists();
}
Repository
![Page 102: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/102.jpg)
class TodoService {
function findById($id) {
$todo = $this->repository->findById($id);
if (!$todo) {
throw new TodoNotFoundException();
}
return $todo;
}
}
Service
![Page 103: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/103.jpg)
class TodoService {
function findById($id) {
return $this->repository->findById($id);
}
}
Service
![Page 104: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/104.jpg)
class TodoService {
public function findLatestLists() {
if ($this->cache->has('latest:lists')) {
return $this->cache->get('latest:lists');
}
$results = $this->repository->findLatestLists();
$this->cache->set('latest:lists', $results);
return $results;
}
}
Service
![Page 105: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/105.jpg)
class TodoDbRepository implements TodoRepository {
public function findLatestLists() {
if ($this->cache->has('latest:lists')) {
return $this->cache->get('latest:lists');
}
$results = $this->repository->query(...);
$this->cache->set('latest:lists', $results);
return $results;
}
}
Repository
![Page 106: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/106.jpg)
class CachingTodoRepository implements TodoRepository {
public function findLatestLists() {
if ($this->cache->has('latest:lists')) {
return $this->cache->get('latest:lists');
}
$results = $this->innerRepository->findLatestLists();
$this->cache->set('latest:lists', $results);
return $results;
}
}
Repository Decorator Decorator object
TodoDbRepository
![Page 107: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/107.jpg)
new TodoService(
new CachingTodoRepository(
new TodoDbRepository(
$entityManager->getRepository('TodoList')
)
)
)
DI Layer
![Page 108: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/108.jpg)
The Inverse Biggie Law
![Page 109: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/109.jpg)
Mo' classesMo' decoupling and reduced overall design issues
![Page 110: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/110.jpg)
Too many finder methods?
![Page 111: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/111.jpg)
$this->todoService->matching(array(
new ListIsClosedCriteria(),
new HighPriorityCriteria()
));
Controller
![Page 112: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/112.jpg)
Doctrine\Criteria
![Page 113: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/113.jpg)
Interlude: Services here...
...services there...
...services everywhere!
![Page 114: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/114.jpg)
Task
TaskService
TodoList
TodoListService
Tag
TagService
TaskRepository TodoListRepository TagRepository
![Page 115: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/115.jpg)
![Page 116: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/116.jpg)
![Page 117: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/117.jpg)
Task
TaskService
TodoList
TodoListService
Tag
TagService
TaskRepository TodoListRepository TagRepository
![Page 118: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/118.jpg)
![Page 119: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/119.jpg)
Task
TodoList
TodoService
Tag
![Page 120: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/120.jpg)
Task
TodoList
TodoService
Tag
User
UserService
![Page 121: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/121.jpg)
![Page 122: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/122.jpg)
Task
TodoList
TodoService
Tag
User
UserService
![Page 123: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/123.jpg)
class TodoListService {
public function findByUser(User $user) {
return $this->repository->findByUser($user);
}
}
Service
![Page 124: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/124.jpg)
class TodoListService {
public function findByUser(UserId $userId) {
return $this->repository->findByUser($userId);
}
}
Service
![Page 125: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/125.jpg)
Task
TodoList
TodoService
Tag
User
UserService
Interfaces!
![Page 126: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/126.jpg)
Services aren't only for entities
![Page 127: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/127.jpg)
Scale can differ wildly
![Page 128: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/128.jpg)
PrintingService
![Page 129: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/129.jpg)
Quality of Implementation
![Page 130: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/130.jpg)
(re)Modeling our Writing
![Page 131: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/131.jpg)
class TodoListService {
function addTask(TodoList $list, $desc, $priority) {
$task = new Task();
$task->setDescription($desc);
$task->setPriority($priority);
$task->setTodoList($list);
$this->repository->save($task);
$this->auditLog->logNewTask($task);
$this->mailer->sendMessage('New thingy!');
}
}
Service
![Page 132: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/132.jpg)
class TodoList {
function addTask(Task $task) {
$this->tasks[] = $task;
}
}
Model
![Page 133: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/133.jpg)
class TodoList {
function addTask($desc, $priority) {
$task = new Task();
$task->setDescription($desc);
$task->setPriority($priority);
$this->tasks[] = $task;
}
}
Model
![Page 134: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/134.jpg)
class TodoList {
function addTask($desc, $priority) {
$task = new Task($desc, $priority);
$this->tasks[] = $task;
}
}
Model
![Page 135: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/135.jpg)
class TodoList {
function addTask($desc, $priority) {
$task = new Task($desc, $priority, $this);
$this->tasks[] = $task;
}
}
Model
ORM allowance
![Page 136: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/136.jpg)
class TodoList {
function addTask($desc, $priority) {
$task = new Task($desc, $priority);
$this->tasks[] = $task;
}
}
Model
![Page 137: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/137.jpg)
class TodoListService {
function addTask(TodoList $list, $desc, $priority) {
$list->addTask($desc, $priority);
$this->repository->save($list);
$this->auditLog->logNewTask($task);
$this->mailer->sendMessage('New thingy!');
}
}
Service
![Page 138: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/138.jpg)
class TodoList {
function addTask($desc, $priority) {
$task = new Task($desc, $priority);
$this->tasks[] = $task;
}
}
Model
![Page 139: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/139.jpg)
Model
class TodoList {
function addTask($desc, $priority) {
$task = new Task($desc, $priority);
$this->tasks[] = $task;
if (count($this->tasks) > 10) {
$this->status = static::UNREALISTIC;
}
}
}
![Page 140: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/140.jpg)
Meaningful Tests
![Page 141: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/141.jpg)
Working Together
![Page 142: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/142.jpg)
class TodoListService {
function addTask(TodoList $list, $desc, $priority) {
$list->addTask($desc, $priority);
$this->repository->save($list);
$this->auditLog->logNewTask($task);
$this->mailer->sendMessage('New thingy!');
}
}
Service
![Page 143: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/143.jpg)
Model
class TodoList {
function addTask($desc, $priority) {
$task = new Task($desc, $priority);
$this->tasks[] = $task;
if (count($this->tasks) > 10) {
$this->status = static::UNREALISTIC;
}
}
}
![Page 144: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/144.jpg)
class TodoListService {
function addTask(TodoList $list, $desc, $priority) {
$list->addTask($desc, $priority);
$this->repository->save($list);
$this->auditLog->logNewTask($task);
$this->mailer->sendMessage('New thingy!');
}
}
Service
![Page 145: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/145.jpg)
class TodoListService {
function addTask(TodoList $list, $desc, $priority) {
$list->addTask($desc, $priority);
$this->repository->save($list);
$this->auditLog->logNewTask($task);
$this->mailer->sendMessage('New thingy!');
if (count($this->tasks) > 10) {
$this->auditLog->logTooAmbitious($task);
$this->mailer->sendMessage('Too unrealistic');
}
}
}
Service
![Page 146: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/146.jpg)
class TodoListService {
function addTask(TodoList $list, $desc, $priority) {
$list->addTask($desc, $priority);
$this->repository->save($list);
$this->auditLog->logNewTask($task);
$this->mailer->sendMessage('New thingy!');
if (count($this->tasks) > 10) {
$this->auditLog->logTooAmbitious($task);
$this->mailer->sendMessage('Too unrealistic');
}
}
}
Service
![Page 147: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/147.jpg)
PrintingService
TodoService
![Page 148: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/148.jpg)
Something new...
![Page 149: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/149.jpg)
Something better...
![Page 150: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/150.jpg)
Domain Events
![Page 151: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/151.jpg)
Common Pattern
![Page 152: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/152.jpg)
Observer
![Page 153: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/153.jpg)
New usage
![Page 154: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/154.jpg)
Model
function addTask($desc, $priority) {
$task = new Task($desc, $priority, $this);
$this->tasks[] = $task;
$this->raise(
new TaskAddedEvent($this->id, $desc, $priority)
);
if (count($this->tasks) > 10) {
$this->status = static::UNREALISTIC;
}
}
![Page 155: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/155.jpg)
Event
class TaskAddedEvent {
protected $description;
protected $priority;
function __construct($desc, $priority) {
$this->description = $desc;
$this->priority = $priority;
}
}
![Page 156: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/156.jpg)
Model
function addTask($desc, $priority) {
$task = new Task($desc, $priority, $this);
$this->tasks[] = $task;
$this->raise(
new TaskAddedEvent($this->id, $desc, $priority)
);
if (count($this->tasks) > 10) {
$this->status = static::UNREALISTIC;
}
}
![Page 157: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/157.jpg)
Model
class TodoList {
protected $pendingEvents = array();
protected function raise($event) {
$this->pendingEvents[] = $event;
}
public function releaseEvents() {
$events = $this->pendingEvents;
$this->pendingEvents = array();
return $events;
}
}
Excellent Trait
![Page 158: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/158.jpg)
No dispatcher
![Page 159: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/159.jpg)
class TodoListService {
function addTask(TodoList $list, $desc, $priority) {
$list->addTask($desc, $priority);
$this->repository->save($list);
$this->auditLog->logNewTask($task);
$this->mailer->sendMessage('New thingy!');
}
}
Service
![Page 160: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/160.jpg)
class TodoListService {
function addTask(TodoList $list, $desc, $priority) {
$list->addTask($desc, $priority);
$this->repository->save($list);
}
}
Service
![Page 161: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/161.jpg)
class TodoListService {
function addTask(TodoList $list, $desc, $priority) {
$list->addTask($desc, $priority);
$this->repository->save($list);
$events = $list->releaseEvents();
$this->eventDispatcher->dispatch($events);
}
}
Service
![Page 162: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/162.jpg)
Event Listeners
class EmailListener {
function onTaskAdded($event) {
$taskDesc = $event->getDescription();
$this->mailer->sendMessage('New thingy: '.$taskDesc);
}
function onUserRegistered($event) {
$this->mailer->sendMessage('welcome sucka!');
}
}
![Page 163: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/163.jpg)
Model
function addTask($desc, $priority) {
$task = new Task($desc, $priority, $this);
$this->tasks[] = $task;
$this->raise(
new TaskAddedEvent($this->id, $desc, $priority)
);
if (count($this->tasks) > 10) {
$this->status = static::UNREALISTIC;
}
}
![Page 164: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/164.jpg)
Model
function addTask($desc, $priority) {
$task = new Task($desc, $priority, $this);
$this->tasks[] = $task;
$this->raise(
new TaskAddedEvent($this->id, $desc, $priority)
);
if (count($this->tasks) > 10) {
$this->status = static::UNREALISTIC;
$this->raise(new WasTooAmbitiousEvent($this->id));
}
}
![Page 165: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/165.jpg)
Nice things:
![Page 166: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/166.jpg)
Model
function addTask($desc, $priority) {
$task = new Task($desc, $priority, $this);
$this->tasks[] = $task;
$this->raise(
new TaskAddedEvent($this->id, $desc, $priority)
);
if (count($this->tasks) > 10) {
$this->status = static::UNREALISTIC;
$this->raise(new WasTooAmbitiousEvent($this->id));
}
}
Logic is here!
![Page 167: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/167.jpg)
class TodoListService {
protected $dependency1;
protected $dependency2;
protected $dependency3;
protected $dependency4;
protected $dependency5;
protected $dependency6;
}
Service
Big ball of mud
in the making
![Page 168: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/168.jpg)
Event Listeners
class EmailListener {
function onTaskAdded($event) {
$taskName = $event->task->getName();
$this->mailer->sendMessage('New thingy: '.$taskName);
}
function onUserRegistered($event) {
$this->mailer->sendMessage('welcome sucka!');
}
} Thin. Easy to test
![Page 169: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/169.jpg)
PrintingService
TodoService
Serialize & Send,
Sucka!
![Page 170: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/170.jpg)
Model
function addTask($desc, $priority) {
$task = new Task($desc, $priority, $this);
$this->tasks[] = $task;
$this->raise(
new TaskAddedEvent($this->id, $desc, $priority)
);
if (count($this->tasks) > 10) {
$this->status = static::UNREALISTIC;
}
}
![Page 171: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/171.jpg)
Less nice things.
![Page 172: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/172.jpg)
Humans hate debugging events.
Dev Logging.Debug comma
nds.
![Page 173: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/173.jpg)
Model
Service Layer
Controller
View
![Page 174: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/174.jpg)
Model
Service Layer
Controller
View
![Page 175: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/175.jpg)
Model
Service Layer
Controller
View
![Page 176: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/176.jpg)
Consuming Application Services
![Page 177: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/177.jpg)
function addTaskAction($req) {
$list = $this->todoService->findById($req->get('id'));
$this->todoService->addTask(
$list, $req->get('desc'), $req->get('priority')
);
return $this->redirect('edit_page');
}
Controller
![Page 178: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/178.jpg)
function addTaskAction($req) {
$list = $this->todoService->findById($req->get('id'));
$this->todoService->addTask(
$list, $req->get('desc'), $req->get('priority')
);
return $this->redirect('edit_page');
}
Controller
![Page 179: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/179.jpg)
function addTaskAction($req) {
$list = $this->todoService->findById($req->get('id'));
$list->addTask($req->get('desc'), $req->get('priority'));
return $this->redirect('edit_page');
}
Controller
![Page 180: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/180.jpg)
function addTaskAction($req) {
$list = $this->todoService->findById($req->get('id'));
$list->addTask($req->get('desc'), $req->get('priority'));
$list->rename('blah');
return $this->redirect('edit_page');
}
Controller
![Page 181: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/181.jpg)
function addTaskAction($req) {
$list = $this->todoService->findById($req->get('id'));
$list->addTask($req->get('desc'), $req->get('priority'));
$list->rename('blah');
$this->todoService->addTask(...);
return $this->redirect('edit_page');
}
Controller
![Page 182: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/182.jpg)
![Page 183: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/183.jpg)
Model
Service Layer
Controller
View
![Page 184: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/184.jpg)
Model
Service Layer
Controller
View
![Page 185: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/185.jpg)
Model
Service Layer
Controller
View
![Page 186: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/186.jpg)
![Page 187: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/187.jpg)
View Models
![Page 188: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/188.jpg)
PHP version, not MVVM.
![Page 189: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/189.jpg)
class TodoService {
function findById($id) {
$todoList = $this->repository->findById($id);
return $todoList;
}
}
Service
![Page 190: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/190.jpg)
class TodoService {
function findById($id) {
$todoList = $this->repository->findById($id);
return new TodoDTO($todoList);
}
}
Service
![Page 191: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/191.jpg)
class TodoDTO {
public function getName();
public function getStatus();
public function getMostRecentTask();
}
TodoDTO
![Page 192: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/192.jpg)
![Page 193: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/193.jpg)
class TodoService {
function generateReport() {
$data = $this->repository->performSomeCrazyQuery();
return new AnnualGoalReport($data);
}
}
Service
![Page 194: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/194.jpg)
Ain't rocket science.
![Page 195: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/195.jpg)
Reverse it: DTOs not for output...
![Page 196: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/196.jpg)
...but for input.
![Page 197: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/197.jpg)
Going Commando
![Page 198: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/198.jpg)
![Page 199: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/199.jpg)
![Page 200: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/200.jpg)
Command
class AddTaskCommand {
public $description;
public $priority;
public $todoListId;
}
![Page 201: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/201.jpg)
function addTaskAction($req) {
$command = new AddTaskCommand();
$command->description = $req->get('description');
$command->priority = $req->get('priority');
$command->todoListId = $req->get('todo_id');
$this->todoService->execute($command);
return $this->redirect('edit_page');
}
}
Controller
![Page 202: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/202.jpg)
ServiceController Handler Bar
Handler Baz
Handler Foo
![Page 203: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/203.jpg)
ServiceController
Handler Baz
![Page 204: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/204.jpg)
class TodoListService {
}
Service
![Page 205: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/205.jpg)
class TodoListService {
function execute($command) {
}
}
Service
![Page 206: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/206.jpg)
class TodoListService {
function execute($command) {
get_class($command);
}
}
Service
![Page 207: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/207.jpg)
class TodoListService {
function execute($command) {
$command->getName();
}
}
Service
![Page 208: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/208.jpg)
class TodoListService {
function execute($command) {
$command->execute();
}
}
Service
![Page 209: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/209.jpg)
class TodoListService {
function execute($command) {
}
}
Service
![Page 210: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/210.jpg)
What goes in a handler?
![Page 211: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/211.jpg)
class TodoListHandler {
function handleAddTask($cmd) {
$list = $this->repository->findById($cmd->todoListId);
$list->addTask($cmd->description, $cmd->priority);
}
function handleCompleteTask($command)
function handleRemoveTask($command)
}
Handler
![Page 212: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/212.jpg)
class TodoListService {
function execute($command) {
}
}
Service
![Page 213: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/213.jpg)
class CommandBus {
function execute($command) {
}
}
Service
![Page 214: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/214.jpg)
class MyCommandBus implements CommandBus {
function execute($command) {
}
}
Service
![Page 215: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/215.jpg)
class ValidatingCommandBus implements CommandBus {
function execute($command) {
if (!$this->validator->isValid($command)) {
throw new InvalidCommandException();
}
$this->innerCommandBus->execute($command);
}
}
Service
![Page 216: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/216.jpg)
Command
class AddTaskCommand {
public $description;
public $priority;
public $todoListId;
}
![Page 217: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/217.jpg)
Command
use Symfony\Component\Validator\Constraints as Assert;
class AddTaskCommand {
/** @Assert\Length(max="50") */
public $description;
public $priority;
public $todoListId;
}
![Page 218: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/218.jpg)
LoggingTransactions
Event Dispatching
![Page 219: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/219.jpg)
Fewer Dependencies per class.Simple layers.Easy to test.
![Page 220: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/220.jpg)
View Models + Commands
![Page 221: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/221.jpg)
Model
Service Layer
Controller
View
ViewModelsCommands
![Page 222: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/222.jpg)
CRUD for the framework.Domain Model for the chewy center.
formstemplatesvalidators
tough logicsemanticstesting
![Page 223: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/223.jpg)
Diverge Further
![Page 224: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/224.jpg)
CQRS
![Page 225: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/225.jpg)
On the surface, it looks the same.
![Page 226: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/226.jpg)
function addTaskAction($req) {
$command = new AddTaskCommand();
$command->description = $req->get('description');
$command->priority = $req->get('priority');
$command->todoListId = $req->get('todo_id');
$this->commandBus->execute($command);
return $this->redirect('edit_page');
}
}
Controller
![Page 227: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/227.jpg)
CQS
![Page 228: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/228.jpg)
Commands = Change DataQueries = Read Data
![Page 229: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/229.jpg)
CQRS
![Page 230: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/230.jpg)
Model
class TodoList {
function rename($name);
function addTask($desc, $priority);
function getName();
function getTasks();
}
![Page 231: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/231.jpg)
Two Models
![Page 232: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/232.jpg)
Write Model
class TodoListModel {
function rename($name);
function addTask($desc, $priority);
}
class TodoListView {
function getName();
function getTasks();
}
Read Model
![Page 233: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/233.jpg)
![Page 234: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/234.jpg)
Model
class TodoList {
function rename($name);
function addTask($desc, $priority);
function getName();
function getTasks();
function getParticipatingUsers();
}
![Page 235: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/235.jpg)
Write Model
class TodoListModel {
function rename($name);
function addTask($desc, $priority);
}
class TodoListView {
function getName();
function getTasks();
function getParticipatingUsers();
}
Read Model
![Page 236: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/236.jpg)
Write Model
class TodoListModel {
function rename($name);
function addTask($desc, $priority);
}
class TodoListView {
function getName();
function getTasks();
function getParticipatingUsers();
}
Read Model
ORM entity1 Model
SQL queryN Models
![Page 237: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/237.jpg)
Read and Write are two different systems.
![Page 238: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/238.jpg)
User and Shopping Cart?
![Page 239: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/239.jpg)
Same kind of split.
![Page 240: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/240.jpg)
Surrounding classes?
![Page 241: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/241.jpg)
A lot of it looks the same.
![Page 242: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/242.jpg)
class TodoListHandler {
function handleAddTask($cmd) {
$list = $this->repository->findById($cmd->todoListId);
$list->addTask($cmd->description, $cmd->priority);
}
}
Handler
![Page 243: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/243.jpg)
class TodoListService {
public function findByUser(User $user) {
return $this->repository->findByUser($user);
}
}
Service
![Page 244: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/244.jpg)
class TodoListService {
public function findByUser(User $user) {
return $this->repository->findByUser($user);
}
}
Service
class TodoListHandler {
function handleAddTask($cmd) {
$list = $this->repository->findById($cmd->todoListId);
$list->addTask($cmd->description, $cmd->priority);
}
}
Handler
![Page 245: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/245.jpg)
![Page 246: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/246.jpg)
$todoList = new TodoList();
$this->repository->save($todoList);
$todoList->getId();
Controller
![Page 247: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/247.jpg)
$command = new CreateTodoCommand(UUID::create());
$commandBus->execute($command);
$command->uuid;
Controller
![Page 248: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/248.jpg)
Zoom Out
![Page 249: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/249.jpg)
Martin Fowler waz here
![Page 250: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/250.jpg)
![Page 251: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/251.jpg)
![Page 252: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/252.jpg)
![Page 253: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/253.jpg)
![Page 254: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/254.jpg)
Domain events
![Page 255: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/255.jpg)
DB Views
![Page 256: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/256.jpg)
BigHonkingQueue
![Page 257: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/257.jpg)
github.com/beberlei/litecqrs-php/github.com/qandidate-labs/broadway
github.com/gregoryyoung/m-r
![Page 258: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/258.jpg)
Pros & Cons
![Page 259: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/259.jpg)
Big mental leap.Usually more LOC.
Not for every domain.Can be mixed.
![Page 260: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/260.jpg)
Easy to Scale.Bears Complexity.Async Operations.
Event Sourcing.
![Page 261: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/261.jpg)
Event Sourcing?
![Page 262: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/262.jpg)
CQRS+
Event Sourcing
![Page 263: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/263.jpg)
Instead of storing the current state in the db...
![Page 264: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/264.jpg)
...store the domain events?
![Page 265: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/265.jpg)
SnapshotsDebuggingAudit Log
Business IntelligenceOnline/Offline users
Retroactively Fix Bugs
![Page 266: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/266.jpg)
Google it.Or ask me afterwards.
![Page 267: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/267.jpg)
Epilogue
![Page 268: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/268.jpg)
"A foolish consistency is the hobgoblin of little minds."
- Ralph Waldo Emerson
![Page 269: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/269.jpg)
Strong opinions, weakly held.
![Page 270: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/270.jpg)
Strong techniques, weakly held.
![Page 271: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/271.jpg)
PHP 3
![Page 272: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/272.jpg)
PHP 4 -5
![Page 273: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/273.jpg)
PHP 5.3+
![Page 274: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/274.jpg)
PHP 7
![Page 275: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/275.jpg)
Might seem crazy.
![Page 276: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/276.jpg)
Bang for the buck.
![Page 277: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/277.jpg)
People ARE doing this.
![Page 278: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/278.jpg)
It IS working for them.
![Page 279: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/279.jpg)
You can too.
![Page 280: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/280.jpg)
Questions?
![Page 281: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/281.jpg)
Further Reading• codebetter.com/gregyoung• martinfowler.com/tags/domain driven design.html• shawnmc.cool/domain-driven-design• whitewashing.de• verraes.net
![Page 282: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/282.jpg)
Thanks To:
• Warnar Boekkooi @boekkooi
• Daan van Renterghem @DRvanR• Matthijs van den Bos @matthijsvandenb
![Page 283: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/283.jpg)
Image Credits• http://www.flickr.com/photos/calgaryreviews/6427412605/sizes/l/
• http://msnbcmedia.msn.com/j/MSNBC/Components/Slideshows/_production/twisp_090511_/twisp_090511_02.ss_full.jpg
• http://shotthroughawindow.wordpress.com/2011/07/22/hp7b/
• http://www.sxc.hu/photo/605471
• http://martinfowler.com/bliki/images/cqrs/cqrs.png
• http://www.flickr.com/photos/83346641@N00/5578975430/in/photolist-9uZH2y-8rTZL1-dixjR-ffBPiv-8SbK8K-ffS4md-6UeEGP
• http://www.flickr.com/photos/lac-bac/7195938394/sizes/o/
• http://tdzdaily.org/wp-content/uploads/2013/03/Dumb-and-Dumber.png
• http://upload.wikimedia.org/wikipedia/commons/1/17/Charlton_Heston_in_The_Ten_Commandments_film_trailer.jpg
• http://commons.wikimedia.org/wiki/File:Trench_construction_diagram_1914.png
• http://www.flickr.com/photos/jeffreyww/4747314852/sizes/l/
• http://www.flickr.com/photos/jdhancock/3540861791/sizes/l/
• http://www.flickr.com/photos/superfantastic/50088733/sizes/l
![Page 284: Models and Service Layers, Hemoglobin and Hobgoblins](https://reader033.vdocuments.us/reader033/viewer/2022052522/554dc5dfb4c905bd488b50c8/html5/thumbnails/284.jpg)
joind.in/12101
@rosstuck
Ross Tuckrosstuck.com