Формируем глпавный шаблон проекта
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<?php include_http_metas() ?>
<?php include_metas() ?>
<?php include_title() ?>
<link rel="shortcut icon" href="/favicon.ico" />
</head>
<body>
<div id="container">
<div id="header">
<div id="banner">
</div>
<div id="logo">
</div>
</div>
<div id="topmenu">
</div>
<div id="navigation">
Extra Content
<fieldset>
<legend>Collapsible List — Take 4</legend>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>
Item 3
<ul>
<li>Item 3.1</li>
<li>
Item 3.2
<ul>
<li>Item 3.2.1</li>
<li>Item 3.2.2</li>
<li>Item 3.2.3</li>
</ul>
</li>
<li>Item 3.3</li>
</ul>
</li>
<li>
Item 4
<ul>
<li>Item 4.1</li>
<li>
Item 4.2
<ul>
<li>Item 4.2.1</li>
<li>Item 4.2.2</li>
</ul>
</li>
</ul>
</li>
<li>Item 5</li>
</ul>
</fieldset>
</div>
<div id="content">
Primary Content
<div id="smallFeatures">
<div id="smallFeaturesInner">
<div id="feature2" class="feature">
<div id="feature2Inner">
<h3>
Secondary title I
</h3>
<p>
Какой-то текст.
</p>
<p class="featureContinue">
<a href="#">Visit the page</a>
</p>
</div>
</div>
<!-- END feature2 -->
<div id="feature3" class="feature">
<div id="feature3Inner">
<h3>
Secondary title II
</h3>
<p>
Какой-то текст.
</p>
<p class="featureContinue">
<a href="#">Visit the page</a>
</p>
</div>
<!-- END feature3Inner -->
</div>
<!-- END feature3 -->
<div id="feature4" class="feature">
<div id="feature4Inner">
<h3>
Secondary title III
</h3>
<p>
Какой-то текст.
</p>
<p class="featureContinue">
<a href="#">Visit the page</a>
</p>
</div>
<!-- END feature4Inner -->
</div>
<!-- END feature4 -->
<div class="clearer">
</div>
</div>
<!-- END smallFeaturesInner -->
<div id="feature1">
<?php echo $sf_data->getRaw('sf_content') ?>
<p class="featureContinue">
<?php echo link_to('back to the news list', 'public/index',
'style=display:block;float:right;') ?>
</p>
</div>
<!-- END feature1 -->
</div>
<!-- END smallFeatures -->
<div class="clearer">
</div>
</div>
<!-- END content -->
</div>
<div id="footer">
Footer<p>Force Layout:
</p>
</div>
</div>
</body>
</html>
Навигационную панель слева строим с помощью jquery
Пишем скрипт menu и подключаем его и jquery к проекту
menu
$(function(){
$('li:has(ul)')
.click(function(event){
if (this == event.target) {
if ($(this).children().is(':hidden')) {
$(this)
.css('list-style-image','url(minus.gif)')
.children().slideDown();
}
else {
$(this)
.css('list-style-image','url(plus.gif)')
.children().slideUp();
}
}
return false;
})
.css({cursor:'pointer',
'list-style-image':'url(plus.gif)'})
.children().hide();
$('li:not(:has(ul))').css({
cursor: 'default',
'list-style-image':'none'
});
});
default:
http_metas:
content-type: text/html
metas:
title: symfony project
robots: index, follow
description: symfony project
keywords: symfony, project
language: en
stylesheets: [main, art]
javascripts: [jquery, menu]
has_layout: on
layout: layout
Чтобы все это работало, добавляем нужные стили
body
{
text-align:center;
color:#333;
font-family: sans-serif;
margin:0px 0;
background-color: #FBFFC0;
}
body,td {
font-size: 10pt;
}
table {
background-color: black;
border: 1px black solid;
border-collapse: collapse;
}
th {
border: 1px outset silver;
background-color: maroon;
color: white;
}
tr {
background-color: white;
margin: 1px;
}
tr.striped {
background-color: coral;
}
td {
padding: 1px 8px;
}
#jQueryStatement {
color: maroon;
}
fieldset {width: auto;
margin-bottom: 12px;
border-color: #00457b;
background-color: #cfeace;
}
fieldset div {
margin-bottom: 6px;
font-weight: normal;
}
legend {
border: 2px ridge #00457b;
font-weight: bold;
background-color: #e36a51;
color: white;
padding: 2px 16px;
}
button {
background-color: #2a523c;
padding: 2px 16px;
color: #cfeace;
font-weight:bold;
}
a,#exampleIndex li {
color: #2a523c;
}
a:hover,#exampleIndex li:hover {
color: #ff0088;
}
#exampleIndex ul {
list-style: none;
margin: 8px;
padding: 0;
}
#exampleIndex li {
text-decoration: underline;
font-weight: bold;
cursor: pointer;
margin: 0;
padding: 0;
}
.chapterBlock {
background-color: #ddeadc;
border: 3px double #00457b;
margin: 6px 8px;
padding: 6px;
}
p{
font-size:.9em;
line-height:1.3em;
margin:20px auto;
}
#notice p{
text-align:justify !important;
}
#container{
width:100%;
margin:0 auto;
}
#container p{
text-align:right;
}
#header{
background-color: #FFA345;
width:100%;
line-height:90px;
color:#fff;
}
#header #banner {
background-color: #FFA345;
width:80%;
line-height:90px;
color:#fff;
float:left;
}
#header #logo{
background-color: #FF0045;
width:20%;
color:#fff;
float:right;
}
#header #mbanner{
background-color: #FFA345;
width:100%;
line-height:90px;
color:#fff;
float:right;
}
#content{
background-color: #00009F;
width:80%;
float:right;
color:#fff;
}
#topmenu{
background-color: #94C6FF;
width:100%;
line-height:35px;
clear:both;
}
#topmenu #calendar{
background:url(../images/top_back1.jpg) no-repeat;
width:395px;
line-height:35px;
float:left;
}
#topmenu #topm{
background:url(../images/top_back1.jpg);
width:592px;
line-height:35px;
float:right;
}
#navigation{
background-color: #C5FF8A;
width:250px;
float:left;
}
#extraContent{
display:none;
}
#footer{
background-color: #94C6FF;
width:100%;
line-height:50px;
clear:both;
}
a{
font-weight:bold;
color:#000;
cursor: pointer;
}
.article
{
color:#666;
float:left;
}
#smallFeatures
{
position: static;
border: none;
border-bottom: 1px solid #CCCCCC;
padding: 0;
}
#smallFeatures .feature
{
clear: none;
float: left;
width: 33.3%;
border-top: 0 none #FFFFFF;
padding: 0;
background-color: transparent;
}
#smallFeatures .feature h3
{
clear: none;
margin: 0 0 15px 0;
border-top: 1px solid #CCCCCC;
border-bottom: 1px solid #CCCCCC;
padding: 8px 15px;
background-color: #EEEEEE;
background-image: none;
}
#feature1{
margin: 0 15px 15px 15px;
}
#smallFeatures .feature p
{
margin: 0 15px 15px 15px;
}
#smallFeatures .featureContinue
{
border-top: 1px dashed #CCCCCC;
padding-top: 0.25em;
}
В шаблоне index для чтения новости целиком создаем ссылку read more...
<div id="main">
<h1>News and articles</h1>
<?php foreach($articles as $article): ?>
<fieldset>
<legend><?php echo $article->getCreatedAt('d/M/Y') ?></legend>
<div class="article">
<?php echo link_to(
image_tag('/uploads/'.$article->getFilePath()),
'public/article?id='.$article->getId(),
'class=image title='.$article->getTitle()
) ?>
<?php echo $article->getTeaser() ?>
<?php echo link_to('read more... ', 'public/article?id='.$article->getId(),
'style=display:block;float:right;') ?>
</div>
</fieldset>
<?php endforeach; ?>
<div id="footer">
powered by <?php echo link_to('symfony', 'http://www.symfony-project.com') ?>
</div>
</div>
И соответствующий этой ссылке action в классе publicActions
<?php
/**
* public actions.
*
* @package prod
* @subpackage public
* @author Your name here
* @version SVN: $Id: actions.class.php 2692 2006-11-15 21:03:55Z fabien $
*/
class publicActions extends sfActions
{
/**
* Executes index action
*
*/
public function executeIndex()
{
//$this->forward('default', 'module');
$c = new Criteria();
$c->addDescendingOrderByColumn(ArticlePeer::CREATED_AT);
$this->articles = ArticlePeer::doSelect($c);
}
public function executeArticle()
{
$this->article = ArticlePeer::retrieveByPk($this->getRequestParameter('id'));
$this->forward404unless($this->article);
$c = new Criteria();
$c->add(ArticlePeer::ID, $this->getRequestParameter('id'));
$this->articles = ArticlePeer::doSelect($c);
}
}
А для представления - шаблон
<h1><?php echo $article->getTitle() ?> </h1>
<fieldset>
<legend><?php echo $article->getCreatedAt('d/M/Y') ?></legend>
<p>
<?php echo link_to(
image_tag('/uploads/'.$article->getFilePath()),
'public/article?id='.$article->getId(),
'class=image title='.$article->getTitle()
) ?>
<?php echo $article->getBody() ?>
</p>
</fieldset>
суббота, 5 апреля 2008 г.
Страница новостей (продолжение)
пятница, 4 апреля 2008 г.
Создадим приложение для публикации новостей
- Создадим приложение для публикации новостей.
Требуется
Авторизация
Информация о пользователе
Публикация анонса
Помещение в публикацию изображения
Просмотр публикации целиком
Установки для базы данных
all:
propel:
class: sfPropelDatabase
param:
dsn: mysql://root@localhost/prod
Спроектируем 3 таблицы
author:
_attributes: { phpName: Author }
id:
first_name: varchar(30)
last_name: varchar(30)
email: varchar(75)
website: varchar(100)
birthday: date
years_experience: integer
article:
_attributes: { phpName: Article }
id:
author_id:
title: varchar(255)
teaser: longvarchar
body: longvarchar
file_path: varchar(50)
file_attachment: varchar(255)
created_at: ~
tag:
article_id: ~
name: varchar(50)
name: varchar(50)
Построим модель и таблицы
$symfony propel-build-all
Чистим кеш
$symfony clear-cache
Создаем приложение
$symfony init-app frontend
Генерируем панель админа
$symfony propel-init-admin frontend author Author
$symfony propel-init-admin frontend article Article
смотрим
http://localhost/frontend_dev.php/author
http://localhost/frontend_dev.php/article
Создаем автора
Редактируем представление
открываем generator.yml из apps/frontend/modules/article/config/
generator:
class: sfPropelAdminGenerator
param:
model_class: Article
theme: default
и добавляем следующий код:
list:
display: [title, created_at]
object_actions:
_edit:
name: Edit article
чтобы выбрать картинку
edit:
display: [file_path, title, created_at]
fields:
file_path:
type: admin_input_file_tag
Создаем несколько новостей
generator:
class: sfPropelAdminGenerator
param:
model_class: Article
theme: default
list:
display: [title, created_at]
object_actions:
_edit:
name: Edit article
edit:
display: [_img, file_path, title, created_at, teaser, body]
fields:
file_path:
type: admin_input_file_tag
tags_string:
name: Tags
type: input_tag
Для того чтобы это работало, нужно создать часть шаблона
_img.php
<?php echo image_tag('/uploads/'.$article->getFilePath()) ?>
Скорректировать класс Article
Article.php
<?php
/**
* Subclass for representing a row from the 'article' table.
*
*
*
* @package lib.model
*/
class Article extends BaseArticle
{
public function getTagsString()
{
$tags = array (9);
foreach ($this->getTags() as $tag)
{
$tags[] = $tag->__toString();
}
return implode(' ', $tags);
}
public function setTagsString($tagPhrase)
{
// remove old tags
$this->deleteTags();
// set new tags
$tagNames = explode(' ', $tagPhrase);
foreach($tagNames as $tagName)
{
$tag = new Tag();
$tag->setArticle($this);
$tag->setName($tagName);
$tag->save();
}
}
public function deleteTags()
{
$c = new Criteria();
$c->add(TagPeer::ARTICLE_ID, $this->getId());
TagPeer::doDelete($c);
}
}
Скорректировать класс Tag
Tag.php
<?php
/**
* Subclass for representing a row from the 'tag' table.
*
*
*
* @package lib.model
*/
class Tag extends BaseTag
{
public function __toString()
{
return $this->getName();
}
}
Создаем модуль для анонимных посетителей
<?php
/**
* public actions.
*
* @package prod
* @subpackage public
* @author Your name here
* @version SVN: $Id: actions.class.php 2692 2006-11-15 21:03:55Z fabien $
*/
class publicActions extends sfActions
{
/**
* Executes index action
*
*/
public function executeIndex()
{
//$this->forward('default', 'module');
$c = new Criteria();
$c->addDescendingOrderByColumn(ArticlePeer::CREATED_AT);
$this->articles = ArticlePeer::doSelect($c);
}
}
И соответствующий ему шаблон
<div id="main">
<h1>News and articles</h1>
<?php foreach($articles as $article): ?>
<?php echo $article->getCreatedAt('d/M/Y') ?>
<div class="article">
<?php echo link_to(
image_tag('/uploads/'.$article->getFilePath()),
'public/article?id='.$article->getId(),
'class=image title='.$article->getTitle()
) ?>
<?php echo $article->getTeaser() ?>
<?php echo link_to('read more... ', 'public/article?id='.$article->getId(),
'style=display:block;float:right;') ?>
</div>
<?php endforeach; ?>
<div id="footer">
powered by <?php echo link_to('symfony', 'http://www.symfony-project.com') ?>
</div>
</div>
Создаем стиль для этого шаблона
body
{
text-align:center;
color:#333;
font-family: sans-serif;
margin:0px 0;
background-color: #FBFFC0;
}
p{
font-size:.9em;
line-height:1.3em;
margin:20px auto;
}
#footer{
background-color: #94C6FF;
width:100%;
line-height:50px;
clear:both;
}
a{
font-weight:bold;
color:#000;
cursor: pointer;
}
.article
{
color:#666;
float:left;
}
Добавляем этот стиль
default:
http_metas:
content-type: text/html
metas:
title: symfony project
robots: index, follow
description: symfony project
keywords: symfony, project
language: en
stylesheets: [main, art]
javascripts: []
has_layout: on
layout: layout
пятница, 21 марта 2008 г.
Страница общего доступа
После добавления нового модуля, который мы назвали public
$ symfony init-module frontend public
мы заменили стандартную страницу приветствия
// apps/.../actions/actions.class.php
public function executeIndex()
{
$c = new Criteria();
$c->addDescendingOrderByColumn(PhotoPeer::CREATED_AT);
$this->photos = PhotoPeer::doSelect($c);
}
Оформление нового шаблона :
// apps/.../modules/public/templates/indexSuccess.php
<div id="main">
<h1>Mои фотографии</h1>
<?php foreach($photos as $photo): ?>
<div class="photo">
<?php echo link_to(
image_tag('/uploads/thumbnail/'.$photo->getFilePath()),
'public/photo?id='.$photo->getId(),
'class=image title='.$photo->getDescription()
) ?>
"<?php echo $photo->getDescription() ?>"
on <?php echo $photo->getCreatedAt('d/m') ?>,
tagged <?php echo $photo->getTagsString() ?>
</div>
<?php endforeach; ?>
<div id="footer">
сделано на <?php echo link_to('symfony', 'http://www.symfony-project.com') ?>
</div>
</div>
Подгрузили стили:
// apps/..../actions/actions.class.php
public function preExecute()
{
$this->getResponse()->addStylesheet('frontend');
}
Пример стилей
body
{
font-family: "Trebuchet MS", arial, sans-serif;
background: #edd;
}
#main
{
margin: auto;
width: 680px;
padding:20px;
background: white;
}
#main h1
{
margin-bottom: 20px;
border-bottom: solid 1px lightgrey;
}
#footer
{
clear: left;
text-align:right;
}
.photo
{
width: 160px;
padding-right: 10px;
padding-bottom: 10px;
float:left;
}
a.image:hover img
{
border: solid 4px grey;
}
a.image img
{
border: solid 4px lightgrey;
}
label
{
display: block;
margin-top: 5px;
}
.comment
{
background: #eee;
border: solid 1px #ddd;
margin: 10px;
padding: 5px;
}
.comment .details
{
font-weight: bold;
}
При вызове конкретной фотографии, выполняется действие:
// apps/.../actions/actions.class.php
public function executePhoto()
{
$photo = PhotoPeer::retrieveByPk($this->getRequestParameter('id'));
$this->forward404unless($photo);
$this->photo = $photo;
}
Результат отображается с помощью шаблона:
// apps/..../modules/public/templates/photoSuccess.php
<div id="main">
<?php echo link_to('back to the photo list', 'public/index',
'style=display:block;float:right;') ?>
<h1>Picture details</h1>
<a href="/uploads/<?php echo $photo->getFilePath() ?>" title="click for the full-size version">
<?php echo image_tag('/uploads/'.$photo->getFilePath(), 'width=100%') ?>
</a><br/>
<p>
"<?php echo $photo->getDescription() ?>"
published on <?php echo $photo->getCreatedAt('d/m') ?>,
tagged <?php echo $photo->getTagsString() ?>
</p>
<div id="footer">
powered by <?php echo link_to('symfony', 'http://www.symfony-project.com') ?>
</div>
</div>
Оптимизируем приложение
У двух шаблонов общий код:
// apps/..../modules/public/templates/_photo_description.php
"<?php echo $photo->getDescription() ?>"
published on <?php echo $photo->getCreatedAt('d/m') ?>,
tagged
<?php foreach($photo->getTags() as $tag): ?>
<?php $tag=$tag->getName(); echo link_to($tag, 'public/tag?tag='.$tag) ?>
<?php endforeach; ?>
Редактируем шаблоны indexSuccess.php и photoSuccess.php:
// in apps/frontend/modules/public/templates/photoSuccess.php
<div id="main">
<?php echo link_to('back to the photo list', 'public/index',
'style=display:block;float:right;') ?>
<h1>Picture details</h1>
<a href="/uploads/<?php echo $photo->getFilePath() ?>" title="click for the full-size version">
<?php echo image_tag('/uploads/'.$photo->getFilePath(), 'width=100%') ?>
</a><br/>
<p>
<?php echo include_partial('photo_description', array(
'photo' => $photo
)) ?>
</p>
<div id="footer">
powered by <?php echo link_to('symfony', 'http://www.symfony-project.com') ?>
</div>
</div>
Редактируем главный шаблон:
// in apps/frontend/templates/layout.php
<!DOCTYPE html PUBLIC "-//W3C [17]//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
<?php echo include_http_metas() ?>
<?php echo include_metas() ?>
<?php echo include_title() ?>
<link rel="shortcut icon" href="/favicon.ico" />
</head>
<body>
<div id="main">
<?php echo $sf_data->getRaw('sf_content') ?>
<div id="footer">
powered by <?php echo link_to('symfony', 'http://www.symfony-project.com') ?>
</div>
</div>
</body>
</html>
Удалим <div id="main"></div> и the <div id="footer"></div> из обеих шаблонов и создадим новый шаблон для действия:
// apps/.../modules/public/actions/actions.class.php
public function executeTag()
{
$this->forward404Unless($tag = $this->getRequestParameter('tag'));
$c = new Criteria();
$c->addJoin(PhotoPeer::ID, TagPeer::PHOTO_ID);
$c->add(TagPeer::NAME, $tag);
$this->photos = PhotoPeer::doSelect($c);
$this->setTemplate('Index');
}
// apps/..../modules/public/templates/indexSuccess.php
<?php if($tag = $sf_params->get('tag')): ?>
<?php echo link_to('back to the photo list', 'public/index', 'style=display:block;float:right;') ?>
<?php endif; ?>
<h1>
My pictures
<?php if($tag): ?>
tagged "<?php echo $tag ?>"
<?php endif; ?>
</h1>
<?php foreach($photos as $photo): ?>
<div class="photo">
<?php echo link_to(
image_tag('/uploads/thumbnail/'.$photo->getFilePath()),
'public/photo?id='.$photo->getId(),
'class=image title='.$photo->getDescription()
) ?>
<?php echo include_partial('photo_description', array(
'photo' => $photo
)) ?>
</div>
<?php endforeach; ?>
//apps/..../modules/public/templates/photoSuccess.php
...
<?php use_helper('Javascript'); ?>
<div id="comments">
<h2>Comments</h2>
<?php foreach($photo->getComments() as $comment): ?>
<?php include_partial('comment', array('comment' => $comment)) ?>
<?php endforeach; ?>
<div id="updateDiv">
<?php echo link_to_function('Add a comment', visual_effect('toggle_blind', 'addComment')) ?>
<?php echo form_remote_tag(array(
'url' => 'public/addComment',
'update' => 'updateDiv',
'complete' => visual_effect('highlight', 'updateDiv'),
), 'id=addComment style=display:none;') ?>
<?php echo input_hidden_tag('photo_id', $photo->getId()) ?>
<?php echo label_for('author', 'Your name') ?>
<?php echo input_tag('author') ?><br />
<?php echo label_for('body', 'Your comment') ?>
<?php echo textarea_tag('body') ?><br />
<?php echo submit_tag('submit') ?>
</form>
</div>
</div>
_comment.php для отображения коментариев:
// apps/.../modules/photo/templates/_comment.php
<?php echo use_helper('Date') ?>
<div class="comment">
<p class="details">
<?php echo $comment->getAuthor() ?> said
<?php echo distance_of_time_in_words($comment->getPhoto()->getCreatedAt('U'), $comment->getCreatedAt('U')) ?> after
</p>
<p class="body"><?php echo $comment->getBody() ?></p>
</div>
Используем Ajax :
// in apps/.../modules/public/actions/actions.class.php
public function executeAddComment()
{
$this->forward404unless($photo = PhotoPeer::retrieveByPk($this->getRequestParameter('photo_id')));
$comment = new Comment();
$comment->setPhoto($photo);
$comment->setAuthor($this->getRequestParameter('author'));
$comment->setBody($this->getRequestParameter('body'));
$comment->save();
$this->comment = $comment;
}
Ajax шаблон:
// in apps/..../modules/public/templates/addCommentSuccess.php
<?php include_partial('comment', array('comment' => $comment)) ?>
суббота, 15 марта 2008 г.
Используем плагины
Используем плагины
Плагин sfThumbnail создает значки определенного размера для публикуемых изображений:
symfony plugin-install http://plugins.symfony-project.com/sfThumbnailPlugin
$ php symfony clear-cache
Применим установленный плагин sfThumbnail к нашему классу Photo. Добавим в Photo.php:
// in lib/model/Photo.php
public function setFilePath($value)
{
parent::setFilePath($value);
$this->generateThumbnail($value);
}
public function generateThumbnail($value)
{
parent::setFilePath($value);
$uploadDir = sfConfig::get('sf_upload_dir');
$thumbnail = new sfThumbnail(150, 150);
$thumbnail->loadFile($uploadDir.'/'.$this->getFilePath());
$thumbnail->save($uploadDir.'/thumbnail/'.$this->getFilePath(), 'image/png');
}
Это позволит создавать значки размером 150x150px от оригинального размера файла и сохранять из в каталог uploads/thumbnail/ . В классе generateThumbnail используется класс sfConfig для получения пути к директории uploads.
$ cd web/uploads
$ mkdir thumbnail
$ chmod 777 thumbnail
Также необходимо отредактировать файл _photo.php :
// in apps/prod/modules/photo/templates/_photo.php
<?php echo image_tag('/uploads/thumbnail/'.$photo->getFilePath()) ?>
Теперь можно загрузить изображение.
Для обеспечения безопасности в приложении необходима авторизация. Эту задачу решает плагин sfGuard Установим его:
$symfony plugin-install http://plugins.symfony-project.com/sfGuardPlugin
Разрешим его использование, отредактировав файл apps/prod/config/settings.yml:
// apps/prod/config/settings.yml
all:
.actions:
login_module: sfGuardAuth
login_action: signin
.settings:
enabled_modules: [default, sfGuardAuth, sfGuardUser]
Кроме того, неоюходимо помень наследование в классе myUser, изменив myUser.class.php:
//apps/prod/lib/myUser.class.php
class myUser extends sfGuardSecurityUser
{
}
Сообщим symfony, что все действия в модуле photo теперь требуют авторизации. В modules/photo/config/ :
// apps/prodd/modules/photo/config/security.yml
all:
is_secure: on
В sfGuardPlugin входит модуль управления пользователями, что дает возможность создавать и управлять пользователями. Для его включения тредуется пересоздать все
propel-build-all
Если в базе есть данные, которые нужно сохранить, перед пересборкой их надо бекаптровать:
>symfony propel-dump-data prod testdata.yml
>symfony cc
>symfony propel-build-all-load prod
Смотрим результат
http://localhost/prod_dev.php/photo.
sfGuardPlugin создает бюджет id: admin, password: admin.
Для создания новых пользователей, вызовите URL: http://localhost/prod_dev.php/sfGuardUser.
Для анонимных посетителей, необходимо добавить страницу
$symfony init-module prod public
Получим каталог public/ в apps/prod/modules/, содержащий:
actions/
config/
lib/
template/
validate/
Отредактируем apps/prod/modules/public/actions/actions.class.php.
// actions/actions.class.php
public function executeIndex()
{
$c = new Criteria();
$c->addDescendingOrderByColumn(PhotoPeer::CREATED_AT);
$this->photos = PhotoPeer::doSelect($c);
}
Эти три строки соответствуют SQL запросу:
SELECT * FROM photo ORDER BY created_at;
//в apps/prod/modules/public/templates/indexSuccess.php
<div id="main">
<h1>My pictures</h1>
<?php foreach($photos as $photo): ?>
<div class="photo">
<?php echo link_to(
image_tag('/uploads/thumbnail/'.$photo->getFilePath()),
'public/photo?id='.$photo->getId(),
'class=image title='.$photo->getDescription()
) ?>
"<?php echo $photo->getDescription() ?>"
on <?php echo $photo->getCreatedAt('d/m') ?>,
tagged <?php echo $photo->getTagsString() ?>
</div>
<?php endforeach; ?>
<div id="footer">
powered by <?php echo link_to('symfony', 'http://www.symfony-project.com') ?>
</div>
</div>
Если нелюходимо подключать стили в каждую страницу, необходимо изменить метод preExecute в actions.class.php:
// apps/prod/actions/actions.class.php
public function preExecute()
{
$this->getResponse()->addStylesheet('frontend');
}
http://localhost/prod_dev.php/public/index.
Для запрета вызывать изображения по их идентификатору, изменим executePhoto():
// apps/prod/actions/actions.class.php
public function executePhoto()
{
$photo = PhotoPeer::retrieveByPk($this->getRequestParameter('id'));
$this->forward404unless($photo);
$this->photo = $photo;
}
Создадим шаблон photoSuccess.php в кпталоге templates/ :
// apps/prod/modules/public/templates/photoSuccess.php
<div id="main">
<?php echo link_to('back to the photo list', 'public/index',
'style=display:block;float:right;') ?>
<h1>Picture details</h1>
<a href="/uploads/<?php echo $photo->getFilePath() ?>" title="click for the full-size version">
<?php echo image_tag('/uploads/'.$photo->getFilePath(), 'width=100%') ?>
</a><br/>
<p>
"<?php echo $photo->getDescription() ?>"
published on <?php echo $photo->getCreatedAt('d/m') ?>,
tagged <?php echo $photo->getTagsString() ?>
</p>
<div id="footer">
powered by <?php echo link_to('symfony', 'http://www.symfony-project.com') ?>
</div>
</div>
пятница, 29 февраля 2008 г.
Продолжаем строить Blog на Symfony
Модифицируем главный шаблон приложения layout.php
Открываем и редактируем главный шаблон приложения prod/apps/blog/templates/layout.php:
<div id="container" style="width:600px;margin:0 auto;border:1px solid grey;padding:10px">
<div id="navigation" style="display:inline;float:right">
<ul>
<li><?php echo link_to('List of posts', 'post/list') ?></li>
<li><?php echo link_to('List of comments', 'comment/list') ?></li>
</ul>
</div>
<div id="title">
<h1><?php echo link_to('Мой дневник на symfony', '@homepage') ?></h1>
</div>
<div id="content" style="clear:right">
<?php echo $sf_data->getRaw('sf_content') ?>
</div>
</div>
Если уже готов дизайн, замените это на вашу структуру, положив изображения в prod/www/images, а css в prod/www/css.
Изменим служебную часть проекта, оазместив в конфигурационном файле prod/apps/blog/config/view.yml:
default:
http_metas:
content-type: text/html
metas:
title: The best weblog ever
robots: index, follow
description: symfony project
keywords: symfony, project
language: en
stylesheets: [main]
javascripts: []
has_layout: on
layout: layout
Создаем главный модуль main:
c:\xampp\htdocs\prod> symfony init-module frontend main
Редактируем prod/apps/blog/modules/main/actions/actions.class.php и убираем содержимое метода executeIndex():
public function executeIndex() { }
Редактируем шаблон prod/apps/blog/modules/main/templates/indexSuccess.php, например так:
<h1>Привет. Вы можете оставить запись в моем личном дневнике</h1>
<p>Вы <?php echo rand(1000,5000) ?>-й посетитель на сегодня.</p>
Скажем symfony какое действие ей выполнять первым, отредактировав prod/apps/blog/config/routing.yml:
homepage:
url: /
param: { module: main, action: index }
Смотрим результат:
http://localhost/blog_dev.php/