001100010010011110100001101101110011
$app->get('/', function () {
return 'welcome to the homepage';
})->bind('homepage');
$app->get('/hello/{name}', function ($name) {
return "Hello $name!";
})->bind('hello');
symfony/twig-bridge
in composer.json
"require": {
"symfony/twig-bridge": "2.*"
}
bootstrap.php
$app->register(new Silex\Provider\UrlGeneratorServiceProvider());
$app['url_generator']->generate('homepage');
$app['url_generator']->generate('hello', array('name' => 'Bramus'));
// -> `/hello/Bramus`
{{ app.url_generator.generate('homepage') }}
twig-bridge
{{ path('homepage') }} {# -> `/` #}
{{ url('homepage') }} {# -> `http://example.org/` #}
{{ path('hello', {name: 'Bramus'}) }} {# -> `/hello/Bramus` #}
{{ url('hello', {name: 'Bramus'}) }} {# -> `http://example.org/hello/Bramus` #}
app.php
)
$pages = array(
'/' => 'home',
'/about' => 'about'
);
foreach ($pages as $route => $view) {
$app->get($route, function () use ($app, $view) {
return $app['twig']->render('static/' . $view . '.twig');
})->bind($view);
}
}
Let's take a look at assets/ws2-sws-fiddles-silex/08.static-pages/
→
/src/views/static/
bind()
within the connect()
function of the controller
{{ app.request.baseUrl }}
in Twig anymore as {{ path('links') }}
includes it
app.request.getPathInfo()|split('/')[1]
Captain's log: We have lost control of the ship.
Adddendum: Whoooaaaa!
DEBUG
(100)
INFO
(200)
NOTICE
(250)
WARNING
(300)
ERROR
(400)
CRITICAL
(500)
ALERT
(550)
EMERGENCY
(600)
monolog/monolog
in composer.json
"require": {
"monolog/monolog": ">=1.0.0"
}
bootstrap.php
$app->register(new Silex\Provider\MonologServiceProvider(), array(
'monolog.logfile' => __DIR__ . '/development.log',
));
monolog.logfile
— Location of logfilemonolog.level
(optional) — Minimum log level before event is written in log. Default: Monolog\Logger::DEBUG
monolog.name
(optional) — Name of the monolog channel.myapp
$app['monolog']
$app['monolog']->addDebug('Testing the Monolog logging.');
$app['monolog']->addInfo(sprintf('User "%s" registered.', $username));
$app['monolog']->addWarning('The use of global is deprecated');
$app['monolog']->addError('Could not update item in database');
[2013-03-25 15:12:55] myapp.DEBUG: Testing the Monolog logging.
[2013-03-25 15:12:56] myapp.INFO: User "Bramus" registered.
[2013-03-25 15:12:57] myapp.WARNING: The use of global is deprecated
[2013-03-25 15:12:58] myapp.ERROR: Could not update item in database
OK. We're in the middle of nowhere,
which is the safest part of nowhere.
A before application middleware allows you to tweak the Request before the controller is executed
$app->before(function (Request $request) use ($app) {
$app['twig']->addGlobal('first_url_part', explode('/', $request->getPathInfo())[1]);
});
$app->before(function (Request $request) use ($app) {
// ...
}, Application::EARLY_EVENT);
An after application middleware allows you to tweak the Response before it is sent to the client
$app->after(function (Request $request) use ($app) {
// ...
});
A finish application middleware allows you to execute tasks after the Response has been sent to the client (like sending emails or logging)
$app->finish(function (Request $request, Response $response) {
// Warning: modifications to the Request or Response will be ignored
});
Let's take a look at assets/ws2-sws-fiddles-silex/09.middlewares/
→
A before route middleware is fired just before the route callback, but after the before application middlewares
$app->get('/somewhere', function () {
// ...
})->before(function (Request $request) use ($app) {
// ...
});
public function connect(Application $app) {
return $app['controllers_factory']->get('/somewhere',
array($this,'somewhere'))->before(array($this,'check'));
}
public function check(Request $request, Application $app) { /* ... */ }
An after route middleware is fired just after the route callback, but before the application its after application middlewares
$app->get('/somewhere', function () {
// ...
})->after(function (Request $request, Response $response) use ($app) {
// ...
});
See further ;-)
I am the grand funeral director.
— Do you validate parking?
symfony/validator
in composer.json
"require": {
"symfony/validator": "~2.3"
}
bootstrap.php
$app->register(new Silex\Provider\ValidatorServiceProvider());
\Symfony\Component\Validator\Constraints
⚑
Don't use the following examples to base your code upon. Only use them to get the gist of the constraints. When working with forms we'll use an other structure!
$app['validator']->validateValue($val, constraints);
use Symfony\Component\Validator\Constraints as Assert;
$app->get('/validate/{email}', function ($email) use ($app) {
$errors = $app['validator']->validateValue($email, new Assert\Email());
if (count($errors) > 0) {
return (string) $errors;
} else {
return 'The email is valid';
}
});
use Symfony\Component\Validator\Constraints as Assert;
$book = array(
'title' => 'My Book',
'author' => array(
'first_name' => 'Fabien',
'last_name' => 'Potencier',
),
);
$constraints = new Assert\Collection(array(
'title' => new Assert\Length(array('min' => 10)),
'author' => new Assert\Collection(array(
'first_name' => array(
new Assert\NotBlank(),
new Assert\Length(array('min' => 10))
),
'last_name' => new Assert\Length(array('min' => 10)),
)),
));
$errors = $app['validator']->validateValue($book, $constraints);
if (count($errors) > 0) {
foreach ($errors as $error) {
echo $error->getPropertyPath().' '.$error->getMessage()."\n";
}
} else {
echo 'The book is valid';
}
Guards! ... bring me the forms I need
to fill out to have her taken away!
symfony/form
and symfony/twig-bridge
in composer.json
"require": {
"symfony/form": "~2.3"
"symfony/twig-bridge": "~2.3"
}
bootstrap.php
$app->register(new Silex\Provider\FormServiceProvider());
$app['form.factory']
to get an instance of Symfony's FormFactory
$app->match('/form', function (Request $request) use ($app) {
// some default data for when the form is displayed the first time
$data = array(
'name' => 'Your name',
'email' => 'Your email',
'message' => 'Your message'
);
// Get the form
$form = $app['form.factory']->createBuilder('form', $data)
->add('name', 'text')
->add('email', 'email')
->add('message', 'textarea')
->getForm();
// Inspects the given request to see if the form was submitted or not
// If so it will transform and validate the data
$form->handleRequest($request);
// The form was submitted and is valid!
if ($form->isValid()) {
// Get the data
$data = $form->getData();
// Do something with the data
// …
// redirect somewhere
return $app->redirect('...');
}
// display the form
return $app['twig']->render('index.twig', array('form' => $form->createView()));
});
<form action="#" method="post" {{ form_enctype(form) }}>
{{ form_widget(form) }}
<input type="submit" name="submit" />
</form>
<form action="#" method="post">
<div id="form">
<div>
<label for="form_name">Name</label>
<input type="text" id="form_name" name="form[name]" value="Your name">
</div>
<div>
<label for="form_email">Email</label>
<input type="text" id="form_email" name="form[email]" value="Your email">
</div>
<div>
<label for="form_message">Message</label>
<textarea id="form_message" name="form[message]">Your message</textarea>
</div>
<input type="hidden" id="form_token" name="form[_token]" value="bdb2fdb025d2a20fa21e4a3cbc6c8fda8051e020">
</div>
<input type="submit" name="submit" />
</form>
A CSRF attack forces a logged-on victim’s browser to send a forged HTTP request, including the victim’s session cookie and any other automatically included authentication information, to a vulnerable web application. This allows the attacker to force the victim’s browser to generate requests the vulnerable application thinks are legitimate requests from the victim.
$loginform = $app['form.factory']->createNamed('loginform')
->add('username', 'text')
->add('password', 'password');
$data = array('username' => 'root', 'password' => 'Azerty123');
$loginform = $app['form.factory']->createNamed('loginform', 'form', $data)
->add('username', 'text')
->add('password', 'password');
<form action="#" method="post" {{ form_enctype(loginform) }}>
<dl class="clearfix">
<dt>
{{ form_label(loginform.username) }}
</dt>
<dd>
{{ form_widget(loginform.username) }}
{{ form_errors(loginform.username) }}
</dd>
<dt>
{{ form_label(loginform.password) }}
</dt>
<dd>
{{ form_widget(loginform.password) }}
{{ form_errors(loginform.password) }}
</dd>
</dl>
{{ form_widget(loginform._token) }}
<input type="submit" name="submit" value="Log In" />
</form>
use Symfony\Component\Validator\Constraints as Assert;
…
$loginform = $app['form.factory']->createNamed('loginform', 'form', $data)
->add('username', 'text', array(
'constraints' => new Assert\Email()
))
->add('password', 'password', array(
'constraints' => array(
new Assert\NotBlank(),
new Assert\Length(array('max' => 30))
)
));
composer.json
though
"require": {
"symfony/form": "~2.3",
"symfony/validator": "~2.3",
"symfony/twig-bridge": "~2.3",
"symfony/config": "~2.3",
"symfony/translation": "~2.3"
}
bootstrap.php
(with emtpy messages) or it won't work
$app->register(new Silex\Provider\TranslationServiceProvider(), array(
'translator.messages' => array(),
));
Let's take a look at assets/ws2-sws-fiddles-silex/10.forms-validation/
→
novalidate
attribute to the form to prevent HTML5 formchecking.
label
or from within Twig
$addlinkform->add('url', 'url', array('label' => 'The URL'));
{{ form_row(addlinkform.url, { 'label': 'The URL' }) }}
date
as a type
widget
to single_text
to get one single textfield
format
$registerform->add('date', 'date', array(
'widget' => 'single_text',
'format' => 'YYYY-mm-dd'
));
if (!$registerform->get('email')->isValid()) { … }
$addlinkform->addError(new \Symfony\Component\Form\FormError('That link was already entered'));
{{ form_errors(addlinkform) }}
{{ form_widget(addlinkform.title) }}
{{ form_widget(addlinkform.url) }}
{{ form_widget(addlinkform._token) }}
$app->match('/', function (Application $app) {
$uploadform = $app['form.factory']
->createNamed('uploadform')
->add('my_upload', 'file', array(
'constraints' => new Assert\NotBlank()
));
$uploadform->handleRequest($app['request']);
if ($uploadform->isValid()) {
$files = $app['request']->files->get($uploadform->getName());
$filename = $files['my_upload']->getClientOriginalName();
$files['my_upload']->move(__DIR__ . '/../public_html/uploads/', $filename);
return $app['twig']->render('form.twig', array(
'message' => 'File was successfully uploaded!',
'uploadform' => $uploadform->createView()
));
}
return $app['twig']->render('form.twig', array(
'message' => 'Upload a file',
'uploadform' => $uploadform->createView()
));
})->method('GET|POST');
Let's take a look at assets/ws2-sws-fiddles-silex/11.session-upload/
→
Now Stop! Hammertime!
bootstrap.php
$app->register(new Silex\Provider\SessionServiceProvider());
$app['session']
to get and set session data
$app['session']->set('name', 'Bramus');
echo $app['session']->get('name'); // Bramus
Again take a look at assets/ws2-sws-fiddles-silex/11.session-upload/
→
If we can re-route engine power through the primary weapons and configure them to Melllvar's frequency, that should overload his electro-quantum structure.
define()
use the custom ConfigServiceProvider⚑$app
igorw/config-service-provider
in composer.json
"require": {
"igorw/config-service-provider": "~1.1"
}
bootstrap.php
referencing the config
$app->register(new Igorw\Silex\ConfigServiceProvider(__DIR__ . '/config.php'));
return array(
'db.options' => array(
'dbname' => 'todolist',
'user' => 'root',
'password' => 'Azerty123',
'host' => 'localhost',
'driver' => 'pdo_mysql',
'charset' => 'utf8mb4'
),
'myproject.test' => array(
'param2' => '456',
'param3' => array(
'param2B' => '456',
'param2C' => '456',
),
'param4' => array(4, 5, 6)
)
);
{
"db.options": {
"dbname": "todolist",
"user": "root",
"password": "Azerty123",
"host": "localhost",
"driver": "pdo_mysql",
"charset": "utf8mb4"
},
"myproject.test": {
"param2": "456",
"param3": {
"param2B": "456",
"param2C": "456"
},
"param4": [4, 5, 6]
}
}
---
db.options:
dbname: "todolist"
user: "root"
password: "Azerty123"
host: "localhost"
driver: "pdo_mysql"
charset: "utf8mb4"
myproject.test:
param2: "456"
param3:
param2B: "456"
param2C: "456"
param4:
- 4
- 5
- 6
$app['db.options']['user']