SlideShare a Scribd company logo
1 of 84
Globalcode – Open4education
Developing for Business
Trilha – PHP Architecture
Globalcode – Open4education
apresentação
Antonio Spinelli
@tonicospinelli
tonicospinelli85@gmail.com
Globalcode – Open4education
o propósito sempre é o mesmo:
resolver problema para o negócio!
Globalcode – Open4education
comportamento
problema simples
vs
soluções complexas
Globalcode – Open4education
comportamento
escopo abstrato
=
problema desconhecido
Globalcode – Open4education
comportamento
agregue valor para negócio
entenda a demanda
agilidade não é "sobrinhagem"
Globalcode – Open4education
conhecimento
leia código
peça e faça code review
automatize tarefas repetitivas
Globalcode – Open4education
user story
Lista de Desejos
Eu como usuário convidado, quero adicionar um produto
esgotado em minha lista de desejos para que eu receba uma
notificação quando este estiver disponível.
Objetivo
reposição mais inteligente de produtos
Globalcode – Open4education
php estruturado
Globalcode – Open4education
php estruturado
adicionando um item
na lista de desejos
Globalcode – Open4education
// public/wishlist.php
// ...
if (isset($_POST['submit']) && isValidWishList($_POST['wish_item'])) {
$wishItem = getWishList($_POST['wish_item']);
$db->beginTransaction();
try {
$stm = $db->prepare(
'INSERT INTO wishlists (email, product_id) VALUES (?, ?)'
);
$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
Globalcode – Open4education
php estruturado
// public/wishlist.php
// ...
<table>
<?php foreach ($wishlist as $wish): ?>
<tr>
<td><?php echo $wish['id']; ?> </td>
<td><?php echo $wish['product_name']; ?> </td>
<?php if ($wish['product_stock'] == 0): ?>
<td>Not Available</td>
<?php else: ?>
<td>Available</td>
<?php endif; ?>
<td>
<?php echo removeUrl($wish['id'], ['email' => $email]); ?>
</td>
</tr>
<?php endforeach; ?>
</table>
// ...
Globalcode – Open4education
php estruturado
notificar usuário que
o item está disponível
Globalcode – Open4education
php estruturado
// 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 $wishlist) {
mail(
$wishlist['email'],
"{$wishlist['product_name']} disponível",
$mailBody
);
$stm = $db->prepare("UPDATE wishlists SET status='S' WHERE id=?");
$stm->execute([$wishlist['id']]);
}
Globalcode – Open4education
php estruturado
Pronto! funciona!
Globalcode – Open4education
php estruturado
quais problemas neste código?
Globalcode – Open4education
php estruturado
organização pobre
sem verificação de erro
dificuldade de reusar código
Globalcode – Open4education
php estruturado
isolando a apresentação
Globalcode – Open4education
php estruturado
// templates/wishlist/list.php
<table>
<?php foreach ($wishlist as $wish): ?>
<tr>
<td><?php echo $wish['id']; ?> </td>
<td><?php echo $wish['product_name']; ?> </td>
<?php if ($wish['product_stock'] == 0): ?>
<td>Not Available</td>
<?php else: ?>
<td>Available</td>
<?php endif; ?>
<td>
<?php echo removeUrl($wish['id'], ['email' => $email]); ?>
</td>
</tr>
<?php endforeach; ?>
</table>
Globalcode – Open4education
php estruturado
isolando regras de negócio
Globalcode – Open4education
php estruturado
function isValidWishList(array $data);
function getWishList(array $data);
function findAllWishProducts($email);
function addWishItem(array $data);
function removeWishItem($id);
function findAllWishlistsToNotify();
function wishlistNotified($id);
Globalcode – Open4education
php estruturado
interagindo com
regra de negócio e apresentação
Globalcode – Open4education
php estruturado
public/wishlist.php
require_once __DIR__ . '/../lib/functions.php';
require_once __DIR__ . '/../lib/models/wishlist.php';
require_once __DIR__ . '/../lib/dbconn.php';
if (isset($_POST['submit']) && isValidWishList($_POST['wish_item'])) {
$wishItem = getWishList($_POST['wish_item']);
if (addWishItem($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';
Globalcode – Open4education
php estruturado
isolando layout
Globalcode – Open4education
php estruturado
// template/layout.php
<!DOCTYPE html>
<html>
<head>
<title><?php echo $title ?></title>
</head>
<body>
<?php echo $content ?>
</body>
</html>
Globalcode – Open4education
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' ?>
Globalcode – Open4education
php estruturado
front controller
Globalcode – Open4education
php estruturado
Without a front controller
GET /wishlist.php?email=email@test.com
With index.php as the front controller
GET /index.php/wishlist/email@test.com
Globalcode – Open4education
php puro front controller
// public/index.php
// load function files
// 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>';
}
Globalcode – Open4education
php estruturado
autoload
Globalcode – Open4education
php estruturado autoload
// public/index.php
require_once __DIR__ . '/../config/app.php';
require_once LIBRARY_DIR . '/functions.php';
require_once LIBRARY_DIR . '/models/wishlist.php';
require_once LIBRARY_DIR . '/controllers/wishlist.php';
// include_path is other alternative
ini_set('include_path', __DIR__ . '/../lib');
Globalcode – Open4education
php estruturado composer
{
"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"
]
}
}
Globalcode – Open4education
php estruturado projeto
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
Globalcode – Open4education
php business
Globalcode – Open4education
php business
clareza no código
facilidade de crescimento
testes automatizados
Globalcode – Open4education
php business
testes automatizados
Globalcode – Open4education
php business testes automatizados
garantem regras conhecidas
auxiliam refatoração
não evitam bugs
Globalcode – Open4education
php business phpunit
PHPUnit 5.4.6 by Sebastian Bergmann and contributors.
................................................... 59 / 59 (100%)
Time: 349 ms, Memory: 6.00MB
OK (59 tests, 126 assertions)
Globalcode – Open4education
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.
php business phpunit
Globalcode – Open4education
php business
não confie em arrays
evite abreviações
Globalcode – Open4education
/**
* 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 business array, não confie!
Globalcode – Open4education
php business
objetos de valor
Globalcode – Open4education
php business objetos de valor
são objetos simples
encapsulam tipos primitivos
representam o valor
Globalcode – Open4education
class Status
{
const PENDING = 'P';
const SENT = 'S';
public function __construct($status)
{
$this->validate($status);
$this->status = $status;
}
// … other methods
public function equalsTo(Status $status)
{
return $status === $this;
}
}
php business objetos de valor
Globalcode – Open4education
php business
entidades
Globalcode – Open4education
php business entidades
são mutáveis
possuem identificador
Globalcode – Open4education
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;
}
}
php business entidades
Globalcode – Open4education
class WishlistItem
{
public function __construct(
Id $id,
$name,
Available $isAvailable
) {
$this->id = $id;
$this->name = $name;
$this->available = $isAvailable;
}
}
php business entidades
Globalcode – Open4education
php business
repositórios
Globalcode – Open4education
php business repositórios
camada de persistência
estratégia de armazenamento
Globalcode – Open4education
interface WishlistRepository
{
public function find($id);
public function findAllByEmail($email);
public function add(Wishlist $wishlist);
public function delete(Wishlist $wishlist);
public function findAllToNotify();
}
php business repositórios
Globalcode – Open4education
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']
);
}
}
php business repositórios
Globalcode – Open4education
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);
}
}
php business repositórios
Globalcode – Open4education
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());
}
}
php business repositórios
Globalcode – Open4education
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}"
);
}
}
php business repositórios
Globalcode – Open4education
function wishlistListAction($email)
{
$db = dbConnect();
$factory = new WishlistFactory();
$repository = new WishlistPdoRepository($db, $factory);
$wishlist = $repository->findAllByEmail($email);
include TEMPLATE_DIR . '/wishlists/list.php';
}
php business repositórios
Globalcode – Open4education
php business
serviços
Globalcode – Open4education
php business serviços
camada de operações
orquestram os objetos
definem o que fazer
Globalcode – Open4education
$db = dbConnect();
$factory = new WishlistFactory();
$repository = new WishlistRepository($db, $factory);
$resolver = new ItemResolver(new ProductRepository($db));
try {
$intention = getIntention($request['wish_item']);
$useCase = new AddItemWishlistUseCase(
$repository, $factory, $resolver
);
$wishlist = $useCase->execute($intention);
$successmsg = "{$wishlist->getItemName()} added!";
} catch (Exception $e) {
$errormsg = $e->getMessage();
}
php business serviços
Globalcode – Open4education
class AddItemWishlistUseCase
{
public function execute(AddItemIntention $intention)
{
$item = $this->resolver->resolve($intention->itemId);
try {
$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 business serviços
Globalcode – Open4education
// 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();
$intention = new NotifyProductsAvailableIntention($pending);
$useCase = new NotifyProductsAvailableUseCase($repository, $notifier);
$useCase->execute($intention);
php business serviços
Globalcode – Open4education
class NotifyProductsAvailableUseCase
{
public function __construct($repository, $notifier)
public function execute(NotifyProductsIntention $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);
}
}
}
php business serviços
Globalcode – Open4education
php business
injeção de dependências
Globalcode – Open4education
php business injeção de dependência
princípio da inversão de dependência
dependências configuráveis
Globalcode – Open4education
php business injeção de dependência
Respect/Config
Globalcode – Open4education
// 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]
php business injeção de dependência
Globalcode – Open4education
// 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 validation */) {
wishlistAddAction($container, $_GET['email'], $_POST);
}
php business injeção de dependência
Globalcode – Open4education
function wishlistAddAction(Container $container, $email, $request)
{
try {
$intention = getIntention($request['wish_item']);
$useCase = $container->wishlistAddItemWishlistUseCase;
$wishlist = $useCase->execute($intention);
$successmsg = "{$wishlist->getItemName()} added!";
} catch (Exception $e) {
$errormsg = $e->getMessage();
}
}
php business injeção de dependência
Globalcode – Open4education
php business
eventos
Globalcode – Open4education
php business eventos
mecanismo de inversão de controle
comunicação assíncrona
baixo acoplamento
Globalcode – Open4education
php business eventos
symfony/event-dispatcher
Globalcode – Open4education
class UpdateProductUseCase
{
public function __construct($repository, $factory, $eventDispatcher);
public function execute(Intention $intention)
{
// do something
$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;
}
}
php business eventos
Globalcode – Open4education
class StockListener
{
public function __construct(NotifyProductAvailable $useCase);
public function __invoke(ProductStockIncreasedEvent $event)
{
$productId = $event->getProduct()->getId();
$intention = new NotifyProductIntention($productId);
$this->useCase->execute($intention);
}
}
php business eventos
Globalcode – Open4education
config/app.ini
[wishlistStockListener StockHasIncreasedListener]
useCase = [notifyProductAvailableUseCase]
[eventDispatcher EventDispatcher]
addListener[] = ["product.stock.increased", [wishlistStockListener]]
[productUpdateUseCase UpdateProductUseCase]
__construct = [[repository], [factory], [eventDispatcher]]
php business eventos
Globalcode – Open4education
php business
estrutura
Globalcode – Open4education
camadas
business
use cases
application
web
devices
useinterface
database
ExternalInterfaces
Globalcode – Open4education
// public/wishlist.php
// ...
if (isset($_POST['submit']) && isValidWishList($_POST['wish_item'])) {
$wishItem = getWishList($_POST['wish_item']);
$db->beginTransaction();
try {
$stm = $db->prepare(
'INSERT INTO wishlists (email, product_id) VALUES (?, ?)'
);
$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
Globalcode – Open4education
function wishlistAddAction(Container $container, $email, $request)
{
try {
$intention = getIntention($request['wish_item']);
$useCase = $container->wishlistAddItemWishlistUseCase;
$wishlist = $useCase->execute($intention);
$successmsg = "{$wishlist->getItemName()} added!";
} catch (Exception $e) {
$errormsg = $e->getMessage();
}
}
php business
Globalcode – Open4education
estrutura inicial
developing-for-business
├── cli
│ ├── create_tables.php
│ └── wishlist_notification.php
├── data
│ └── business.db
├── lib
│ ├── dbconn.php
│ └── functions.php
└── public
├── product.php
└── wishlist.phpw
Globalcode – Open4education
estrutura de negócio
developing-for-business
└── src
└── Application
├── Product
│ ├── Controllers
│ └── Repositories
└── ProductWishlist
├── Controllers
├── Listeners
└── Repositories
developing-for-business
└── src
├── Product
│ ├── Events
│ ├── Exceptions
│ ├── Intentions
│ ├── Repositories
│ └── UseCases
└── Wishlist
├── Exceptions
├── Intentions
├── Repositories
└── UseCases
Globalcode – Open4education
conclusão
saia da zona de conforto
testes automatizados
domain driven design
domain specific language
princípio solid
Globalcode – Open4education
Life's too short for bad software
Lew Cirne, New Relic
Globalcode – Open4education
Implementing Domain-Driven Design
by Vaughn Vernon
Patterns of Enterprise Application Architecture
by Martin Fowler
Domain-Driven Design
by Eric Evans
DDD in PHP
by Carlos Buenosvinos, Christian Soronellas and Keyvan Akbary
referências
Globalcode – Open4education
Obrigado
tonicospinelli/developing-for-business
https://joind.in/talk/ad6a7

More Related Content

What's hot

PhpSpec 2.0 ilustrated by examples
PhpSpec 2.0 ilustrated by examplesPhpSpec 2.0 ilustrated by examples
PhpSpec 2.0 ilustrated by examplesMarcello Duarte
 
Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using CodeceptionJeroen van Dijk
 
November Camp - Spec BDD with PHPSpec 2
November Camp - Spec BDD with PHPSpec 2November Camp - Spec BDD with PHPSpec 2
November Camp - Spec BDD with PHPSpec 2Kacper Gunia
 
Introduction to CodeIgniter (RefreshAugusta, 20 May 2009)
Introduction to CodeIgniter (RefreshAugusta, 20 May 2009)Introduction to CodeIgniter (RefreshAugusta, 20 May 2009)
Introduction to CodeIgniter (RefreshAugusta, 20 May 2009)Michael Wales
 
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...Rafael Dohms
 
PHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better CodePHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better CodeSWIFTotter Solutions
 
Curso Symfony - Clase 2
Curso Symfony - Clase 2Curso Symfony - Clase 2
Curso Symfony - Clase 2Javier Eguiluz
 
So S.O.L.I.D Fu - Designing Better Code
So S.O.L.I.D Fu - Designing Better CodeSo S.O.L.I.D Fu - Designing Better Code
So S.O.L.I.D Fu - Designing Better CodeNeil Crookes
 
Crafting beautiful software
Crafting beautiful softwareCrafting beautiful software
Crafting beautiful softwareJorn Oomen
 
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowForget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowKacper Gunia
 
Top 5 Magento Secure Coding Best Practices
Top 5 Magento Secure Coding Best PracticesTop 5 Magento Secure Coding Best Practices
Top 5 Magento Secure Coding Best PracticesOleksandr Zarichnyi
 
Your code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConYour code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConRafael Dohms
 
Zf2 how arrays will save your project
Zf2   how arrays will save your projectZf2   how arrays will save your project
Zf2 how arrays will save your projectMichelangelo van Dam
 
Curso Symfony - Clase 4
Curso Symfony - Clase 4Curso Symfony - Clase 4
Curso Symfony - Clase 4Javier Eguiluz
 
Storytelling By Numbers
Storytelling By NumbersStorytelling By Numbers
Storytelling By NumbersMichael King
 

What's hot (19)

PhpSpec 2.0 ilustrated by examples
PhpSpec 2.0 ilustrated by examplesPhpSpec 2.0 ilustrated by examples
PhpSpec 2.0 ilustrated by examples
 
Dependency Injection
Dependency InjectionDependency Injection
Dependency Injection
 
Refactoring using Codeception
Refactoring using CodeceptionRefactoring using Codeception
Refactoring using Codeception
 
November Camp - Spec BDD with PHPSpec 2
November Camp - Spec BDD with PHPSpec 2November Camp - Spec BDD with PHPSpec 2
November Camp - Spec BDD with PHPSpec 2
 
Zero to SOLID
Zero to SOLIDZero to SOLID
Zero to SOLID
 
What's new with PHP7
What's new with PHP7What's new with PHP7
What's new with PHP7
 
Introduction to CodeIgniter (RefreshAugusta, 20 May 2009)
Introduction to CodeIgniter (RefreshAugusta, 20 May 2009)Introduction to CodeIgniter (RefreshAugusta, 20 May 2009)
Introduction to CodeIgniter (RefreshAugusta, 20 May 2009)
 
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...
“Writing code that lasts” … or writing code you won’t hate tomorrow. - PHP Yo...
 
PHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better CodePHP: 4 Design Patterns to Make Better Code
PHP: 4 Design Patterns to Make Better Code
 
Curso Symfony - Clase 2
Curso Symfony - Clase 2Curso Symfony - Clase 2
Curso Symfony - Clase 2
 
So S.O.L.I.D Fu - Designing Better Code
So S.O.L.I.D Fu - Designing Better CodeSo S.O.L.I.D Fu - Designing Better Code
So S.O.L.I.D Fu - Designing Better Code
 
Crafting beautiful software
Crafting beautiful softwareCrafting beautiful software
Crafting beautiful software
 
Forget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers CracowForget about Index.php and build you applications around HTTP - PHPers Cracow
Forget about Index.php and build you applications around HTTP - PHPers Cracow
 
Top 5 Magento Secure Coding Best Practices
Top 5 Magento Secure Coding Best PracticesTop 5 Magento Secure Coding Best Practices
Top 5 Magento Secure Coding Best Practices
 
Your code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnConYour code sucks, let's fix it - DPC UnCon
Your code sucks, let's fix it - DPC UnCon
 
Zf2 how arrays will save your project
Zf2   how arrays will save your projectZf2   how arrays will save your project
Zf2 how arrays will save your project
 
Curso Symfony - Clase 4
Curso Symfony - Clase 4Curso Symfony - Clase 4
Curso Symfony - Clase 4
 
Storytelling By Numbers
Storytelling By NumbersStorytelling By Numbers
Storytelling By Numbers
 
logic321
logic321logic321
logic321
 

Similar to Developing for Business

Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Michelangelo van Dam
 
Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Michelangelo van Dam
 
CodeIgniter PHP MVC Framework
CodeIgniter PHP MVC FrameworkCodeIgniter PHP MVC Framework
CodeIgniter PHP MVC FrameworkBo-Yi Wu
 
Dealing with Legacy PHP Applications
Dealing with Legacy PHP ApplicationsDealing with Legacy PHP Applications
Dealing with Legacy PHP ApplicationsClinton Dreisbach
 
Hardcore URL Routing for WordPress - WordCamp Atlanta 2014 (PPT)
Hardcore URL Routing for WordPress - WordCamp Atlanta 2014 (PPT)Hardcore URL Routing for WordPress - WordCamp Atlanta 2014 (PPT)
Hardcore URL Routing for WordPress - WordCamp Atlanta 2014 (PPT)Mike Schinkel
 
Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Michelangelo van Dam
 
Workshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfastWorkshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfastMichelangelo van Dam
 
Workshop quality assurance for php projects - ZendCon 2013
Workshop quality assurance for php projects - ZendCon 2013Workshop quality assurance for php projects - ZendCon 2013
Workshop quality assurance for php projects - ZendCon 2013Michelangelo van Dam
 
PHP and Databases
PHP and DatabasesPHP and Databases
PHP and DatabasesThings Lab
 
Gail villanueva add muscle to your wordpress site
Gail villanueva   add muscle to your wordpress siteGail villanueva   add muscle to your wordpress site
Gail villanueva add muscle to your wordpress sitereferences
 
Building Testable PHP Applications
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applicationschartjes
 
WordPress Plugin development
WordPress Plugin developmentWordPress Plugin development
WordPress Plugin developmentMostafa Soufi
 
Becoming a better WordPress Developer
Becoming a better WordPress DeveloperBecoming a better WordPress Developer
Becoming a better WordPress DeveloperJoey Kudish
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐいHisateru Tanaka
 
DDD on example of Symfony (Webcamp Odessa 2014)
DDD on example of Symfony (Webcamp Odessa 2014)DDD on example of Symfony (Webcamp Odessa 2014)
DDD on example of Symfony (Webcamp Odessa 2014)Oleg Zinchenko
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxMichelangelo van Dam
 
Как получить чёрный пояс по WordPress?
Как получить чёрный пояс по WordPress?Как получить чёрный пояс по WordPress?
Как получить чёрный пояс по WordPress?Yevhen Kotelnytskyi
 

Similar to Developing for Business (20)

Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12Workshop quality assurance for php projects tek12
Workshop quality assurance for php projects tek12
 
Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012Quality Assurance for PHP projects - ZendCon 2012
Quality Assurance for PHP projects - ZendCon 2012
 
CodeIgniter PHP MVC Framework
CodeIgniter PHP MVC FrameworkCodeIgniter PHP MVC Framework
CodeIgniter PHP MVC Framework
 
Dealing with Legacy PHP Applications
Dealing with Legacy PHP ApplicationsDealing with Legacy PHP Applications
Dealing with Legacy PHP Applications
 
Hardcore URL Routing for WordPress - WordCamp Atlanta 2014 (PPT)
Hardcore URL Routing for WordPress - WordCamp Atlanta 2014 (PPT)Hardcore URL Routing for WordPress - WordCamp Atlanta 2014 (PPT)
Hardcore URL Routing for WordPress - WordCamp Atlanta 2014 (PPT)
 
Unit testing zend framework apps
Unit testing zend framework appsUnit testing zend framework apps
Unit testing zend framework apps
 
Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8Unit testing after Zend Framework 1.8
Unit testing after Zend Framework 1.8
 
Workshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfastWorkshop quality assurance for php projects - phpbelfast
Workshop quality assurance for php projects - phpbelfast
 
Workshop quality assurance for php projects - ZendCon 2013
Workshop quality assurance for php projects - ZendCon 2013Workshop quality assurance for php projects - ZendCon 2013
Workshop quality assurance for php projects - ZendCon 2013
 
PHP and Databases
PHP and DatabasesPHP and Databases
PHP and Databases
 
Gail villanueva add muscle to your wordpress site
Gail villanueva   add muscle to your wordpress siteGail villanueva   add muscle to your wordpress site
Gail villanueva add muscle to your wordpress site
 
Building Testable PHP Applications
Building Testable PHP ApplicationsBuilding Testable PHP Applications
Building Testable PHP Applications
 
WordPress Plugin development
WordPress Plugin developmentWordPress Plugin development
WordPress Plugin development
 
Becoming a better WordPress Developer
Becoming a better WordPress DeveloperBecoming a better WordPress Developer
Becoming a better WordPress Developer
 
関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい関西PHP勉強会 php5.4つまみぐい
関西PHP勉強会 php5.4つまみぐい
 
Lecture9_OOPHP_SPring2023.pptx
Lecture9_OOPHP_SPring2023.pptxLecture9_OOPHP_SPring2023.pptx
Lecture9_OOPHP_SPring2023.pptx
 
DDD on example of Symfony (Webcamp Odessa 2014)
DDD on example of Symfony (Webcamp Odessa 2014)DDD on example of Symfony (Webcamp Odessa 2014)
DDD on example of Symfony (Webcamp Odessa 2014)
 
Fatc
FatcFatc
Fatc
 
Unit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBeneluxUnit testing with zend framework PHPBenelux
Unit testing with zend framework PHPBenelux
 
Как получить чёрный пояс по WordPress?
Как получить чёрный пояс по WordPress?Как получить чёрный пояс по WordPress?
Как получить чёрный пояс по WordPress?
 

More from Antonio Spinelli

Farming logs to save the weekend
Farming logs to save the weekendFarming logs to save the weekend
Farming logs to save the weekendAntonio Spinelli
 
Substituir Type Codes "com" Classe
Substituir Type Codes "com" ClasseSubstituir Type Codes "com" Classe
Substituir Type Codes "com" ClasseAntonio Spinelli
 
O profissional que você respeita
O profissional que você respeitaO profissional que você respeita
O profissional que você respeitaAntonio Spinelli
 
Compartilhando qualidade e conhecimento com code review
Compartilhando qualidade e conhecimento com code reviewCompartilhando qualidade e conhecimento com code review
Compartilhando qualidade e conhecimento com code reviewAntonio Spinelli
 
modernizando a arquitertura de sua aplicação
modernizando a arquitertura  de sua aplicaçãomodernizando a arquitertura  de sua aplicação
modernizando a arquitertura de sua aplicaçãoAntonio Spinelli
 

More from Antonio Spinelli (6)

Farming logs to save the weekend
Farming logs to save the weekendFarming logs to save the weekend
Farming logs to save the weekend
 
STRUCTured Type Codes
STRUCTured Type CodesSTRUCTured Type Codes
STRUCTured Type Codes
 
Substituir Type Codes "com" Classe
Substituir Type Codes "com" ClasseSubstituir Type Codes "com" Classe
Substituir Type Codes "com" Classe
 
O profissional que você respeita
O profissional que você respeitaO profissional que você respeita
O profissional que você respeita
 
Compartilhando qualidade e conhecimento com code review
Compartilhando qualidade e conhecimento com code reviewCompartilhando qualidade e conhecimento com code review
Compartilhando qualidade e conhecimento com code review
 
modernizando a arquitertura de sua aplicação
modernizando a arquitertura  de sua aplicaçãomodernizando a arquitertura  de sua aplicação
modernizando a arquitertura de sua aplicação
 

Recently uploaded

Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountPuma Security, LLC
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityPrincipled Technologies
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Miguel Araújo
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slidevu2urc
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationMichael W. Hawkins
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonAnna Loughnan Colquhoun
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitecturePixlogix Infotech
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slidespraypatel2
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024BookNet Canada
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhisoniya singh
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationSafe Software
 

Recently uploaded (20)

Breaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path MountBreaking the Kubernetes Kill Chain: Host Path Mount
Breaking the Kubernetes Kill Chain: Host Path Mount
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
Boost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivityBoost PC performance: How more available memory can improve productivity
Boost PC performance: How more available memory can improve productivity
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
Mastering MySQL Database Architecture: Deep Dive into MySQL Shell and MySQL R...
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
Histor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slideHistor y of HAM Radio presentation slide
Histor y of HAM Radio presentation slide
 
GenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day PresentationGenCyber Cyber Security Day Presentation
GenCyber Cyber Security Day Presentation
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
Data Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt RobisonData Cloud, More than a CDP by Matt Robison
Data Cloud, More than a CDP by Matt Robison
 
Understanding the Laravel MVC Architecture
Understanding the Laravel MVC ArchitectureUnderstanding the Laravel MVC Architecture
Understanding the Laravel MVC Architecture
 
🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Slack Application Development 101 Slides
Slack Application Development 101 SlidesSlack Application Development 101 Slides
Slack Application Development 101 Slides
 
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
Transcript: #StandardsGoals for 2024: What’s new for BISAC - Tech Forum 2024
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Diplomatic Enclave | Delhi
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time AutomationFrom Event to Action: Accelerate Your Decision Making with Real-Time Automation
From Event to Action: Accelerate Your Decision Making with Real-Time Automation
 

Developing for Business

  • 1. Globalcode – Open4education Developing for Business Trilha – PHP Architecture
  • 2. Globalcode – Open4education apresentação Antonio Spinelli @tonicospinelli tonicospinelli85@gmail.com
  • 3. Globalcode – Open4education o propósito sempre é o mesmo: resolver problema para o negócio!
  • 5. Globalcode – Open4education comportamento escopo abstrato = problema desconhecido
  • 6. Globalcode – Open4education comportamento agregue valor para negócio entenda a demanda agilidade não é "sobrinhagem"
  • 7. Globalcode – Open4education conhecimento leia código peça e faça code review automatize tarefas repetitivas
  • 8. Globalcode – Open4education user story Lista de Desejos Eu como usuário convidado, quero adicionar um produto esgotado em minha lista de desejos para que eu receba uma notificação quando este estiver disponível. Objetivo reposição mais inteligente de produtos
  • 10. Globalcode – Open4education php estruturado adicionando um item na lista de desejos
  • 11. Globalcode – Open4education // public/wishlist.php // ... if (isset($_POST['submit']) && isValidWishList($_POST['wish_item'])) { $wishItem = getWishList($_POST['wish_item']); $db->beginTransaction(); try { $stm = $db->prepare( 'INSERT INTO wishlists (email, product_id) VALUES (?, ?)' ); $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
  • 12. Globalcode – Open4education php estruturado // public/wishlist.php // ... <table> <?php foreach ($wishlist as $wish): ?> <tr> <td><?php echo $wish['id']; ?> </td> <td><?php echo $wish['product_name']; ?> </td> <?php if ($wish['product_stock'] == 0): ?> <td>Not Available</td> <?php else: ?> <td>Available</td> <?php endif; ?> <td> <?php echo removeUrl($wish['id'], ['email' => $email]); ?> </td> </tr> <?php endforeach; ?> </table> // ...
  • 13. Globalcode – Open4education php estruturado notificar usuário que o item está disponível
  • 14. Globalcode – Open4education php estruturado // 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 $wishlist) { mail( $wishlist['email'], "{$wishlist['product_name']} disponível", $mailBody ); $stm = $db->prepare("UPDATE wishlists SET status='S' WHERE id=?"); $stm->execute([$wishlist['id']]); }
  • 15. Globalcode – Open4education php estruturado Pronto! funciona!
  • 16. Globalcode – Open4education php estruturado quais problemas neste código?
  • 17. Globalcode – Open4education php estruturado organização pobre sem verificação de erro dificuldade de reusar código
  • 18. Globalcode – Open4education php estruturado isolando a apresentação
  • 19. Globalcode – Open4education php estruturado // templates/wishlist/list.php <table> <?php foreach ($wishlist as $wish): ?> <tr> <td><?php echo $wish['id']; ?> </td> <td><?php echo $wish['product_name']; ?> </td> <?php if ($wish['product_stock'] == 0): ?> <td>Not Available</td> <?php else: ?> <td>Available</td> <?php endif; ?> <td> <?php echo removeUrl($wish['id'], ['email' => $email]); ?> </td> </tr> <?php endforeach; ?> </table>
  • 20. Globalcode – Open4education php estruturado isolando regras de negócio
  • 21. Globalcode – Open4education php estruturado function isValidWishList(array $data); function getWishList(array $data); function findAllWishProducts($email); function addWishItem(array $data); function removeWishItem($id); function findAllWishlistsToNotify(); function wishlistNotified($id);
  • 22. Globalcode – Open4education php estruturado interagindo com regra de negócio e apresentação
  • 23. Globalcode – Open4education php estruturado public/wishlist.php require_once __DIR__ . '/../lib/functions.php'; require_once __DIR__ . '/../lib/models/wishlist.php'; require_once __DIR__ . '/../lib/dbconn.php'; if (isset($_POST['submit']) && isValidWishList($_POST['wish_item'])) { $wishItem = getWishList($_POST['wish_item']); if (addWishItem($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';
  • 24. Globalcode – Open4education php estruturado isolando layout
  • 25. Globalcode – Open4education php estruturado // template/layout.php <!DOCTYPE html> <html> <head> <title><?php echo $title ?></title> </head> <body> <?php echo $content ?> </body> </html>
  • 26. Globalcode – Open4education 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' ?>
  • 27. Globalcode – Open4education php estruturado front controller
  • 28. Globalcode – Open4education php estruturado Without a front controller GET /wishlist.php?email=email@test.com With index.php as the front controller GET /index.php/wishlist/email@test.com
  • 29. Globalcode – Open4education php puro front controller // public/index.php // load function files // 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>'; }
  • 30. Globalcode – Open4education php estruturado autoload
  • 31. Globalcode – Open4education php estruturado autoload // public/index.php require_once __DIR__ . '/../config/app.php'; require_once LIBRARY_DIR . '/functions.php'; require_once LIBRARY_DIR . '/models/wishlist.php'; require_once LIBRARY_DIR . '/controllers/wishlist.php'; // include_path is other alternative ini_set('include_path', __DIR__ . '/../lib');
  • 32. Globalcode – Open4education php estruturado composer { "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" ] } }
  • 33. Globalcode – Open4education php estruturado projeto 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
  • 35. Globalcode – Open4education php business clareza no código facilidade de crescimento testes automatizados
  • 36. Globalcode – Open4education php business testes automatizados
  • 37. Globalcode – Open4education php business testes automatizados garantem regras conhecidas auxiliam refatoração não evitam bugs
  • 38. Globalcode – Open4education php business phpunit PHPUnit 5.4.6 by Sebastian Bergmann and contributors. ................................................... 59 / 59 (100%) Time: 349 ms, Memory: 6.00MB OK (59 tests, 126 assertions)
  • 39. Globalcode – Open4education 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. php business phpunit
  • 40. Globalcode – Open4education php business não confie em arrays evite abreviações
  • 41. Globalcode – Open4education /** * 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 business array, não confie!
  • 42. Globalcode – Open4education php business objetos de valor
  • 43. Globalcode – Open4education php business objetos de valor são objetos simples encapsulam tipos primitivos representam o valor
  • 44. Globalcode – Open4education class Status { const PENDING = 'P'; const SENT = 'S'; public function __construct($status) { $this->validate($status); $this->status = $status; } // … other methods public function equalsTo(Status $status) { return $status === $this; } } php business objetos de valor
  • 45. Globalcode – Open4education php business entidades
  • 46. Globalcode – Open4education php business entidades são mutáveis possuem identificador
  • 47. Globalcode – Open4education 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; } } php business entidades
  • 48. Globalcode – Open4education class WishlistItem { public function __construct( Id $id, $name, Available $isAvailable ) { $this->id = $id; $this->name = $name; $this->available = $isAvailable; } } php business entidades
  • 49. Globalcode – Open4education php business repositórios
  • 50. Globalcode – Open4education php business repositórios camada de persistência estratégia de armazenamento
  • 51. Globalcode – Open4education interface WishlistRepository { public function find($id); public function findAllByEmail($email); public function add(Wishlist $wishlist); public function delete(Wishlist $wishlist); public function findAllToNotify(); } php business repositórios
  • 52. Globalcode – Open4education 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'] ); } } php business repositórios
  • 53. Globalcode – Open4education 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); } } php business repositórios
  • 54. Globalcode – Open4education 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()); } } php business repositórios
  • 55. Globalcode – Open4education 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}" ); } } php business repositórios
  • 56. Globalcode – Open4education function wishlistListAction($email) { $db = dbConnect(); $factory = new WishlistFactory(); $repository = new WishlistPdoRepository($db, $factory); $wishlist = $repository->findAllByEmail($email); include TEMPLATE_DIR . '/wishlists/list.php'; } php business repositórios
  • 57. Globalcode – Open4education php business serviços
  • 58. Globalcode – Open4education php business serviços camada de operações orquestram os objetos definem o que fazer
  • 59. Globalcode – Open4education $db = dbConnect(); $factory = new WishlistFactory(); $repository = new WishlistRepository($db, $factory); $resolver = new ItemResolver(new ProductRepository($db)); try { $intention = getIntention($request['wish_item']); $useCase = new AddItemWishlistUseCase( $repository, $factory, $resolver ); $wishlist = $useCase->execute($intention); $successmsg = "{$wishlist->getItemName()} added!"; } catch (Exception $e) { $errormsg = $e->getMessage(); } php business serviços
  • 60. Globalcode – Open4education class AddItemWishlistUseCase { public function execute(AddItemIntention $intention) { $item = $this->resolver->resolve($intention->itemId); try { $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 business serviços
  • 61. Globalcode – Open4education // 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(); $intention = new NotifyProductsAvailableIntention($pending); $useCase = new NotifyProductsAvailableUseCase($repository, $notifier); $useCase->execute($intention); php business serviços
  • 62. Globalcode – Open4education class NotifyProductsAvailableUseCase { public function __construct($repository, $notifier) public function execute(NotifyProductsIntention $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); } } } php business serviços
  • 63. Globalcode – Open4education php business injeção de dependências
  • 64. Globalcode – Open4education php business injeção de dependência princípio da inversão de dependência dependências configuráveis
  • 65. Globalcode – Open4education php business injeção de dependência Respect/Config
  • 66. Globalcode – Open4education // 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] php business injeção de dependência
  • 67. Globalcode – Open4education // 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 validation */) { wishlistAddAction($container, $_GET['email'], $_POST); } php business injeção de dependência
  • 68. Globalcode – Open4education function wishlistAddAction(Container $container, $email, $request) { try { $intention = getIntention($request['wish_item']); $useCase = $container->wishlistAddItemWishlistUseCase; $wishlist = $useCase->execute($intention); $successmsg = "{$wishlist->getItemName()} added!"; } catch (Exception $e) { $errormsg = $e->getMessage(); } } php business injeção de dependência
  • 70. Globalcode – Open4education php business eventos mecanismo de inversão de controle comunicação assíncrona baixo acoplamento
  • 71. Globalcode – Open4education php business eventos symfony/event-dispatcher
  • 72. Globalcode – Open4education class UpdateProductUseCase { public function __construct($repository, $factory, $eventDispatcher); public function execute(Intention $intention) { // do something $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; } } php business eventos
  • 73. Globalcode – Open4education class StockListener { public function __construct(NotifyProductAvailable $useCase); public function __invoke(ProductStockIncreasedEvent $event) { $productId = $event->getProduct()->getId(); $intention = new NotifyProductIntention($productId); $this->useCase->execute($intention); } } php business eventos
  • 74. Globalcode – Open4education config/app.ini [wishlistStockListener StockHasIncreasedListener] useCase = [notifyProductAvailableUseCase] [eventDispatcher EventDispatcher] addListener[] = ["product.stock.increased", [wishlistStockListener]] [productUpdateUseCase UpdateProductUseCase] __construct = [[repository], [factory], [eventDispatcher]] php business eventos
  • 75. Globalcode – Open4education php business estrutura
  • 76. Globalcode – Open4education camadas business use cases application web devices useinterface database ExternalInterfaces
  • 77. Globalcode – Open4education // public/wishlist.php // ... if (isset($_POST['submit']) && isValidWishList($_POST['wish_item'])) { $wishItem = getWishList($_POST['wish_item']); $db->beginTransaction(); try { $stm = $db->prepare( 'INSERT INTO wishlists (email, product_id) VALUES (?, ?)' ); $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
  • 78. Globalcode – Open4education function wishlistAddAction(Container $container, $email, $request) { try { $intention = getIntention($request['wish_item']); $useCase = $container->wishlistAddItemWishlistUseCase; $wishlist = $useCase->execute($intention); $successmsg = "{$wishlist->getItemName()} added!"; } catch (Exception $e) { $errormsg = $e->getMessage(); } } php business
  • 79. Globalcode – Open4education estrutura inicial developing-for-business ├── cli │ ├── create_tables.php │ └── wishlist_notification.php ├── data │ └── business.db ├── lib │ ├── dbconn.php │ └── functions.php └── public ├── product.php └── wishlist.phpw
  • 80. Globalcode – Open4education estrutura de negócio developing-for-business └── src └── Application ├── Product │ ├── Controllers │ └── Repositories └── ProductWishlist ├── Controllers ├── Listeners └── Repositories developing-for-business └── src ├── Product │ ├── Events │ ├── Exceptions │ ├── Intentions │ ├── Repositories │ └── UseCases └── Wishlist ├── Exceptions ├── Intentions ├── Repositories └── UseCases
  • 81. Globalcode – Open4education conclusão saia da zona de conforto testes automatizados domain driven design domain specific language princípio solid
  • 82. Globalcode – Open4education Life's too short for bad software Lew Cirne, New Relic
  • 83. Globalcode – Open4education Implementing Domain-Driven Design by Vaughn Vernon Patterns of Enterprise Application Architecture by Martin Fowler Domain-Driven Design by Eric Evans DDD in PHP by Carlos Buenosvinos, Christian Soronellas and Keyvan Akbary referências