Skip to content

Instantly share code, notes, and snippets.

@k-holy
Created October 28, 2011 04:26
Show Gist options
  • Save k-holy/1321620 to your computer and use it in GitHub Desktop.
Save k-holy/1321620 to your computer and use it in GitHub Desktop.
Silex PhpTalServiceProvider + RedBean
<!DOCTYPE html>
<html>
<head metal:define-macro="head">
<meta charset="UTF-8" />
<link rel="stylesheet" media="screen" href="/css/base.css" />
<script src="/js/jquery-1.6.2.min.js"></script>
<tal:block metal:define-slot="head-extra"></tal:block>
<title tal:content="title">Title</title>
</head>
<body metal:define-macro="body">
<div id="header">
<h1>Silex + RedBeanPHP + PHPTAL CRUD Examples</h1>
</div>
<div id="container">
<div id="menu" metal:define-slot="menu">
<ul>
<li><a href="/profiles/">人物一覧</a></li>
<li><a href="/profiles/register">人物登録</a></li>
</ul>
</div>
<h2 tal:content="title">画面名</h2>
<p class="message" tal:condition="exists:message" tal:content="message">Flashメッセージ</p>
<div id="main" metal:define-slot="main">
メイン
</div>
</div>
<div id="footer">
Copyright &copy; k-holy &lt;k.holy74@gmail.com&gt;
</div>
</body>
</html>
<?php
/**
* PHP versions 5
*
* @copyright 2011 k-holy <k.holy74@gmail.com>
* @author k.holy74@gmail.com
* @license http://www.opensource.org/licenses/mit-license.php The MIT License (MIT)
*/
namespace Keizu;
require_once realpath(__DIR__ . '/silex.phar');
const INTERNAL_ENCODING = 'UTF-8';
const CSRF_TOKEN_NAME = 'AEg9GE5#4ZyPY$fd';
use Silex\Application;
use Silex\Provider\SessionServiceProvider;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Holy\Silex\Provider\PhpTalServiceProvider;
use Holy\Silex\Provider\RedBeanServiceProvider;
$app = new Application();
$app['debug'] = true;
$app['autoloader']->registerNamespace('Holy' , realpath(__DIR__ . '/vendor/k-holy/src'));
$app->register(new SessionServiceProvider());
$app->register(new PhpTalServiceProvider(), array(
'phptal.class_path' => realpath(__DIR__ . '/vendor/phptal'),
'phptal.options' => array(
'templateRepository' => realpath(__DIR__ . '/views'),
),
));
$app->register(new RedBeanServiceProvider(), array(
'db.redbean.class_path' => realpath(__DIR__ . '/vendor/redbean'),
'db.options' => array(
'dsn' => sprintf('sqlite:%s', realpath(__DIR__ . '/app/data/keizu.sqlite')),
),
));
$app['db']->debug(true);
// Error handler
$app->error(function(\Exception $e, $code) use ($app) {
$message = 'Internal Server Error';
if ($e instanceof \Symfony\Component\HttpKernel\Exception\HttpExceptionInterface) {
switch ($code) {
case 403:
$message = 'Forbidden';
break;
case 404:
$message = 'NotFound';
break;
case 405:
$message = 'Method Not Allowed';
break;
}
}
$app['phptal']->set('message', $message);
$app['phptal']->set('error', ($app['debug']) ? $e->__toString() : null);
$app['phptal']->set('title', 'エラー');
return new Response($app['phptal']->setTemplate('error.html')->execute(),
(isset($code)) ? $code : 500);
});
// Before filter
$app->before(function(Request $request) use($app) {
if ($app['session']->hasFlash('message')) {
$app['phptal']->set('message', $app['session']->getFlash('message'));
$app['session']->removeFlash('message');
}
});
//----------------------------------------------------------------------------
// 人物一覧
//----------------------------------------------------------------------------
$app->get('/profiles/', function() use ($app) {
$app['phptal']->set('items', $app['db']->find('profiles', ' 1 ORDER BY id'));
$app['phptal']->set('title', '人物一覧');
return $app['phptal']->setTemplate('profiles/index.html')->execute();
});
//----------------------------------------------------------------------------
// フィールド、バリデータ定義
//----------------------------------------------------------------------------
$fields = array(
'name' => '名前',
'notes' => '備考',
);
$validator = function($bean) use ($fields) {
$errors = array();
foreach ($fields as $field => $label) {
switch ($field) {
case 'name':
if (!isset($bean->{$field}) || 0 === strlen($bean->{$field})) {
$errors[$field] = sprintf('%sを入力してください', $label);
} elseif (20 < mb_strlen($bean->{$field}, INTERNAL_ENCODING)) {
$errors[$field] = sprintf('%sを20文字以内で入力してください', $label);
}
break;
}
}
return (empty($errors)) ? true : $errors;
};
//----------------------------------------------------------------------------
// 人物登録
//----------------------------------------------------------------------------
$app->match('/profiles/register', function() use ($app, $fields, $validator) {
$bean = $app['db']->dispense('profiles');
switch($app['request']->getMethod()) {
case 'POST':
$bean->import($app['request']->request->all(), array_keys($fields));
if ($app['request']->get(CSRF_TOKEN_NAME) === $app['session']->getId()) {
if (true === ($errors = $validator($bean))) {
$app['db']->store($bean);
$app['session']->setFlash('message', '人物情報を登録しました。');
return $app->redirect('/profiles/', 302);
}
}
$app['phptal']->set('errors', $errors);
break;
}
$app['phptal']->set('token', array(
'name' => CSRF_TOKEN_NAME,
'value' => $app['session']->getId(),
));
$app['phptal']->set('data' , $bean);
$app['phptal']->set('title', '人物登録');
return $app['phptal']->setTemplate('profiles/edit.html')->execute();
});
//----------------------------------------------------------------------------
// 人物編集
//----------------------------------------------------------------------------
$app->match('/profiles/{id}/modify', function($id) use ($app, $fields, $validator) {
$bean = $app['db']->load('profiles', $id);
switch($app['request']->getMethod()) {
case 'POST':
$bean->import($app['request']->request->all(), array_keys($fields));
if ($app['request']->get(CSRF_TOKEN_NAME) === $app['session']->getId()) {
if (true === ($errors = $validator($bean))) {
$app['db']->store($bean);
$app['session']->setFlash('message', '人物情報を更新しました。');
return $app->redirect('/profiles/', 302);
}
}
$app['phptal']->set('errors', $errors);
break;
}
$app['phptal']->set('token', array(
'name' => CSRF_TOKEN_NAME,
'value' => $app['session']->getId(),
));
$app['phptal']->set('data' , $bean);
$app['phptal']->set('title', '人物編集');
return $app['phptal']->setTemplate('profiles/edit.html')->execute();
})->assert('id', '\d+');
//----------------------------------------------------------------------------
// 人物削除
//----------------------------------------------------------------------------
$app->match('/profiles/{id}/delete', function($id) use ($app) {
$bean = $app['db']->load('profiles', $id);
switch($app['request']->getMethod()) {
case 'POST':
if ($app['request']->get(CSRF_TOKEN_NAME) === $app['session']->getId()) {
$app['db']->trash($bean);
$app['session']->setFlash('message', '人物情報を削除しました。');
return $app->redirect('/profiles/', 302);
}
break;
}
$app['phptal']->set('token', array(
'name' => CSRF_TOKEN_NAME,
'value' => $app['session']->getId(),
));
$app['phptal']->set('data' , $bean);
$app['phptal']->set('title', '人物削除');
return $app['phptal']->setTemplate('profiles/delete.html')->execute();
})->assert('id', '\d+');
$app->run();
<?php
/**
* PHP versions 5
*
* @copyright 2011 k-holy <k.holy74@gmail.com>
* @author k.holy74@gmail.com
* @license http://www.opensource.org/licenses/mit-license.php The MIT License (MIT)
*/
namespace Holy\Silex\Provider;
use Silex\Application;
use Silex\ServiceProviderInterface;
class PhpTalServiceProvider implements ServiceProviderInterface
{
public function register(Application $app)
{
$app['phptal'] = $app->share(function() use ($app) {
$phptal = new \PHPTAL();
$app['phptal.options'] = array_replace(
array(
'outputMode' => null,
'encoding' => null,
'templateRepository' => null,
'phpCodeDestination' => null,
'phpCodeExtension' => null,
'cacheLifetime' => null,
),
(isset($app['phptal.options'])) ? $app['phptal.options'] : array()
);
foreach ($app['phptal.options'] as $name => $value) {
$method = 'set' . ucfirst($name);
if (!method_exists($phptal, $method)) {
throw new \RuntimeException(
sprintf('The accessor method to "%s" is not defined.', $name));
}
if (isset($value)) {
switch ($name) {
case 'templateRepository':
if ('\\' === DIRECTORY_SEPARATOR) {
$value = (is_array($value))
? array_map(function($var) {
return str_replace('\\', '/', $var);
}, $value) : str_replace('\\', '/', $value);
}
break;
default:
break;
}
$phptal->{$method}($value);
}
}
return $phptal;
});
if (isset($app['phptal.class_path'])) {
$app['autoloader']->registerPrefix('PHPTAL', $app['phptal.class_path']);
}
}
}
<!DOCTYPE html>
<html>
<head metal:use-macro="__layout.html/head">
<meta charset="UTF-8" />
<title>人物削除</title>
</head>
<body metal:use-macro="__layout.html/body">
<div id="container">
<div id="main" metal:fill-slot="main">
<ul class="errors" tal:condition="exists:errors">
<li tal:repeat="error errors" tal:content="error">エラーメッセージ</li>
</ul>
<form method="post">
<input type="hidden" tal:attributes="name token/name;value token/value" />
<table>
<tr>
<th>ID</th>
<td>${data/id}</td>
</tr>
<tr>
<th>名前</th>
<td>${data/name}</td>
</tr>
<tr>
<th>備考</th>
<td>${data/notes}</td>
</tr>
</table>
<p>
<input type="submit" name="delete" value="削除" />
</p>
</form>
<p><a href="/profiles/">戻る</a></p>
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head metal:use-macro="__layout.html/head">
<meta charset="UTF-8" />
<title>人物編集</title>
</head>
<body metal:use-macro="__layout.html/body">
<div id="container">
<div id="main" metal:fill-slot="main">
<ul class="errors" tal:condition="exists:errors">
<li tal:repeat="error errors" tal:content="error">エラーメッセージ</li>
</ul>
<form method="post">
<input type="hidden" tal:attributes="name token/name;value token/value" />
<table>
<tr>
<th>ID</th>
<td tal:content="data/id">1</td>
</tr>
<tr>
<th>名前</th>
<td><input type="text" name="name" tal:attributes="value data/name" /></td>
</tr>
<tr>
<th>備考</th>
<td><textarea name="notes" tal:content="data/notes"></textarea></td>
</tr>
</table>
<p>
<input type="submit" name="store" value="保存" />
</p>
</form>
<p><a href="/profiles/">戻る</a></p>
</div>
</div>
</body>
</html>
<!DOCTYPE html>
<html>
<head metal:use-macro="__layout.html/head">
<meta charset="UTF-8" />
<tal:block metal:fill-slot="head-extra">
<link rel="stylesheet" media="screen" href="/css/list.css" />
</tal:block>
<title>一覧</title>
</head>
<body metal:use-macro="__layout.html/body">
<div id="container">
<div id="main" metal:fill-slot="main">
<table class="list">
<thead>
<tr>
<th>ID</th>
<th>名前</th>
<th>備考</th>
<th></th>
</tr>
</thead>
<tbody>
<tr tal:repeat="item items" tal:attributes="class php: repeat.item.even ? 'row1' : 'row2'">
<td class="number" tal:content="item/id">ID</td>
<td tal:content="item/name">k-holy</td>
<td tal:content="item/notes">眠い眠い眠い</td>
<td class="action">
<a href="/profiles/${item/id}/modify">編集</a>
<a href="/profiles/${item/id}/delete">削除</a>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment