SlideShare ist ein Scribd-Unternehmen logo
1 von 118
Downloaden Sie, um offline zu lesen
modernizando a arquitertura
de sua aplicação
Antonio Spinelli @tonicospinelli
tornando o seu código mais robusto e escalável
problema simples
vs
soluções complexas
soluções simples
o objetivo não muda:
resolver problemas para o negócio!
entenda o problema
agregue valor ao negócio
agilidade não é "sobrinhagem"
desenvolvedor
desenvolvedor
automatize tarefas repetidas
peça e faça code review
leia código
Lista de Desejos para Produtos
Eu como um usuário convidado, quero adicionar um produto
indisponível dentro da minha lista de desejos, de modo que eu
receba uma notificação quando este estiver disponível.
Objetivo
reposição de estoque inteligente e
estreitar relacionamento com cliente
user story
php puro
adicionando um item na lista de desejos
php puro
// public/wishlist.php
// ...
if (isset($_POST['submit']) && isValid($_POST['wish_item'])) {
}
// ...
php puro
// public/wishlist.php
// ...
if (isset($_POST['submit']) && isValid($_POST['wish_item'])) {
$wishItem = createWishListItem($_POST['wish_item']);
}
// ...
php puro
// public/wishlist.php
// ...
if (isset($_POST['submit']) && isValid($_POST['wish_item'])) {
$wishItem = createWishListItem($_POST['wish_item']);
$stm = $db->prepare('insert new entry (email, product_id)');
$stm->execute([$wishItem['email'], $wishItem['product_id']]);
$successmsg = 'Product was added at wish list successfully!';
}
// ...
php puro
// public/wishlist.php
// ...
if (isset($_POST['submit']) && isValid($_POST['wish_item'])) {
$wishItem = createWishListItem($_POST['wish_item']);
$db->beginTransaction();
try {
$stm = $db->prepare('insert new entry (email, product_id)');
$stm->execute([$wishItem['email'], $wishItem['product_id']]);
$successmsg = 'Product was added at wish list successfully!';
$db->commit();
} catch (Exception $e) {
$db->rollBack();
$errormsg = 'Product could not be added at wishlist! :(';
}
}
// ..
php puro
// public/wishlist.php
// ...
<table>
<?php foreach ($wishlist as $item): ?>
<tr>
<td><?php echo $item['id']; ?> </td>
<td><?php echo $item['product_name']; ?> </td>
<?php if ($item['product_stock'] == 0): ?>
<td>Not Available</td>
<?php else: ?>
<td>Available</td>
<?php endif; ?>
<td>
<?php echo removeUrl($item['id'], ['email' => $email]); ?>
</td>
</tr>
<?php endforeach; ?>
</table>
// ...
php puro
notificar usuário quando
o item estiver disponível
php puro
// cli/wishlist_notify.php
// ...
$query = "find all available products from wishlist";
$stm = $db->prepare($query);
$stm->execute();
$wishlists = $stm->fetchAll(PDO::FETCH_ASSOC);
php puro
// cli/wishlist_notify.php
// ...
$query = "find all available products from wishlist";
$stm = $db->prepare($query);
$stm->execute();
$wishlists = $stm->fetchAll(PDO::FETCH_ASSOC);
foreach ($wishlists as $item) {
mail(
$item['email'],
"{$item['product_name']} available",
$mailBody
);
$stm = $db->prepare("define new status for id = ?");
$stm->execute([$item['id']]);
}
php puro
pronto!
funciona!
php puro
quais problemas temos com este código?
atenção
organização pobre
sem verificação de erros
dificuldade para reutilizar o código
php puro
php estruturado
isolando a apresentação
php estruturado
// templates/wishlist/list.php
<table>
<?php foreach ($wishlist as $item): ?>
<tr>
<td><?php echo $item['id']; ?> </td>
<td><?php echo $item['product_name']; ?> </td>
<?php if ($item['product_stock'] == 0): ?>
<td>Not Available</td>
<?php else: ?>
<td>Available</td>
<?php endif; ?>
<td>
<?php echo removeUrl($item['id'], ['email' => $email]); ?>
</td>
</tr>
<?php endforeach; ?>
</table>
php estruturado
isolando regra de negócio
php estruturado
// lib/models/wishlist.php
function addItemIntoWishlist(array $data);
function createWishListItem(array $data);
function findAllWishlistsToNotify();
function findAllWishProducts($email);
function isValidWishList(array $data);
function removeWishItem($id);
function wishlistNotified($id);
php estruturado
interagindo
regras de negócio com a apresentação
php estruturado
// public/wishlist.php
require_once __DIR__ . '/../lib/dbconn.php';
require_once __DIR__ . '/../lib/functions.php';
require_once __DIR__ . '/../lib/wishlist.php';
if (isset($_POST['submit']) && isValidWishList($_POST['wish_item'])) {
$wishItem = createWishListItem($_POST['wish_item']);
$db->beginTransaction();
try {
$stm = $db->prepare('insert new entry (email, product_id)');
$stm->execute([$wishItem['email'], $wishItem['product_id']]);
$db->commit();
$successmsg = 'Product was added at wish list successfully!';
} catch (Exception $e) {
$db->rollBack();
$errormsg = 'Product could not be added at wishlist! :(';
}
}
// ...
php estruturado
// public/wishlist.php
require_once __DIR__ . '/../lib/dbconn.php';
require_once __DIR__ . '/../lib/functions.php';
require_once __DIR__ . '/../lib/wishlist.php';
if (isset($_POST['submit']) && isValidWishList($_POST['wish_item'])) {
$wishItem = createWishListItem($_POST['wish_item']);
$db->beginTransaction();
try {
$stm = $db->prepare('insert new entry (email, product_id)');
$stm->execute([$wishItem['email'], $wishItem['product_id']]);
$db->commit();
$successmsg = 'Product was added at wish list successfully!';
} catch (Exception $e) {
$db->rollBack();
$errormsg = 'Product could not be added at wishlist! :(';
}
}
// ...
structured php
// public/wishlist.php
require_once __DIR__ . '/../lib/dbconn.php';
require_once __DIR__ . '/../lib/functions.php';
require_once __DIR__ . '/../lib/wishlist.php';
if (isset($_POST['submit']) && isValidWishList($_POST['wish_item'])) {
$wishItem = createWishListItem($_POST['wish_item']);
if (addItemIntoWishlist($wishItem)) {
$successmsg = 'Product was added at wish list successfully!';
} else {
$errormsg = 'Product could not be added at wishlist! :(';
}
}
// ...
php estruturado
// public/wishlist.php
require_once __DIR__ . '/../lib/dbconn.php';
require_once __DIR__ . '/../lib/functions.php';
require_once __DIR__ . '/../lib/wishlist.php';
if (isset($_POST['submit']) && isValidWishList($_POST['wish_item'])) {
$wishItem = createWishListItem($_POST['wish_item']);
if (addItemIntoWishlist($wishItem)) {
$successmsg = 'Product was added at wish list successfully!';
} else {
$errormsg = 'Product could not be added at wishlist! :(';
}
}
$wishlist = findAllWishProducts($_GET['email']);
include __DIR__ . '/../templates/wishlists/list.php';
php estruturado
isolando layout
php estruturado
// template/layout.php
<!DOCTYPE html>
<html>
<head>
<title><?php echo $title ?></title>
</head>
<body>
<?php echo $content ?>
</body>
</html>
layout padrão
php estruturado
// template/wishlist/list.php
<?php $title = 'My Wish List' ?>
define o título da página
php estruturado
// template/wishlist/list.php
<?php $title = 'My Wish List' ?>
<?php ob_start() ?>
<table>
<tbody>
<?php foreach ($wishlist as $wish): ?>
<tr><!-- print all columns --></tr>
<?php endforeach; ?>
</tbody>
</table>
<?php $content = ob_get_clean() ?>
define o conteúdo da página
php estruturado
// template/wishlist/list.php
<?php $title = 'My Wish List' ?>
<?php ob_start() ?>
<table>
<tbody>
<?php foreach ($wishlist as $wish): ?>
<tr><!-- print all columns --></tr>
<?php endforeach; ?>
</tbody>
</table>
<?php $content = ob_get_clean() ?>
<?php include __DIR__ . '/../layout.php' ?>
extendendo layout padrão
php estruturado
front controller
php estruturado
sem um front controller
GET /wishlist.php?email=email@test.com
com index.php como um front controller
GET /index.php/wishlist/email@test.com
com regras de sobrescrita no servidor web
GET /wishlist/email@test.com
php estruturado
// public/index.php
// route the request internally
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$method = $_SERVER['REQUEST_METHOD'];
if (preg_match('/wishlist/(.*)$', $uri, $matches) && $method == 'GET') {
wishlistListAction($matches[1]);
} elseif ('/index.php/wishlist/add' === $uri && $method == 'POST') {
wishlistAddAction($_GET['email'], $_POST);
} else {
header('HTTP/1.1 404 Not Found');
echo '<html><body><h1>Page Not Found</h1></body></html>';
}
php estruturado
// public/index.php
// route the request internally
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$method = $_SERVER['REQUEST_METHOD'];
if (preg_match('/wishlist/(.*)$', $uri, $matches) && $method == 'GET') {
wishlistListAction($matches[1]);
} elseif ('/index.php/wishlist/add' === $uri && $method == 'POST') {
wishlistAddAction($_GET['email'], $_POST);
} else {
header('HTTP/1.1 404 Not Found');
echo '<html><body><h1>Page Not Found</h1></body></html>';
}
php estruturado
// public/index.php
// route the request internally
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$method = $_SERVER['REQUEST_METHOD'];
if (preg_match('/wishlist/(.*)$', $uri, $matches) && $method == 'GET') {
wishlistListAction($matches[1]);
} elseif ('/index.php/wishlist/add' === $uri && $method == 'POST') {
wishlistAddAction($_GET['email'], $_POST);
} else {
header('HTTP/1.1 404 Not Found');
echo '<html><body><h1>Page Not Found</h1></body></html>';
}
php estruturado
// public/index.php
// route the request internally
$uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH);
$method = $_SERVER['REQUEST_METHOD'];
if (preg_match('/wishlist/(.*)$', $uri, $matches) && $method == 'GET') {
wishlistListAction($matches[1]);
} elseif ('/index.php/wishlist/add' === $uri && $method == 'POST') {
wishlistAddAction($_GET['email'], $_POST);
} else {
header('HTTP/1.1 404 Not Found');
echo '<html><body><h1>Page Not Found</h1></body></html>';
}
php estruturado
autoload
php estruturado
// public/index.php
require_once __DIR__ . '/../config/app.php';
require_once LIBRARY_DIR . '/functions.php';
require_once LIBRARY_DIR . '/wishlist.php';
// include_path is other alternative
ini_set('include_path', __DIR__ . '/../lib');
php estruturado
autoload
php estruturado
{
"name": "tonicospinelli/developing-for-business",
"description": "A Quick Project for Talk",
"license": "MIT",
"autoload": {
"files": [
"./lib/dbconn.php",
"./lib/functions.php",
"./lib/controllers/wishlist.php",
"./lib/models/wishlist.php"
]
}
}
composer
php estruturado
$ composer dump-autoload
// public/index.php
require_once __DIR__ . '/../vendor/autoload.php';
php estruturado
autoload
developing-for-business
├── cli
│ └── wishlist_notification.php
├── composer.json
├── config
│ └── app.php
├── lib
│ ├── controllers
│ │ └── wishlist.php
│ ├── functions.php
│ └── models
│ └── wishlist.php
├── public
│ └── index.php
├── templates
│ └── wishlists
└── vendor
estrutura do projeto
php estruturado
php orientado a objetos
código auto explicativo
facilidade no crescimento
testes automatizados
php orientado a objetos
testes automatizados
php orientado a objetos
garantem regras conhecidas
auxiliam na refatoração
não evitam bugs
testes automatizados
php orientado a objetos
PHPUnit 5.4.6 by Sebastian Bergmann and contributors.
................................................... 59 / 59 (100%)
Time: 349 ms, Memory: 6.00MB
OK (59 tests, 126 assertions)
testes automatizados
php orientado a objetos
PHPUnit 5.4.6 by Sebastian Bergmann and contributors.
..................................F................ 59 / 59 (100%)
Time: 374 ms, Memory: 6.00MB
There was 1 failure:
1) ProductTest::testUpdateProductFailed
Failed asserting that exception of type "ProductException" is
thrown.
FAILURES!
Tests: 59, Assertions: 125, Failures: 1.
testes automatizados
php orientado a objetos
não confie em arrays
evite abreviações
php orientado a objetos
/**
* Creates a new wish list data.
* @param array $data
* @return array
*/
function newWishList(array $data)
{
return array(
'email' => isset($data['email']) ? $data['email'] : null),
'product_id' => $data['product_id'],
'status' => 'P',
);
}
php orientado a objetos
objetos de valor
php orientado a objetos
objetos simples
encapsulam tipos primitivos
representam o valor
objetos de valor
php orientado a objetos
class Status
{
const PENDING = 'P';
const SENT = 'S';
private $status;
public function __construct($status)
{
$this->validate($status);
$this->status = $status;
}
// … other methods
public function equalsTo(Status $status)
{
return $status === $this;
}
}
objetos de valor
php orientado a objetos
entidades
php orientado a objetos
são mutáveis
tem identificador
entidades
php orientado a objetos
class Wishlist
{
public function __construct(
Id $id,
Email email,
WishlistItem $item,
Status $status
) {
$this->id = $id;
$this->email = $email;
$this->item = $item;
$this->status = $status;
}
}
entidades
php orientado a objetos
class Wishlist
{
public function __construct(
Id $id,
Email email,
WishlistItem $item,
Status $status
) {
$this->id = $id;
$this->email = $email;
$this->item = $item;
$this->status = $status;
}
}
por que um
objeto Item?
entidades
php orientado a objetos
class Wishlist
{
public function __construct(
Id $id,
Email email,
WishlistItem $item,
Status $status
) {
$this->id = $id;
$this->email = $email;
$this->item = $item;
$this->status = $status;
}
}
por que um
objeto Item?
Produtos
Presente
entidades
php orientado a objetos
interface WishlistItem
{
public function getId();
}
class WishlistProduct implements WishlistItem
{
public function __construct(
Id $id,
$name,
Available $availability
) {
$this->id = $id;
$this->name = $name;
$this->available = $availability;
}
}
entidades
php orientado a objetos
repositórios
php orientado a objetos
camada de persistência
estratégia de armazenamento
repositórios
php orientado a objetos
interface WishlistRepository
{
public function add(Wishlist $wishlist);
public function delete(Wishlist $wishlist);
public function find($id);
public function findAllByEmail($email);
public function findAllToNotify();
}
repositórios
php orientado a objetos
namespace DevelopBusinessApplicationProductWishlistRepositories;
class PdoRepository implements WishlistRepository
{
public function __construct(PDO $driver, Factory $factory);
public function findAllByEmail($email)
{
$query = "find all items by email";
$stm = $this->driver->prepare($query);
$stm->execute([$email]);
return $stm->fetchAll(
PDO::FETCH_FUNC, [$this->factory, 'create']
);
}
}
repositórios
php orientado a objetos
namespace DevelopBusinessApplicationProductWishlistRepositories;
class RedisRepository implements WishlistRepository
{
public function __construct(Predis $driver, Factory $factory);
public function find($id)
{
$wishlist = $this->driver->get($this->getKey($id));
if (!$wishlist) {
throw WishlistNotFoundException::byIdentifier($id);
}
return $this->factory->fromJson($wishlist);
}
}
repositórios
php orientado a objetos
class PdoRepositoryTest extends PHPUnit_Framework_TestCase
{
public function testAddNewRowSuccessful()
{
$wishlist = $this->factory->fromQueryResult(/* args */);
$pdoSpy = new PDOSpy();
(new Repository($pdoSpy))->add($wishlist);
$this->assertTrue($pdoSpy->beginTransactionCalled);
$this->assertTrue($pdoSpy->commitCalled);
$this->assertEquals(2, $wishlist->getId());
}
}
como testar repositórios?
php orientado a objetos
class PDOSpy extends PDO
{
public function beginTransaction()
{
$this->beginTransactionCalled = true;
}
public function prepare($statement, $options = null)
{
if ($statement == INSERT INTO wishlists VALUES (?, ?, ?)') {
return new WriteStatementStub($this->failureOnWrite);
}
throw new InvalidArgumentException(
"None Stub Statement was found for query: {$statement}"
);
}
}
como testar repositórios?
php orientado a objetos
function wishlistListAction($email)
{
$db = dbConnect();
$factory = new WishlistFactory();
$repository = new WishlistPdoRepository($db, $factory);
$wishlist = $repository->findAllByEmail($email);
include TEMPLATE_DIR . '/wishlists/list.php';
}
repositórios
php orientado a objetos
serviços
php orientado a objetos
camada de operação
orquestra os objetos
define o que fazer
serviços
php orientado a objetos
adicionando um item na lista de desejos
serviços
php orientado a objetos
$db = dbConnect();
$factory = new WishlistFactory();
$repository = new WishlistRepository($db, $factory);
$resolver = new ItemResolver(new ProductRepository($db));
try {
$intention = createIntention($request['wish_item']);
$useCase = new AddItemWishlistUseCase(
$repository, $factory, $resolver
);
$wishlist = $useCase->execute($intention);
$successmsg = "{$wishlist->getItemName()} added!";
} catch (DomainException $e) {
$errormsg = $e->getMessage();
}
resolvendo
dependências
adicionando um item na lista de desejos
php orientado a objetos
$db = dbConnect();
$factory = new WishlistFactory();
$repository = new WishlistRepository($db, $factory);
$resolver = new ItemResolver(new ProductRepository($db));
try {
$intention = createIntention($request['wish_item']);
$useCase = new AddItemWishlistUseCase(
$repository, $factory, $resolver
);
$wishlist = $useCase->execute($intention);
$successmsg = "{$wishlist->getItemName()} added!";
} catch (DomainException $e) {
$errormsg = $e->getMessage();
}
parsing da
requisição
adicionando um item na lista de desejos
php orientado a objetos
$db = dbConnect();
$factory = new WishlistFactory();
$repository = new WishlistRepository($db, $factory);
$resolver = new ItemResolver(new ProductRepository($db));
try {
$intention = createIntention($request['wish_item']);
$useCase = new AddItemWishlistUseCase(
$repository, $factory, $resolver
);
$wishlist = $useCase->execute($intention);
$successmsg = "{$wishlist->getItemName()} added!";
} catch (DomainException $e) {
$errormsg = $e->getMessage();
}
criando
objeto de serviço
adicionando um item na lista de desejos
php orientado a objetos
$db = dbConnect();
$factory = new WishlistFactory();
$repository = new WishlistRepository($db, $factory);
$resolver = new ItemResolver(new ProductRepository($db));
try {
$intention = createIntention($request['wish_item']);
$useCase = new AddItemWishlistUseCase(
$repository, $factory, $resolver
);
$wishlist = $useCase->execute($intention);
$successmsg = "{$wishlist->getItemName()} added!";
} catch (DomainException $e) {
$errormsg = $e->getMessage();
}
executando
o serviço
adicionando um item na lista de desejos
php orientado a objetos
$db = dbConnect();
$factory = new WishlistFactory();
$repository = new WishlistRepository($db, $factory);
$resolver = new ItemResolver(new ProductRepository($db));
try {
$intention = createIntention($request['wish_item']);
$useCase = new AddItemWishlistUseCase(
$repository, $factory, $resolver
);
$wishlist = $useCase->execute($intention);
$successmsg = "{$wishlist->getItemName()} added!";
} catch (DomainException $e) {
$errormsg = $e->getMessage();
}
mensagem de
negócio
adicionando um item na lista de desejos
php orientado a objetos
class AddItemWishlistUseCase
{
public function __construct(
WishlistRepository $repository,
WishlistFactory $factory,
ItemResolver $resolver
) {
// do something
}
}
como adicionar um item na lista de desejos
php orientado a objetos
class AddItemWishlistUseCase
{
public function execute(AddItemIntention $intention)
{
$item = $this->resolver->resolve($intention->itemId);
try {
$wishlist = $this->repository->findOneByEmailAndItem(
$email, $item
);
throw WishlistException::itemAlreadyExists($wishlist);
} catch (WishlistNotFoundException $e) {
// do nothing
}
$wishlist = $this->factory->new($email, $item);
return $this->repository->add($wishlist);
}
}
php orientado a objetos
como adicionar um item na lista de desejos
class AddItemWishlistUseCase
{
public function execute(AddItemIntention $intention)
{
$item = $this->resolver->resolve($intention->itemId);
try {
$wishlist = $this->repository->findOneByEmailAndItem(
$email, $item
);
throw WishlistException::itemAlreadyExists($wishlist);
} catch (WishlistNotFoundException $e) {
// do nothing
}
$wishlist = $this->factory->new($email, $item);
return $this->repository->add($wishlist);
}
}
php orientado a objetos
como adicionar um item na lista de desejos
class AddItemWishlistUseCase
{
public function execute(AddItemIntention $intention)
{
$item = $this->resolver->resolve($intention->itemId);
try {
$wishlist = $this->repository->findOneByEmailAndItem(
$email, $item
);
throw WishlistException::itemAlreadyExists($wishlist);
} catch (WishlistNotFoundException $e) {
// do nothing
}
$wishlist = $this->factory->new($email, $item);
return $this->repository->add($wishlist);
}
}
php orientado a objetos
como adicionar um item na lista de desejos
serviços
notificar usuário quando
um item estiver disponível
php orientado a objetos
// cli/wishlist_notify.php
require_once __DIR__ . '/../config/app.php';
require_once __DIR__ . '/../vendor/autoload.php';
$factory = new WishlistFactory();
$repository = new WishlistRepository(dbConnect(), $factory);
$notifier = new MailNotifier();
$useCase = (new NotifyItemsUseCase($repository, $notifier);
$useCase->execute(new NotifyItemsIntention(Status::PENDING));
notificar quando um item disponível
resolving
dependencies
php orientado a objetos
// cli/wishlist_notify.php
require_once __DIR__ . '/../config/app.php';
require_once __DIR__ . '/../vendor/autoload.php';
$factory = new WishlistFactory();
$repository = new WishlistRepository(dbConnect(), $factory);
$notifier = new MailNotifier();
$useCase = (new NotifyItemsUseCase($repository, $notifier);
$useCase->execute(new NotifyItemsIntention(Status::PENDING));
call service
notificar quando um item disponível
php orientado a objetos
class NotifyItemsUseCase
{
public function execute(NotifyItemsIntention $intention)
{
$status = $intention->getStatus();
$wishlists = $this->repository->findAllByStatus($status);
foreach ($wishlists as $wishlist) {
$this->notifier()->send($wishlist);
$wishlist->changeStatusTo(Status::sent());
$this->repository->update($wishlist);
}
}
}
como notificar quando um item disponível?
php orientado a objetos
class NotifyItemsUseCase
{
public function execute(NotifyItemsIntention $intention)
{
$status = $intention->getStatus();
$wishlists = $this->repository->findAllByStatus($status);
foreach ($wishlists as $wishlist) {
$this->notifier()->send($wishlist);
$wishlist->changeStatusTo(Status::sent());
$this->repository->update($wishlist);
}
}
}
como notificar quando um item disponível?
php orientado a objetos
class NotifyItemsUseCase
{
public function execute(NotifyItemsIntention $intention)
{
$status = $intention->getStatus();
$wishlists = $this->repository->findAllByStatus($status);
foreach ($wishlists as $wishlist) {
$this->notifier()->send($wishlist);
$wishlist->changeStatusTo(Status::sent());
$this->repository->update($wishlist);
}
}
}
como notificar quando um item disponível?
php orientado a objetos
injeção de dependência
php orientado a objetos
princípio da inversão de dependência
dependências configuráveis
injeção de dependência
php orientado a objetos
Respect/Config
injeção de dependência
php orientado a objetos
// config/app.ini
[databaseConnection PDO]
__construct = ["sqlite:../data/business.db", null, null]
[factory WishlistFactory]
[repository WishlistRepository]
__construct = [[databaseConnection], [factory]]
[productRepository ProductRepository]
driver = [databaseConnection]
[itemResolver WishlistItemResolver]
product = [productRepository]
injeção de dependência
php orientado a objetos
// public/index.php
require_once __DIR__ . '/../config/app.php';
require_once __DIR__ . '/../vendor/autoload.php';
$configFile = __DIR__ . '/../config/app.ini';
$container = new RespectConfigContainer($configFile);
if ('/index.php/wishlist/add' === $uri /* other validations */) {
wishlistAddAction($container, $_GET['email'], $_POST);
}
injeção de dependência
php orientado a objetos
// public/index.php
require_once __DIR__ . '/../config/app.php';
require_once __DIR__ . '/../vendor/autoload.php';
$configFile = __DIR__ . '/../config/app.ini';
$container = new RespectConfigContainer($configFile);
if ('/index.php/wishlist/add' === $uri /* other validations */) {
wishlistAddAction($container, $_GET['email'], $_POST);
}
injeção de dependência
php orientado a objetos
function wishlistAddAction(Container $container, $email, $request)
{
try {
$intention = createIntention($request['wish_item']);
$useCase = $container->wishlistAddItemWishlistUseCase;
$wishlist = $useCase->execute($intention);
$successmsg = "{$wishlist->getItemName()} added!";
} catch (Exception $e) {
$errormsg = $e->getMessage();
}
}
injeção de dependência
php orientado a objetos
eventos
php orientado a objetos
mecanismo de inversão de controle
comunicação assíncrona
baixo acoplamento
eventos
php orientado a objetos
symfony/event-dispatcher
eventos
php orientado a objetos
class UpdateProductUseCase
{
public function __construct(/* args */, $eventDispatcher);
public function execute(Intention $intention)
{
$this->repository->update($updatedProduct);
$event = new ProductWasUpdated($updatedProduct);
$this->dispatch('product.updated', $event);
return $updatedProduct;
}
}
eventos
php orientado a objetos
class UpdateProductUseCase
{
public function __construct(/* args */, $eventDispatcher);
public function execute(Intention $intention)
{
$this->repository->update($updatedProduct);
$event = new ProductWasUpdated($updatedProduct);
$this->dispatch('product.updated', $event);
if ($this->isStockIncreased($product, $updatedProduct)) {
$this->dispatch('product.stock.increased', $event);
}
return $updatedProduct;
}
}
eventos
php orientado a objetos
class StockHasIncreasedListener
{
public function __construct(NotifyProductAvailable $useCase);
public function __invoke(ProductStockIncreasedEvent $event)
{
$productId = $event->getProduct()->getId();
$intention = new NotifyProductIntention($productId);
$this->useCase->execute($intention);
}
}
events
object oriented php
config/app.ini
[wishlistStockListener StockHasIncreasedListener]
useCase = [notifyProductAvailableUseCase]
[eventDispatcher EventDispatcher]
addListener[] = ["product.stock.increased",[wishlistStockListener]]
[productUpdateUseCase UpdateProductUseCase]
__construct = [[repository], [factory], [eventDispatcher]]
eventos
php orientado a objetos
estrutura
php orientado a objetos
business
services
application
web
devices
useinterface
database
ExternalInterfaces
camadas
php orientado a objetos
// public/wishlist.php
// ...
if (isset($_POST['submit']) && isValid($_POST['wish_item'])) {
$wishItem = createWishListItem($_POST['wish_item']);
$db->beginTransaction();
try {
$stm = $db->prepare('insert new entry (email, product_id)');
$stm->execute([$wishItem['email'], $wishItem['product_id']]);
$db->commit();
$successmsg = 'Product was added at wish list successfully!';
} catch (Exception $e) {
$db->rollBack();
$errormsg = 'Product could not be added at wishlist! :(';
}
}
// ..
php puro
// lib/controllers/wishList.php
function wishlistAddAction(Container $container, $email, $request)
{
try {
$intention = createIntention($request['wish_item']);
$useCase = $container->wishlistAddItemWishlistUseCase;
$wishlist = $useCase->execute($intention);
$successmsg = "{$wishlist->getItemName()} added!";
} catch (Exception $e) {
$errormsg = $e->getMessage();
}
}
php orientado a objetos
developing-for-business
├── cli
│ └── wishlist_notification.php
├── data
│ └── business.db
├── lib
│ ├── dbconn.php
│ └── functions.php
└── public
└── wishlist.php
estrutura php puro
DevelopBusiness
└── Application
├── Product
│ ├── Controllers
│ └── Repositories
└── ProductWishlist
├── Controllers
├── Resolver
├── Listeners
└── Repositories
DevelopBusiness
├── Product
│ ├── Events
│ ├── Exceptions
│ ├── Intentions
│ ├── Repositories
│ └── UseCases
└── Wishlist
├── Exceptions
├── Intentions
├── ItemResolver.php
├── Repositories
└── UseCases
estrutura php orientado a objetos
conclusão
saia da zona de conforto
interaja com a comunidade
conclusão
automatize tarefas repetitivas
conclusão
domain driven design
conclusão
domain specific language
conclusão
princípio S.O.L.I.D.
conclusão
Implementing Domain-Driven Design
por Vaughn Vernon
Patterns of Enterprise Application Architecture
por Martin Fowler
Domain-Driven Design
por Eric Evans
DDD in PHP
por Carlos Buenosvinos, Christian Soronellas e Keyvan Akbary
referências
Life's too short for bad software
Lew Cirne, New Relic

Weitere ähnliche Inhalte

Was ist angesagt?

Introdução ao Symfony 2 - SfCon 2012
Introdução ao Symfony 2 - SfCon 2012Introdução ao Symfony 2 - SfCon 2012
Introdução ao Symfony 2 - SfCon 2012Hugo Magalhães
 
Aula 12 Relatório - Tabelas
Aula 12   Relatório - TabelasAula 12   Relatório - Tabelas
Aula 12 Relatório - TabelasDalton Martins
 
Symfony - Framework PHP de alta produtividade
Symfony - Framework PHP de alta produtividadeSymfony - Framework PHP de alta produtividade
Symfony - Framework PHP de alta produtividadeHugo Magalhães
 
Evento Front End SP - Organizando o Javascript
 Evento Front End SP - Organizando o Javascript Evento Front End SP - Organizando o Javascript
Evento Front End SP - Organizando o JavascriptMichel Ribeiro
 
Aplicações rápidas para a Web com Django
Aplicações rápidas para a Web com DjangoAplicações rápidas para a Web com Django
Aplicações rápidas para a Web com DjangoFreedom DayMS
 
PHPubSP Object Calisthenics aplicado ao PHP
PHPubSP Object Calisthenics aplicado ao PHPPHPubSP Object Calisthenics aplicado ao PHP
PHPubSP Object Calisthenics aplicado ao PHPGuilherme Blanco
 
PHP robusto com Zend Framework
PHP robusto com Zend FrameworkPHP robusto com Zend Framework
PHP robusto com Zend FrameworkJaime Neto
 
jQuery - Visão Geral
jQuery - Visão GeraljQuery - Visão Geral
jQuery - Visão GeralKaio Valente
 
J query javascript para seres humanos
J query   javascript para seres humanosJ query   javascript para seres humanos
J query javascript para seres humanosnobios
 
Refactoring sem complicação!
Refactoring sem complicação!Refactoring sem complicação!
Refactoring sem complicação!Thamara Hessel
 
LambdaDay: Backbone.js
LambdaDay: Backbone.jsLambdaDay: Backbone.js
LambdaDay: Backbone.jsGiovanni Bassi
 
Orientação a Objetos em PHP
Orientação a Objetos em PHPOrientação a Objetos em PHP
Orientação a Objetos em PHPzehzinho
 
Prog web 02-php-primeiros-passos
Prog web 02-php-primeiros-passosProg web 02-php-primeiros-passos
Prog web 02-php-primeiros-passosRegis Magalhães
 

Was ist angesagt? (19)

Phpex2
Phpex2Phpex2
Phpex2
 
Introdução ao Symfony 2 - SfCon 2012
Introdução ao Symfony 2 - SfCon 2012Introdução ao Symfony 2 - SfCon 2012
Introdução ao Symfony 2 - SfCon 2012
 
Aula 12 Relatório - Tabelas
Aula 12   Relatório - TabelasAula 12   Relatório - Tabelas
Aula 12 Relatório - Tabelas
 
Ecommerce, mais simples do que parece
Ecommerce, mais simples do que pareceEcommerce, mais simples do que parece
Ecommerce, mais simples do que parece
 
Symfony - Framework PHP de alta produtividade
Symfony - Framework PHP de alta produtividadeSymfony - Framework PHP de alta produtividade
Symfony - Framework PHP de alta produtividade
 
Evento Front End SP - Organizando o Javascript
 Evento Front End SP - Organizando o Javascript Evento Front End SP - Organizando o Javascript
Evento Front End SP - Organizando o Javascript
 
Aplicações rápidas para a Web com Django
Aplicações rápidas para a Web com DjangoAplicações rápidas para a Web com Django
Aplicações rápidas para a Web com Django
 
PHP ao Extremo
PHP ao ExtremoPHP ao Extremo
PHP ao Extremo
 
PHPubSP Object Calisthenics aplicado ao PHP
PHPubSP Object Calisthenics aplicado ao PHPPHPubSP Object Calisthenics aplicado ao PHP
PHPubSP Object Calisthenics aplicado ao PHP
 
PHP robusto com Zend Framework
PHP robusto com Zend FrameworkPHP robusto com Zend Framework
PHP robusto com Zend Framework
 
jQuery - Visão Geral
jQuery - Visão GeraljQuery - Visão Geral
jQuery - Visão Geral
 
J query javascript para seres humanos
J query   javascript para seres humanosJ query   javascript para seres humanos
J query javascript para seres humanos
 
Introdução à JQuery
Introdução à JQueryIntrodução à JQuery
Introdução à JQuery
 
Refactoring sem complicação!
Refactoring sem complicação!Refactoring sem complicação!
Refactoring sem complicação!
 
Minicurso de jQuery
Minicurso de jQueryMinicurso de jQuery
Minicurso de jQuery
 
LambdaDay: Backbone.js
LambdaDay: Backbone.jsLambdaDay: Backbone.js
LambdaDay: Backbone.js
 
Orientação a Objetos em PHP
Orientação a Objetos em PHPOrientação a Objetos em PHP
Orientação a Objetos em PHP
 
Php 02 Primeiros Passos
Php 02 Primeiros PassosPhp 02 Primeiros Passos
Php 02 Primeiros Passos
 
Prog web 02-php-primeiros-passos
Prog web 02-php-primeiros-passosProg web 02-php-primeiros-passos
Prog web 02-php-primeiros-passos
 

Andere mochten auch

NetPromo - Proposta
NetPromo - PropostaNetPromo - Proposta
NetPromo - Propostalgfelicio
 
Dip Your Toes in the Sea of Security (PHP MiNDS January Meetup 2016)
Dip Your Toes in the Sea of Security (PHP MiNDS January Meetup 2016)Dip Your Toes in the Sea of Security (PHP MiNDS January Meetup 2016)
Dip Your Toes in the Sea of Security (PHP MiNDS January Meetup 2016)James Titcumb
 
Last Month in PHP - February 2017
Last Month in PHP - February 2017Last Month in PHP - February 2017
Last Month in PHP - February 2017Eric Poe
 
Refactoring Legacy Code
Refactoring Legacy CodeRefactoring Legacy Code
Refactoring Legacy CodeAdam Culp
 
Practical PHP Deployment with Jenkins
Practical PHP Deployment with JenkinsPractical PHP Deployment with Jenkins
Practical PHP Deployment with JenkinsAdam Culp
 
Learn To Test Like A Grumpy Programmer - 3 hour workshop
Learn To Test Like A Grumpy Programmer - 3 hour workshopLearn To Test Like A Grumpy Programmer - 3 hour workshop
Learn To Test Like A Grumpy Programmer - 3 hour workshopchartjes
 
A recommendation engine for your php application
A recommendation engine for your php applicationA recommendation engine for your php application
A recommendation engine for your php applicationMichele Orselli
 
Functional Structures in PHP
Functional Structures in PHPFunctional Structures in PHP
Functional Structures in PHPMarcello Duarte
 
WordPress for the modern PHP developer
WordPress for the modern PHP developerWordPress for the modern PHP developer
WordPress for the modern PHP developerChris Sherry
 

Andere mochten auch (12)

NetPromo - Proposta
NetPromo - PropostaNetPromo - Proposta
NetPromo - Proposta
 
Developing for Business
Developing for BusinessDeveloping for Business
Developing for Business
 
Dip Your Toes in the Sea of Security (PHP MiNDS January Meetup 2016)
Dip Your Toes in the Sea of Security (PHP MiNDS January Meetup 2016)Dip Your Toes in the Sea of Security (PHP MiNDS January Meetup 2016)
Dip Your Toes in the Sea of Security (PHP MiNDS January Meetup 2016)
 
Como programar melhor jogando game boy
Como programar melhor jogando game boyComo programar melhor jogando game boy
Como programar melhor jogando game boy
 
The journey to become a solid developer
The journey to become a solid developer The journey to become a solid developer
The journey to become a solid developer
 
Last Month in PHP - February 2017
Last Month in PHP - February 2017Last Month in PHP - February 2017
Last Month in PHP - February 2017
 
Refactoring Legacy Code
Refactoring Legacy CodeRefactoring Legacy Code
Refactoring Legacy Code
 
Practical PHP Deployment with Jenkins
Practical PHP Deployment with JenkinsPractical PHP Deployment with Jenkins
Practical PHP Deployment with Jenkins
 
Learn To Test Like A Grumpy Programmer - 3 hour workshop
Learn To Test Like A Grumpy Programmer - 3 hour workshopLearn To Test Like A Grumpy Programmer - 3 hour workshop
Learn To Test Like A Grumpy Programmer - 3 hour workshop
 
A recommendation engine for your php application
A recommendation engine for your php applicationA recommendation engine for your php application
A recommendation engine for your php application
 
Functional Structures in PHP
Functional Structures in PHPFunctional Structures in PHP
Functional Structures in PHP
 
WordPress for the modern PHP developer
WordPress for the modern PHP developerWordPress for the modern PHP developer
WordPress for the modern PHP developer
 

Ähnlich wie Modernizando sua aplicação com PHP estruturado

Ecommerce, mais simples do que parece
Ecommerce, mais simples do que pareceEcommerce, mais simples do que parece
Ecommerce, mais simples do que pareceImpacta Eventos
 
Play Framework - FLISOL
Play Framework - FLISOLPlay Framework - FLISOL
Play Framework - FLISOLgrupoweblovers
 
MIRA - Um framework Javascript para construção de interfaces adaptativas em a...
MIRA - Um framework Javascript para construção de interfaces adaptativas em a...MIRA - Um framework Javascript para construção de interfaces adaptativas em a...
MIRA - Um framework Javascript para construção de interfaces adaptativas em a...Ezequiel Bertti
 
Validação e Operações CRUD em PHP
Validação e Operações CRUD em PHPValidação e Operações CRUD em PHP
Validação e Operações CRUD em PHPBreno Vitorino
 
Código legado - PHP Conference Brasil - 2014
Código legado - PHP Conference Brasil - 2014Código legado - PHP Conference Brasil - 2014
Código legado - PHP Conference Brasil - 2014Michael Castillo Granados
 
PHP básico para iniciantes
PHP básico para iniciantesPHP básico para iniciantes
PHP básico para iniciantesEduardo Mendes
 
Palestra Novidades da linguagem C# 6
Palestra Novidades da linguagem C# 6Palestra Novidades da linguagem C# 6
Palestra Novidades da linguagem C# 6Renato Haddad
 
Curso de Ruby on Rails - Aula 03
Curso de Ruby on Rails - Aula 03Curso de Ruby on Rails - Aula 03
Curso de Ruby on Rails - Aula 03Maurício Linhares
 
Simplificando o Javascrip
Simplificando o JavascripSimplificando o Javascrip
Simplificando o JavascripMiquéias Amaro
 
Programando para programadores: Desafios na evolução de um Framework
Programando para programadores: Desafios na evolução de um FrameworkProgramando para programadores: Desafios na evolução de um Framework
Programando para programadores: Desafios na evolução de um FrameworkPablo Dall'Oglio
 
Escrevendo códigos php seguros
Escrevendo códigos php segurosEscrevendo códigos php seguros
Escrevendo códigos php segurosDouglas V. Pasqua
 
Curso de Ruby on Rails - Aula 02
Curso de Ruby on Rails - Aula 02Curso de Ruby on Rails - Aula 02
Curso de Ruby on Rails - Aula 02Maurício Linhares
 
Programação web ii aulas 06 e 07
Programação web ii   aulas 06 e 07Programação web ii   aulas 06 e 07
Programação web ii aulas 06 e 07Yuri Bispo
 

Ähnlich wie Modernizando sua aplicação com PHP estruturado (20)

Aula 8 php
Aula 8 phpAula 8 php
Aula 8 php
 
Ecommerce, mais simples do que parece
Ecommerce, mais simples do que pareceEcommerce, mais simples do que parece
Ecommerce, mais simples do que parece
 
apostila.pdf
apostila.pdfapostila.pdf
apostila.pdf
 
Play Framework - FLISOL
Play Framework - FLISOLPlay Framework - FLISOL
Play Framework - FLISOL
 
Hello SAFE World!!!
Hello SAFE World!!!Hello SAFE World!!!
Hello SAFE World!!!
 
MIRA - Um framework Javascript para construção de interfaces adaptativas em a...
MIRA - Um framework Javascript para construção de interfaces adaptativas em a...MIRA - Um framework Javascript para construção de interfaces adaptativas em a...
MIRA - Um framework Javascript para construção de interfaces adaptativas em a...
 
Validação e Operações CRUD em PHP
Validação e Operações CRUD em PHPValidação e Operações CRUD em PHP
Validação e Operações CRUD em PHP
 
Zend Framework
Zend FrameworkZend Framework
Zend Framework
 
Código legado - PHP Conference Brasil - 2014
Código legado - PHP Conference Brasil - 2014Código legado - PHP Conference Brasil - 2014
Código legado - PHP Conference Brasil - 2014
 
PHP básico para iniciantes
PHP básico para iniciantesPHP básico para iniciantes
PHP básico para iniciantes
 
Php 08 Oo
Php 08 OoPhp 08 Oo
Php 08 Oo
 
Palestra Novidades da linguagem C# 6
Palestra Novidades da linguagem C# 6Palestra Novidades da linguagem C# 6
Palestra Novidades da linguagem C# 6
 
Curso de Ruby on Rails - Aula 03
Curso de Ruby on Rails - Aula 03Curso de Ruby on Rails - Aula 03
Curso de Ruby on Rails - Aula 03
 
Simplificando o Javascrip
Simplificando o JavascripSimplificando o Javascrip
Simplificando o Javascrip
 
PHP MySQL Aula 03
PHP MySQL Aula 03PHP MySQL Aula 03
PHP MySQL Aula 03
 
Programando para programadores: Desafios na evolução de um Framework
Programando para programadores: Desafios na evolução de um FrameworkProgramando para programadores: Desafios na evolução de um Framework
Programando para programadores: Desafios na evolução de um Framework
 
Escrevendo códigos php seguros
Escrevendo códigos php segurosEscrevendo códigos php seguros
Escrevendo códigos php seguros
 
Curso de Ruby on Rails - Aula 02
Curso de Ruby on Rails - Aula 02Curso de Ruby on Rails - Aula 02
Curso de Ruby on Rails - Aula 02
 
Programação web ii aulas 06 e 07
Programação web ii   aulas 06 e 07Programação web ii   aulas 06 e 07
Programação web ii aulas 06 e 07
 
PHP GERAL
PHP GERALPHP GERAL
PHP GERAL
 

Modernizando sua aplicação com PHP estruturado

  • 1. modernizando a arquitertura de sua aplicação Antonio Spinelli @tonicospinelli tornando o seu código mais robusto e escalável
  • 4. o objetivo não muda: resolver problemas para o negócio!
  • 5. entenda o problema agregue valor ao negócio agilidade não é "sobrinhagem" desenvolvedor
  • 6. desenvolvedor automatize tarefas repetidas peça e faça code review leia código
  • 7. Lista de Desejos para Produtos Eu como um usuário convidado, quero adicionar um produto indisponível dentro da minha lista de desejos, de modo que eu receba uma notificação quando este estiver disponível. Objetivo reposição de estoque inteligente e estreitar relacionamento com cliente user story
  • 9. adicionando um item na lista de desejos php puro
  • 10. // public/wishlist.php // ... if (isset($_POST['submit']) && isValid($_POST['wish_item'])) { } // ... php puro
  • 11. // public/wishlist.php // ... if (isset($_POST['submit']) && isValid($_POST['wish_item'])) { $wishItem = createWishListItem($_POST['wish_item']); } // ... php puro
  • 12. // public/wishlist.php // ... if (isset($_POST['submit']) && isValid($_POST['wish_item'])) { $wishItem = createWishListItem($_POST['wish_item']); $stm = $db->prepare('insert new entry (email, product_id)'); $stm->execute([$wishItem['email'], $wishItem['product_id']]); $successmsg = 'Product was added at wish list successfully!'; } // ... php puro
  • 13. // public/wishlist.php // ... if (isset($_POST['submit']) && isValid($_POST['wish_item'])) { $wishItem = createWishListItem($_POST['wish_item']); $db->beginTransaction(); try { $stm = $db->prepare('insert new entry (email, product_id)'); $stm->execute([$wishItem['email'], $wishItem['product_id']]); $successmsg = 'Product was added at wish list successfully!'; $db->commit(); } catch (Exception $e) { $db->rollBack(); $errormsg = 'Product could not be added at wishlist! :('; } } // .. php puro
  • 14. // public/wishlist.php // ... <table> <?php foreach ($wishlist as $item): ?> <tr> <td><?php echo $item['id']; ?> </td> <td><?php echo $item['product_name']; ?> </td> <?php if ($item['product_stock'] == 0): ?> <td>Not Available</td> <?php else: ?> <td>Available</td> <?php endif; ?> <td> <?php echo removeUrl($item['id'], ['email' => $email]); ?> </td> </tr> <?php endforeach; ?> </table> // ... php puro
  • 15. notificar usuário quando o item estiver disponível php puro
  • 16. // cli/wishlist_notify.php // ... $query = "find all available products from wishlist"; $stm = $db->prepare($query); $stm->execute(); $wishlists = $stm->fetchAll(PDO::FETCH_ASSOC); php puro
  • 17. // cli/wishlist_notify.php // ... $query = "find all available products from wishlist"; $stm = $db->prepare($query); $stm->execute(); $wishlists = $stm->fetchAll(PDO::FETCH_ASSOC); foreach ($wishlists as $item) { mail( $item['email'], "{$item['product_name']} available", $mailBody ); $stm = $db->prepare("define new status for id = ?"); $stm->execute([$item['id']]); } php puro
  • 19. quais problemas temos com este código? atenção
  • 20. organização pobre sem verificação de erros dificuldade para reutilizar o código php puro
  • 23. // templates/wishlist/list.php <table> <?php foreach ($wishlist as $item): ?> <tr> <td><?php echo $item['id']; ?> </td> <td><?php echo $item['product_name']; ?> </td> <?php if ($item['product_stock'] == 0): ?> <td>Not Available</td> <?php else: ?> <td>Available</td> <?php endif; ?> <td> <?php echo removeUrl($item['id'], ['email' => $email]); ?> </td> </tr> <?php endforeach; ?> </table> php estruturado
  • 24. isolando regra de negócio php estruturado
  • 25. // lib/models/wishlist.php function addItemIntoWishlist(array $data); function createWishListItem(array $data); function findAllWishlistsToNotify(); function findAllWishProducts($email); function isValidWishList(array $data); function removeWishItem($id); function wishlistNotified($id); php estruturado
  • 26. interagindo regras de negócio com a apresentação php estruturado
  • 27. // public/wishlist.php require_once __DIR__ . '/../lib/dbconn.php'; require_once __DIR__ . '/../lib/functions.php'; require_once __DIR__ . '/../lib/wishlist.php'; if (isset($_POST['submit']) && isValidWishList($_POST['wish_item'])) { $wishItem = createWishListItem($_POST['wish_item']); $db->beginTransaction(); try { $stm = $db->prepare('insert new entry (email, product_id)'); $stm->execute([$wishItem['email'], $wishItem['product_id']]); $db->commit(); $successmsg = 'Product was added at wish list successfully!'; } catch (Exception $e) { $db->rollBack(); $errormsg = 'Product could not be added at wishlist! :('; } } // ... php estruturado
  • 28. // public/wishlist.php require_once __DIR__ . '/../lib/dbconn.php'; require_once __DIR__ . '/../lib/functions.php'; require_once __DIR__ . '/../lib/wishlist.php'; if (isset($_POST['submit']) && isValidWishList($_POST['wish_item'])) { $wishItem = createWishListItem($_POST['wish_item']); $db->beginTransaction(); try { $stm = $db->prepare('insert new entry (email, product_id)'); $stm->execute([$wishItem['email'], $wishItem['product_id']]); $db->commit(); $successmsg = 'Product was added at wish list successfully!'; } catch (Exception $e) { $db->rollBack(); $errormsg = 'Product could not be added at wishlist! :('; } } // ... structured php
  • 29. // public/wishlist.php require_once __DIR__ . '/../lib/dbconn.php'; require_once __DIR__ . '/../lib/functions.php'; require_once __DIR__ . '/../lib/wishlist.php'; if (isset($_POST['submit']) && isValidWishList($_POST['wish_item'])) { $wishItem = createWishListItem($_POST['wish_item']); if (addItemIntoWishlist($wishItem)) { $successmsg = 'Product was added at wish list successfully!'; } else { $errormsg = 'Product could not be added at wishlist! :('; } } // ... php estruturado
  • 30. // public/wishlist.php require_once __DIR__ . '/../lib/dbconn.php'; require_once __DIR__ . '/../lib/functions.php'; require_once __DIR__ . '/../lib/wishlist.php'; if (isset($_POST['submit']) && isValidWishList($_POST['wish_item'])) { $wishItem = createWishListItem($_POST['wish_item']); if (addItemIntoWishlist($wishItem)) { $successmsg = 'Product was added at wish list successfully!'; } else { $errormsg = 'Product could not be added at wishlist! :('; } } $wishlist = findAllWishProducts($_GET['email']); include __DIR__ . '/../templates/wishlists/list.php'; php estruturado
  • 32. // template/layout.php <!DOCTYPE html> <html> <head> <title><?php echo $title ?></title> </head> <body> <?php echo $content ?> </body> </html> layout padrão php estruturado
  • 33. // template/wishlist/list.php <?php $title = 'My Wish List' ?> define o título da página php estruturado
  • 34. // template/wishlist/list.php <?php $title = 'My Wish List' ?> <?php ob_start() ?> <table> <tbody> <?php foreach ($wishlist as $wish): ?> <tr><!-- print all columns --></tr> <?php endforeach; ?> </tbody> </table> <?php $content = ob_get_clean() ?> define o conteúdo da página php estruturado
  • 35. // template/wishlist/list.php <?php $title = 'My Wish List' ?> <?php ob_start() ?> <table> <tbody> <?php foreach ($wishlist as $wish): ?> <tr><!-- print all columns --></tr> <?php endforeach; ?> </tbody> </table> <?php $content = ob_get_clean() ?> <?php include __DIR__ . '/../layout.php' ?> extendendo layout padrão php estruturado
  • 37. sem um front controller GET /wishlist.php?email=email@test.com com index.php como um front controller GET /index.php/wishlist/email@test.com com regras de sobrescrita no servidor web GET /wishlist/email@test.com php estruturado
  • 38. // public/index.php // route the request internally $uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); $method = $_SERVER['REQUEST_METHOD']; if (preg_match('/wishlist/(.*)$', $uri, $matches) && $method == 'GET') { wishlistListAction($matches[1]); } elseif ('/index.php/wishlist/add' === $uri && $method == 'POST') { wishlistAddAction($_GET['email'], $_POST); } else { header('HTTP/1.1 404 Not Found'); echo '<html><body><h1>Page Not Found</h1></body></html>'; } php estruturado
  • 39. // public/index.php // route the request internally $uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); $method = $_SERVER['REQUEST_METHOD']; if (preg_match('/wishlist/(.*)$', $uri, $matches) && $method == 'GET') { wishlistListAction($matches[1]); } elseif ('/index.php/wishlist/add' === $uri && $method == 'POST') { wishlistAddAction($_GET['email'], $_POST); } else { header('HTTP/1.1 404 Not Found'); echo '<html><body><h1>Page Not Found</h1></body></html>'; } php estruturado
  • 40. // public/index.php // route the request internally $uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); $method = $_SERVER['REQUEST_METHOD']; if (preg_match('/wishlist/(.*)$', $uri, $matches) && $method == 'GET') { wishlistListAction($matches[1]); } elseif ('/index.php/wishlist/add' === $uri && $method == 'POST') { wishlistAddAction($_GET['email'], $_POST); } else { header('HTTP/1.1 404 Not Found'); echo '<html><body><h1>Page Not Found</h1></body></html>'; } php estruturado
  • 41. // public/index.php // route the request internally $uri = parse_url($_SERVER['REQUEST_URI'], PHP_URL_PATH); $method = $_SERVER['REQUEST_METHOD']; if (preg_match('/wishlist/(.*)$', $uri, $matches) && $method == 'GET') { wishlistListAction($matches[1]); } elseif ('/index.php/wishlist/add' === $uri && $method == 'POST') { wishlistAddAction($_GET['email'], $_POST); } else { header('HTTP/1.1 404 Not Found'); echo '<html><body><h1>Page Not Found</h1></body></html>'; } php estruturado
  • 43. // public/index.php require_once __DIR__ . '/../config/app.php'; require_once LIBRARY_DIR . '/functions.php'; require_once LIBRARY_DIR . '/wishlist.php'; // include_path is other alternative ini_set('include_path', __DIR__ . '/../lib'); php estruturado autoload
  • 45. { "name": "tonicospinelli/developing-for-business", "description": "A Quick Project for Talk", "license": "MIT", "autoload": { "files": [ "./lib/dbconn.php", "./lib/functions.php", "./lib/controllers/wishlist.php", "./lib/models/wishlist.php" ] } } composer php estruturado
  • 46. $ composer dump-autoload // public/index.php require_once __DIR__ . '/../vendor/autoload.php'; php estruturado autoload
  • 47. developing-for-business ├── cli │ └── wishlist_notification.php ├── composer.json ├── config │ └── app.php ├── lib │ ├── controllers │ │ └── wishlist.php │ ├── functions.php │ └── models │ └── wishlist.php ├── public │ └── index.php ├── templates │ └── wishlists └── vendor estrutura do projeto php estruturado
  • 48. php orientado a objetos
  • 49. código auto explicativo facilidade no crescimento testes automatizados php orientado a objetos
  • 51. garantem regras conhecidas auxiliam na refatoração não evitam bugs testes automatizados php orientado a objetos
  • 52. PHPUnit 5.4.6 by Sebastian Bergmann and contributors. ................................................... 59 / 59 (100%) Time: 349 ms, Memory: 6.00MB OK (59 tests, 126 assertions) testes automatizados php orientado a objetos
  • 53. PHPUnit 5.4.6 by Sebastian Bergmann and contributors. ..................................F................ 59 / 59 (100%) Time: 374 ms, Memory: 6.00MB There was 1 failure: 1) ProductTest::testUpdateProductFailed Failed asserting that exception of type "ProductException" is thrown. FAILURES! Tests: 59, Assertions: 125, Failures: 1. testes automatizados php orientado a objetos
  • 54. não confie em arrays evite abreviações php orientado a objetos
  • 55. /** * Creates a new wish list data. * @param array $data * @return array */ function newWishList(array $data) { return array( 'email' => isset($data['email']) ? $data['email'] : null), 'product_id' => $data['product_id'], 'status' => 'P', ); } php orientado a objetos
  • 56. objetos de valor php orientado a objetos
  • 57. objetos simples encapsulam tipos primitivos representam o valor objetos de valor php orientado a objetos
  • 58. class Status { const PENDING = 'P'; const SENT = 'S'; private $status; public function __construct($status) { $this->validate($status); $this->status = $status; } // … other methods public function equalsTo(Status $status) { return $status === $this; } } objetos de valor php orientado a objetos
  • 61. class Wishlist { public function __construct( Id $id, Email email, WishlistItem $item, Status $status ) { $this->id = $id; $this->email = $email; $this->item = $item; $this->status = $status; } } entidades php orientado a objetos
  • 62. class Wishlist { public function __construct( Id $id, Email email, WishlistItem $item, Status $status ) { $this->id = $id; $this->email = $email; $this->item = $item; $this->status = $status; } } por que um objeto Item? entidades php orientado a objetos
  • 63. class Wishlist { public function __construct( Id $id, Email email, WishlistItem $item, Status $status ) { $this->id = $id; $this->email = $email; $this->item = $item; $this->status = $status; } } por que um objeto Item? Produtos Presente entidades php orientado a objetos
  • 64. interface WishlistItem { public function getId(); } class WishlistProduct implements WishlistItem { public function __construct( Id $id, $name, Available $availability ) { $this->id = $id; $this->name = $name; $this->available = $availability; } } entidades php orientado a objetos
  • 66. camada de persistência estratégia de armazenamento repositórios php orientado a objetos
  • 67. interface WishlistRepository { public function add(Wishlist $wishlist); public function delete(Wishlist $wishlist); public function find($id); public function findAllByEmail($email); public function findAllToNotify(); } repositórios php orientado a objetos
  • 68. namespace DevelopBusinessApplicationProductWishlistRepositories; class PdoRepository implements WishlistRepository { public function __construct(PDO $driver, Factory $factory); public function findAllByEmail($email) { $query = "find all items by email"; $stm = $this->driver->prepare($query); $stm->execute([$email]); return $stm->fetchAll( PDO::FETCH_FUNC, [$this->factory, 'create'] ); } } repositórios php orientado a objetos
  • 69. namespace DevelopBusinessApplicationProductWishlistRepositories; class RedisRepository implements WishlistRepository { public function __construct(Predis $driver, Factory $factory); public function find($id) { $wishlist = $this->driver->get($this->getKey($id)); if (!$wishlist) { throw WishlistNotFoundException::byIdentifier($id); } return $this->factory->fromJson($wishlist); } } repositórios php orientado a objetos
  • 70. class PdoRepositoryTest extends PHPUnit_Framework_TestCase { public function testAddNewRowSuccessful() { $wishlist = $this->factory->fromQueryResult(/* args */); $pdoSpy = new PDOSpy(); (new Repository($pdoSpy))->add($wishlist); $this->assertTrue($pdoSpy->beginTransactionCalled); $this->assertTrue($pdoSpy->commitCalled); $this->assertEquals(2, $wishlist->getId()); } } como testar repositórios? php orientado a objetos
  • 71. class PDOSpy extends PDO { public function beginTransaction() { $this->beginTransactionCalled = true; } public function prepare($statement, $options = null) { if ($statement == INSERT INTO wishlists VALUES (?, ?, ?)') { return new WriteStatementStub($this->failureOnWrite); } throw new InvalidArgumentException( "None Stub Statement was found for query: {$statement}" ); } } como testar repositórios? php orientado a objetos
  • 72. function wishlistListAction($email) { $db = dbConnect(); $factory = new WishlistFactory(); $repository = new WishlistPdoRepository($db, $factory); $wishlist = $repository->findAllByEmail($email); include TEMPLATE_DIR . '/wishlists/list.php'; } repositórios php orientado a objetos
  • 74. camada de operação orquestra os objetos define o que fazer serviços php orientado a objetos
  • 75. adicionando um item na lista de desejos serviços php orientado a objetos
  • 76. $db = dbConnect(); $factory = new WishlistFactory(); $repository = new WishlistRepository($db, $factory); $resolver = new ItemResolver(new ProductRepository($db)); try { $intention = createIntention($request['wish_item']); $useCase = new AddItemWishlistUseCase( $repository, $factory, $resolver ); $wishlist = $useCase->execute($intention); $successmsg = "{$wishlist->getItemName()} added!"; } catch (DomainException $e) { $errormsg = $e->getMessage(); } resolvendo dependências adicionando um item na lista de desejos php orientado a objetos
  • 77. $db = dbConnect(); $factory = new WishlistFactory(); $repository = new WishlistRepository($db, $factory); $resolver = new ItemResolver(new ProductRepository($db)); try { $intention = createIntention($request['wish_item']); $useCase = new AddItemWishlistUseCase( $repository, $factory, $resolver ); $wishlist = $useCase->execute($intention); $successmsg = "{$wishlist->getItemName()} added!"; } catch (DomainException $e) { $errormsg = $e->getMessage(); } parsing da requisição adicionando um item na lista de desejos php orientado a objetos
  • 78. $db = dbConnect(); $factory = new WishlistFactory(); $repository = new WishlistRepository($db, $factory); $resolver = new ItemResolver(new ProductRepository($db)); try { $intention = createIntention($request['wish_item']); $useCase = new AddItemWishlistUseCase( $repository, $factory, $resolver ); $wishlist = $useCase->execute($intention); $successmsg = "{$wishlist->getItemName()} added!"; } catch (DomainException $e) { $errormsg = $e->getMessage(); } criando objeto de serviço adicionando um item na lista de desejos php orientado a objetos
  • 79. $db = dbConnect(); $factory = new WishlistFactory(); $repository = new WishlistRepository($db, $factory); $resolver = new ItemResolver(new ProductRepository($db)); try { $intention = createIntention($request['wish_item']); $useCase = new AddItemWishlistUseCase( $repository, $factory, $resolver ); $wishlist = $useCase->execute($intention); $successmsg = "{$wishlist->getItemName()} added!"; } catch (DomainException $e) { $errormsg = $e->getMessage(); } executando o serviço adicionando um item na lista de desejos php orientado a objetos
  • 80. $db = dbConnect(); $factory = new WishlistFactory(); $repository = new WishlistRepository($db, $factory); $resolver = new ItemResolver(new ProductRepository($db)); try { $intention = createIntention($request['wish_item']); $useCase = new AddItemWishlistUseCase( $repository, $factory, $resolver ); $wishlist = $useCase->execute($intention); $successmsg = "{$wishlist->getItemName()} added!"; } catch (DomainException $e) { $errormsg = $e->getMessage(); } mensagem de negócio adicionando um item na lista de desejos php orientado a objetos
  • 81. class AddItemWishlistUseCase { public function __construct( WishlistRepository $repository, WishlistFactory $factory, ItemResolver $resolver ) { // do something } } como adicionar um item na lista de desejos php orientado a objetos
  • 82. class AddItemWishlistUseCase { public function execute(AddItemIntention $intention) { $item = $this->resolver->resolve($intention->itemId); try { $wishlist = $this->repository->findOneByEmailAndItem( $email, $item ); throw WishlistException::itemAlreadyExists($wishlist); } catch (WishlistNotFoundException $e) { // do nothing } $wishlist = $this->factory->new($email, $item); return $this->repository->add($wishlist); } } php orientado a objetos como adicionar um item na lista de desejos
  • 83. class AddItemWishlistUseCase { public function execute(AddItemIntention $intention) { $item = $this->resolver->resolve($intention->itemId); try { $wishlist = $this->repository->findOneByEmailAndItem( $email, $item ); throw WishlistException::itemAlreadyExists($wishlist); } catch (WishlistNotFoundException $e) { // do nothing } $wishlist = $this->factory->new($email, $item); return $this->repository->add($wishlist); } } php orientado a objetos como adicionar um item na lista de desejos
  • 84. class AddItemWishlistUseCase { public function execute(AddItemIntention $intention) { $item = $this->resolver->resolve($intention->itemId); try { $wishlist = $this->repository->findOneByEmailAndItem( $email, $item ); throw WishlistException::itemAlreadyExists($wishlist); } catch (WishlistNotFoundException $e) { // do nothing } $wishlist = $this->factory->new($email, $item); return $this->repository->add($wishlist); } } php orientado a objetos como adicionar um item na lista de desejos
  • 85. serviços notificar usuário quando um item estiver disponível php orientado a objetos
  • 86. // cli/wishlist_notify.php require_once __DIR__ . '/../config/app.php'; require_once __DIR__ . '/../vendor/autoload.php'; $factory = new WishlistFactory(); $repository = new WishlistRepository(dbConnect(), $factory); $notifier = new MailNotifier(); $useCase = (new NotifyItemsUseCase($repository, $notifier); $useCase->execute(new NotifyItemsIntention(Status::PENDING)); notificar quando um item disponível resolving dependencies php orientado a objetos
  • 87. // cli/wishlist_notify.php require_once __DIR__ . '/../config/app.php'; require_once __DIR__ . '/../vendor/autoload.php'; $factory = new WishlistFactory(); $repository = new WishlistRepository(dbConnect(), $factory); $notifier = new MailNotifier(); $useCase = (new NotifyItemsUseCase($repository, $notifier); $useCase->execute(new NotifyItemsIntention(Status::PENDING)); call service notificar quando um item disponível php orientado a objetos
  • 88. class NotifyItemsUseCase { public function execute(NotifyItemsIntention $intention) { $status = $intention->getStatus(); $wishlists = $this->repository->findAllByStatus($status); foreach ($wishlists as $wishlist) { $this->notifier()->send($wishlist); $wishlist->changeStatusTo(Status::sent()); $this->repository->update($wishlist); } } } como notificar quando um item disponível? php orientado a objetos
  • 89. class NotifyItemsUseCase { public function execute(NotifyItemsIntention $intention) { $status = $intention->getStatus(); $wishlists = $this->repository->findAllByStatus($status); foreach ($wishlists as $wishlist) { $this->notifier()->send($wishlist); $wishlist->changeStatusTo(Status::sent()); $this->repository->update($wishlist); } } } como notificar quando um item disponível? php orientado a objetos
  • 90. class NotifyItemsUseCase { public function execute(NotifyItemsIntention $intention) { $status = $intention->getStatus(); $wishlists = $this->repository->findAllByStatus($status); foreach ($wishlists as $wishlist) { $this->notifier()->send($wishlist); $wishlist->changeStatusTo(Status::sent()); $this->repository->update($wishlist); } } } como notificar quando um item disponível? php orientado a objetos
  • 91. injeção de dependência php orientado a objetos
  • 92. princípio da inversão de dependência dependências configuráveis injeção de dependência php orientado a objetos
  • 94. // config/app.ini [databaseConnection PDO] __construct = ["sqlite:../data/business.db", null, null] [factory WishlistFactory] [repository WishlistRepository] __construct = [[databaseConnection], [factory]] [productRepository ProductRepository] driver = [databaseConnection] [itemResolver WishlistItemResolver] product = [productRepository] injeção de dependência php orientado a objetos
  • 95. // public/index.php require_once __DIR__ . '/../config/app.php'; require_once __DIR__ . '/../vendor/autoload.php'; $configFile = __DIR__ . '/../config/app.ini'; $container = new RespectConfigContainer($configFile); if ('/index.php/wishlist/add' === $uri /* other validations */) { wishlistAddAction($container, $_GET['email'], $_POST); } injeção de dependência php orientado a objetos
  • 96. // public/index.php require_once __DIR__ . '/../config/app.php'; require_once __DIR__ . '/../vendor/autoload.php'; $configFile = __DIR__ . '/../config/app.ini'; $container = new RespectConfigContainer($configFile); if ('/index.php/wishlist/add' === $uri /* other validations */) { wishlistAddAction($container, $_GET['email'], $_POST); } injeção de dependência php orientado a objetos
  • 97. function wishlistAddAction(Container $container, $email, $request) { try { $intention = createIntention($request['wish_item']); $useCase = $container->wishlistAddItemWishlistUseCase; $wishlist = $useCase->execute($intention); $successmsg = "{$wishlist->getItemName()} added!"; } catch (Exception $e) { $errormsg = $e->getMessage(); } } injeção de dependência php orientado a objetos
  • 99. mecanismo de inversão de controle comunicação assíncrona baixo acoplamento eventos php orientado a objetos
  • 101. class UpdateProductUseCase { public function __construct(/* args */, $eventDispatcher); public function execute(Intention $intention) { $this->repository->update($updatedProduct); $event = new ProductWasUpdated($updatedProduct); $this->dispatch('product.updated', $event); return $updatedProduct; } } eventos php orientado a objetos
  • 102. class UpdateProductUseCase { public function __construct(/* args */, $eventDispatcher); public function execute(Intention $intention) { $this->repository->update($updatedProduct); $event = new ProductWasUpdated($updatedProduct); $this->dispatch('product.updated', $event); if ($this->isStockIncreased($product, $updatedProduct)) { $this->dispatch('product.stock.increased', $event); } return $updatedProduct; } } eventos php orientado a objetos
  • 103. class StockHasIncreasedListener { public function __construct(NotifyProductAvailable $useCase); public function __invoke(ProductStockIncreasedEvent $event) { $productId = $event->getProduct()->getId(); $intention = new NotifyProductIntention($productId); $this->useCase->execute($intention); } } events object oriented php
  • 104. config/app.ini [wishlistStockListener StockHasIncreasedListener] useCase = [notifyProductAvailableUseCase] [eventDispatcher EventDispatcher] addListener[] = ["product.stock.increased",[wishlistStockListener]] [productUpdateUseCase UpdateProductUseCase] __construct = [[repository], [factory], [eventDispatcher]] eventos php orientado a objetos
  • 107. // public/wishlist.php // ... if (isset($_POST['submit']) && isValid($_POST['wish_item'])) { $wishItem = createWishListItem($_POST['wish_item']); $db->beginTransaction(); try { $stm = $db->prepare('insert new entry (email, product_id)'); $stm->execute([$wishItem['email'], $wishItem['product_id']]); $db->commit(); $successmsg = 'Product was added at wish list successfully!'; } catch (Exception $e) { $db->rollBack(); $errormsg = 'Product could not be added at wishlist! :('; } } // .. php puro
  • 108. // lib/controllers/wishList.php function wishlistAddAction(Container $container, $email, $request) { try { $intention = createIntention($request['wish_item']); $useCase = $container->wishlistAddItemWishlistUseCase; $wishlist = $useCase->execute($intention); $successmsg = "{$wishlist->getItemName()} added!"; } catch (Exception $e) { $errormsg = $e->getMessage(); } } php orientado a objetos
  • 109. developing-for-business ├── cli │ └── wishlist_notification.php ├── data │ └── business.db ├── lib │ ├── dbconn.php │ └── functions.php └── public └── wishlist.php estrutura php puro
  • 110. DevelopBusiness └── Application ├── Product │ ├── Controllers │ └── Repositories └── ProductWishlist ├── Controllers ├── Resolver ├── Listeners └── Repositories DevelopBusiness ├── Product │ ├── Events │ ├── Exceptions │ ├── Intentions │ ├── Repositories │ └── UseCases └── Wishlist ├── Exceptions ├── Intentions ├── ItemResolver.php ├── Repositories └── UseCases estrutura php orientado a objetos
  • 111. conclusão saia da zona de conforto
  • 112. interaja com a comunidade conclusão
  • 117. Implementing Domain-Driven Design por Vaughn Vernon Patterns of Enterprise Application Architecture por Martin Fowler Domain-Driven Design por Eric Evans DDD in PHP por Carlos Buenosvinos, Christian Soronellas e Keyvan Akbary referências
  • 118. Life's too short for bad software Lew Cirne, New Relic