Показаны сообщения с ярлыком css. Показать все сообщения
Показаны сообщения с ярлыком css. Показать все сообщения

суббота, 5 апреля 2008 г.

Страница новостей (продолжение)

Формируем глпавный шаблон проекта



<!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">


&nbsp;


</div>


<div id="logo">


&nbsp;


</div>


</div>



<div id="topmenu">



&nbsp;



</div>



<div id="navigation">





Extra Content

<fieldset>


<legend>Collapsible List &mdash; 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>












пятница, 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/