This is just a quick response to http://me.veekun.com/blog/2012/07/28/quick-doesnt-mean-dirty/. I won't bother to write a proper blog post for this, so a Gist will have to do ;)
When I read that article, one thing really striked me: If you want to quickly create a web app in PHP, you do exactly the same. I mean, exactly.
I never used the Silex microframework before, so I took this as a chance to see how it works. I'll just do the same as eevee did, only with a bit less commentary (this is a Gist after all!)
I hope that this will show you that PHP and Python are really similar to work with. Also this should show that just because you're using PHP, doesn't mean that you write dirty code. The similarity in the process and code is really incredible :)
First create the project:
curl -s https://getcomposer.org/installer | php
php composer.phar create-project fabpot/silex-skeleton guestbook
cd guestbook/
Run php -S localhost:8888 -t web/
to start the webserver. You'll find a friendly Hello World message if you visit localhost:8888/index_dev.php
in your browser.
Then create a git repo:
rm -rf .git
git init
git add -A
git commit -m "Initial commit"
There are already two templates in the templates/ folder, we just modify them a bit to match eevee's code:
vim templates/layout.html
<!DOCTYPE html>
<html>
<head>
<title>{% block title '' %} - My Awesome Site</title>
<link href="{{ app.request.basepath }}/css/main.css" rel="stylesheet" type="text/css" />
</head>
<body>
<section id="content">
{% block content %}{% endblock %}
</section>
<footer id="footer">
My awesome guestbook
</footer>
</body>
</html>
vim index.html
{% extends "layout.html" %}
{% block title %}Guestbook{% endblock %}
{% block content %}
<h1>Guestbook</h1>
<p>Welcome to my guestbook!</p>
<ul class="guests">
<li>...</li>
</ul>
{% endblock %}
That doesn't give us much yet, we need to create some kind of database. To save me the installation of mysql I'll use sqlite:
vim src/app.php (addition)
<?php
$app['db'] = $app->share(function() {
$pdo = new PDO('sqlite:' . __DIR__ . '/../db.sq3');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
return $pdo;
});
Also create a console task to create the table structure (there is already a skeleton in the file, so I don't even have to look at docs):
vim src/console.php (change)
<?php
$console
->register('create-db')
->setDescription('Create database tables')
->setCode(function (InputInterface $input, OutputInterface $output) use ($app) {
$app['db']->query(
"CREATE TABLE guestbook (
id INTEGER PRIMARY KEY AUTOINCREMENT,
timestamp TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
name TEXT, message TEXT
);
CREATE INDEX timestamp_index ON guestbook (timestamp);"
);
$output->writeln('Created database!');
})
;
Now we can create the DB using ./console create-db
.
Oh, and yeah, I hate ORMs, I prefer raw SQL.
Next let's modify the template to actually display something:
vim templates/index.html (change)
<ul class="guests">
{% for entry in entries %}
<li>
<blockquote>{{ entry.message }}</blockquote>
<p> —<cite>{{ entry.name }}</cite>, <time>{{ entry.timestamp }}</time></p>
</li>
{% endfor %}
</ul>
And adjust the controller for this:
vim src/app.php
<?php
$app->get('/', function () use ($app) {
return $app['twig']->render('index.html', array(
'entries' => $app['db']->query(
'SELECT * FROM guestbook ORDER BY timestamp DESC'
)
));
})
Finally, let's add the code for adding new guestbook entries:
vim templates/index.html
<hr>
<form action="" method="POST">
<p>Name: <input type="text" name="name"></p>
<p>Message: <textarea name="message" rows="10" cols="40"></textarea></p>
<p><button>Sign</button></p>
</form>
vim src/controllers.php
<?php
$app->post('/', function (Request $req) use ($app) {
$app['db']->prepare(
'INSERT INTO guestbook (name, message) VALUES (?, ?)'
)->execute(array(
$req->request->get('name') ?: 'Some dummy who forgot to leave a name',
$req->request->get('message') ?: 'WOW THIS IS THE BEST WEBSITE EVER',
));
return $app->redirect('/');
});
Again, you can see the page using the php -S localhost:8888 -t web/
webserver. It is safe against XSS and SQLi, just like the Python code (the template engine does automatic escaping and we used prepared statements).
I won't bother with deployment here. You could obviously just deploy to Heroku, exactly as you did with Python. Or just upload it to some freespace via FTP. Whatever.
=====
Thanks for listening,
~nikic (http://nikic.github.com/, https://twitter.com/nikita_ppv)
And all these dependencies for a guestbook?
Cloning 337af0c031195d58a5502358ab78c4f30caa7fd0
Cloning v2.1.0-BETA4
Cloning v2.1.0-BETA4
Cloning v2.1.0-BETA4
Cloning v2.1.0-BETA4
Cloning cb15ab7da9a69b123433c4edca68e23564345a31
Cloning 7c328a9752ac035fe38dfae5425cf66b905c5394
Cloning v2.1.0-BETA4
Cloning 7fe9695cb1dae09df7f545aabed8fa4b0026108b
Cloning d839487dafd0e69b3e67b5819caa11a9bb85f215
Cloning d6f016c243105b365a80da60b049ea884b002ecd
Cloning 1f83baa5096b87e85149a933df46881cce04787c
Cloning 7278cfeeb168654bcd148127796cfcd504a30dbe
Cloning 554ad6bb1448fdd54274a061d6a9ee8951284078
Cloning 3ee2b629bc1fcac1d90bf76c251b31ee6acd4704
Cloning 1e9873087f35a730d8d8d01050efbde724e76815