It looks like you are viewing these slides on GitHub. Please clone the source repository in order to get the included PHP examples to work.
He's good, alright. But he's no Clem Johnson. And Johnson played back in the days before steroid injections were mandatory.
<?php
class Router {
protected $request;
protected $response;
public function __construct($path) {
$this->request = new Request();
$this->response = new Response();
$this->path = $path;
// …
}
}
$router = new Router('/hello');
var_dump($router);
<?php
class Router {
protected $request;
protected $response;
public function __construct(Request $request, Response $response, $path) {
$this->request = $request;
$this->response = $response;
$this->path = $path;
}
}
$request = new Request();
$reponse = new Response();
$router = new Router($request, $response, '/hello');
var_dump($router);
Router
) to the one calling (you).
class Container {
protected $dependencies = [];
public function set($name, $val) {
$this->dependencies[$name] = $val;
}
public function get($name) {
return isset($this->dependencies[$name]) ? (is_callable($this->dependencies[$name]) ? $this->dependencies[$name]() : $this->dependencies[$name]) : null;
}
}
// Router Class
class Router {
protected $request;
protected $response;
public function __construct(Request $request, Response $response, $path) {
$this->request = $request;
$this->response = $response;
$this->path = $path;
}
}
// Create DiC
$container = new Container();
// Tell DiC how to create dependencies
$container->set('request', function() {
return new Request();
});
$container->set('response', function() {
return new Response();
});
// Create a router, injecting the dependencies
$router = new Router($container->get('request'), $container->get('response'), '/hello');
A
requires A
and B
requires C
A
from the DiC, it should create all required dependencies (B
and C
)class ServiceLocator {
protected $dependencies = [];
public function set($name, $val) {
$this->dependencies[$name] = $val;
}
public function get($name) {
return isset($this->dependencies[$name]) ? (is_callable($this->dependencies[$name]) ? $this->dependencies[$name]() : $this->dependencies[$name]) : null;
}
}
// Router Class
class Router {
protected $request;
protected $response;
public function __construct(ServiceLocator $sl, $path) {
$this->request = $sl->get('request');
$this->response = $sl->get('response');
$this->path = $path;
}
}
// Create SL
$sl = new ServiceLocator();
// Tell DiC how to create dependencies
$sl->set('request', function() {
return new Request();
});
$sl->set('response', function() {
return new Response();
});
// Create a router, injecting the dependencies
$router = new Router($sl, '/hello');
I'll make you cry, buddy. You're a pimple on society's ass and you'll never amount to anything.
<?php
namespace Silex;
…
class Application extends \Pimple implements … {
…
}
<?php
require_once '/path/to/pimple.php';
$container = new Pimple();
Silex\Application
extends \Pimple
, our $app
also is an instance of (a special type of) \Pimple
<?php
…
$app = new Silex\Application();
$app['some_parameter'] = 'value';
echo $app['some_parameter']; // value
A service is an object that does something as part of a larger system. […] Almost any global object can be a service.
$app['some_service'] = function () {
return new Whatever();
};
$service = $app['some_service'];
$app['some_service']
, a new instance of the service is created.By default, each time you get a service, Pimple returns a new instance of it. If you want the same instance to be returned for all calls, use a shared service.
$app['some_service'] = $app->share(function () {
return new Whatever();
});
$service = $app['some_service'];
require 'facebook-php-sdk/src/facebook.php';
$facebook = new \Facebook(array(
'appId' => 'YOUR_APP_ID',
'secret' => 'YOUR_APP_SECRET',
));
// Get User ID
$user = $facebook->getUser();
Facebook
object as a dependency of our Silex $app
.
bootstrap.php
$app['facebook.app_id'] = 'YOUR_APP_ID';
$app['facebook.secret'] = 'YOUR_APP_SECRET';
$app['facebook'] = $app->share(function($app) {
return new \Facebook(array(
'appId' => $app['facebook.app_id'],
'secret' => $app['facebook.secret']
));
});
$app->get('/', function(Silex\Application $app) {
$user = $app['facebook']->getUser();
return $app->json($user);
});
Final boarding call for Flight 406, non-stop service to pain!
app.php
with routing logicbootstrap.php
with dependency injectionsFrom the Silex Docs:
This is very straight forward, just create a new class that implements two methods. In theregister()
method, you can define services on the application which then may make use of other services and parameters. In theboot()
method, you can configure the application, just before it handles a request.
ControllerProvider
but different interface/methods
namespace MyNamespace\Provider\Service;
use Silex\Application;
use Silex\ServiceProviderInterface;
class WhateverServiceProvider implements ServiceProviderInterface {
public function register(Application $app) {
// Store the service on Pimple
$app['whatever'] = >share(function() {
return new Whatever();
}
}
public function boot(Application $app) { … }
}
/src/MyNamespace/Provider/Service
$app
using
$app->register(new MyNamespace\Provider\Service\WhateverServiceProvider(), []);
FacebookServiceProvider.php
)
<?php
namespace Ikdoeict\Provider\Service;
use Silex\Application;
use Silex\ServiceProviderInterface;
class FacebookServiceProvider implements ServiceProviderInterface {
public function register(Application $app) {
$app['facebook'] = $app->share(function() use ($app) {
return new \Facebook(array(
'appId' => $app['facebook.app_id'],
'secret' => $app['facebook.secret']
));
});
}
public function boot(Application $app) {}
}
bootstrap.php
)
$app->register(new Ikdoeict\Provider\Service\FacebookServerProvider(), array(
'facebook.app_id' => 'YOUR_APP_ID',
'facebook.secret' => 'YOUR_APP_SECRET'
));
app.php
)
$app->get('/', function(Silex\Application $app) {
$user = $app['facebook']->getUser();
return $app->json($user);
});
$ composer require twig/twig:~1.8
bootstrap.php
$app->register(new Silex\Provider\TwigServiceProvider(), array(
'twig.path' => __DIR__ . '/views',
));
$app->get('/hello/{name}', function ($name) use ($app) {
return $app['twig']->render('hello.twig', array(
'name' => $name,
));
});
Let's take a look at assets/ws2-sws-fiddles-silex/05.tweets-twig/
→
/src/views/
/src/views/errors/
: 404.twig
/src/views/tweets/
: overview.twig
& detail.twig
/src/views
: layout.twig
$app['twig']
{{ app.request.baseUrl }}
$ composer require swiftmailer/swiftmailer:~5.0
bootstrap.php
$app->register(new Silex\Provider\SwiftmailerServiceProvider(), array(
'swiftmailer.options' => array(
'host' => 'host',
'port' => '25',
'username' => 'username',
'password' => 'password',
'encryption' => null,
'auth_mode' => null
)
));
$app->post('/feedback', function () use ($app) {
$request = $app['request'];
$message = \Swift_Message::newInstance()
->setSubject('[YourSite] Feedback')
->setFrom(array('noreply@yoursite.com'))
->setTo(array('feedback@yoursite.com'))
->setBody($request->get('message'));
$app['mailer']->send($message);
return new Response('Thank you for your feedback!', 201);
});
$ composer require doctrine/dbal:~2.2
bootstrap.php
$app->register(new Silex\Provider\DoctrineServiceProvider(), array(
'db.options' => array(
'driver' => 'pdo_mysql',
'host' => 'localhost',
'dbname' => 'todolist',
'user' => 'root',
'password' => 'Azerty123',
'charset' => 'utf8mb4'
)
));
$app->get('/blog/{id}', function ($id) use ($app) {
$sql = 'SELECT * FROM posts WHERE id = ?';
$post = $app['db']->fetchAssoc($sql, array($id));
return '<h1>' . $app->escape($post['title']) . '</h1>'.
'<p>' . $app->escape($post['body']) . '</p>';
})->assert('id', '\d+');
Let's take a look at assets/ws2-sws-fiddles-silex/06.doctrine/
→
Uh oh, I think we're going in circles. I recognize that pattern of striations on that gypsum formation.
→ If we can split out our data access logic,
we can strive towards MVC
Knp\Repository
class which you extend per entity
insert()
, update()
, delete()
, find()
, or findAll()
functionsRepositoryServiceProvider
for use with Silex
"require": {
"knplabs/repository-service-provider": "dev-master"
}
Knp\Repository
class
<?php
namespace Knp;
use Doctrine\DBAL\Connection;
abstract class Repository {
abstract public function getTableName();
public $db;
public function __construct(Connection $db) {
$this->db = $db;
}
public function insert(array $data) {
return $this->db->insert($this->getTableName(), $data);
}
public function update(array $data, array $identifier) {
return $this->db->update($this->getTableName(), $data, $identifier);
}
public function delete(array $identifier) {
return $this->db->delete($this->getTableName(), $identifier);
}
public function find($id) {
return $this->db->fetchAssoc(sprintf('SELECT * FROM %s WHERE id = ? LIMIT 1', $this->getTableName()), array((int) $id));
}
public function findAll() {
return $this->db->fetchAll(sprintf('SELECT * FROM %s', $this->getTableName()));
}
}
namespace Ikdoeict\Repository;
class TweetsRepository extends \Knp\Repository {
public function getTableName() { return 'tweets'; }
}
$app->register(new Knp\Provider\RepositoryServiceProvider(), array(
'repository.repositories' => array(
'db.tweets' => 'Ikdoeict\\Repository\\TweetsRepository'
)
));
$app['db.tweets']->findAll();
Let's take a look at assets/ws2-sws-fiddles-silex/07.doctrine-organized/
→
/src/Namespace/Repository
TweetsRepository
recommended
\Knp\Provider
getTableName
function must return the DB table name
RepositoryServiceProvider
db.
as a prefixNot sure if ...