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

пятница, 28 марта 2008 г.

Завершаем строительство Blog

При добалении коментария, мы должны выбирать соответствующий id post. Это неудобно.


Добавим снизу файла modules/post/templates/showSuccess.php :


<?php echo link_to('Add a comment', 'comment/create?post_id='.$post->getId()) ?>


заменим в файле


modules/comment/templates/editSuccess.php строки:


<tr>

<th>Post:</th>

<td><?php echo object_select_tag($comment, 'getPostId', array (

'related_class' => 'Post',

)) ?></td>

</tr>


на:


<?php if ($sf_params->has('post_id')): ?>

<?php echo input_hidden_tag('post_id',$sf_params->get('post_id')) ?>

<?php else: ?>

<tr>

<th>Post*:</th>

<td><?php echo object_select_tag($comment, 'getPostId', array('related_class' => 'Post')) ?></td>

</tr>

<?php endif; ?>


В файле modules/comment/actions/actions.class.php найдем метод executeUpdate(). Изменим его:


public function executeUpdate ()

{

if (!$this->getRequestParameter('id', 0))

{

$comment = new Comment();

}

else

{

$comment = CommentPeer::retrieveByPk($this->getRequestParameter('id'));

$this->forward404Unless($comment);

}



$comment->setId($this->getRequestParameter('id'));

$comment->setPostId($this->getRequestParameter('post_id'));

$comment->setAuthor($this->getRequestParameter('author'));

$comment->setEmail($this->getRequestParameter('email'));

$comment->setBody($this->getRequestParameter('body'));



$comment->save();



return $this->redirect('post/show?id='.$comment->getPostId());

}


Валидпция форм


Создадим update.yml в /modules/comment/validate/ :


 

methods:
post: [author, email, body]
get: [author, email, body]

fillin:
enabled: on



names:
author:
required: Yes
required_msg: The name field cannot be left blank


 email:
required: No
validators: emailValidator

 body:
required: Yes
required_msg: The text field cannot be left blank

emailValidator:
class: sfEmailValidator
param:
email_error: The email address is not valid.

 

Конроллер будет перенаправлять пользователя в случае ошибки на updateError.php . Для реализации этого добавим метод handleErrorUpdate в класс действий modules/comment/actions/actions.class.php:


public function handleErrorUpdate()

{

$this->forward('comment', 'create');

}


Изменим шаблон modules/comment/templates/editSuccess.php, добавив сверху:


<?php if ($sf_request->hasErrors()): ?>

<div id="errors" style="padding:10px;">

Please correct the following errors and resubmit:

<ul>

<?php foreach ($sf_request->getErrors() as $error): ?>

<li><?php echo $error ?></li>

<?php endforeach; ?>

</ul>

</div>

<?php endif; ?>


 


Убираем спецсимволы %20 Редактируем Post.php в /lib/model/ :


public function getStrippedTitle()

{

$result = strtolower($this->getTitle());



// strip all non word chars

$result = preg_replace('/\W/', ' ', $result);



// replace all white space sections with a dash

$result = preg_replace('/\ +/', '-', $result);



// trim dashes

$result = preg_replace('/\-$/', '', $result);

$result = preg_replace('/^\-/', '', $result);



return $result;

}


Создаем действие permalink. Добавим метод в modules/post/actions/actions.class.php:


public function executePermalink()

{

$posts = PostPeer::doSelect(new Criteria());

$title = $this->getRequestParameter('title');

foreach ($posts as $post)

{

if ($post->getStrippedTitle() == $title)

{

$this->getRequest()->setParameter('id', $post->getId());



return $this->forward('post', 'show');

}

}



$this->forward404();

}


Меняем шаблон modules/post/templates/listSuccess.php, удаляя id table header и лоетку, а также заменяя Title с:


<td><?php echo $post->getTitle() ?></td>


на:


<td><?php echo link_to($post->getTitle(), '@post?title='.$post->getStrippedTitle()) ?></td>


Редактируем routing.yml из /config/ добавляя сверзу:


list_of_posts:
url: /latest_posts
param: { module: post, action: list }

post:
url: /weblog/:title
param: { module: post, action: permalink }

Защищаем приложение


В шаблоне modules/post/templates/showSuccess.php удаляем:

<?php echo link_to('edit', 'post/edit?id='.$post->getId()) ?>


Также в modules/post/templates/listSuccess.php удаляем:


<?php echo link_to('create', 'post/create') ?>


Также можно удалить методы из modules/post/actions/actions.class.php:


* executeCreate

* executeEdit

* executeUpdate

* executeDelete


Создаем админку


$ symfony init-app backend

$ symfony propel-init-admin backend post Post

$ symfony propel-init-admin backend comment Comment


Редактируем (apps/backend/templates/layout.php):


<div id="navigation">

<ul style="list-style:none;">

<li><?php echo link_to('Manage posts', 'post/list') ?></li>

<li><?php echo link_to('Manage comments', 'comment/list') ?></li>

</ul>

</div>

<div id="content">

<?php echo $sf_data->getRaw('sf_content') ?>

</div>


Генерирум форму backend/modules/post/config/generator.yml:


generator:
class: sfPropelAdminGenerator
param:
model_class: Post
theme: default
fields:
title: { name: Title }
excerpt: { name: Exerpt }
body: { name: Body }
nb_comments: { name: Comments }
created_at: { name: Creation date }
list:
title: Post list
layout: tabular
display: [=title, excerpt, nb_comments, created_at]
object_actions:
_edit: ~
_delete: ~
max_per_page: 5
filters: [title, created_at]
edit:
title: Post detail
fields:
title: { type: input_tag, params: size=53 }
excerpt: { type: textarea_tag, params: size=50x2 }
body: { type: textarea_tag, params: size=50x10 }
created_at: { type: input_date_tag, params: rich=on }

 


Редактируем /lib/model/Post.php:

public function getNbComments()

{

return count($this->getComments());

}


Защищаем вход в админку


в apps/backend/modules/post/config/security.yml:


all:
is_secure: on

 


$symfony init-module backend security


Редактируем apps/backend/modules/security/templates/indexSuccess.php:


<h2>Authentication</h2>



<?php if ($sf_request->hasErrors()): ?>

Identification failed - please try again

<?php endif; ?>



<?php echo form_tag('security/login') ?>

<label for="login">login:</label>

<?php echo input_tag('login', $sf_params->get('login')) ?>



<label for="password">password:</label>

<?php echo input_password_tag('password') ?>



<?php echo submit_tag('submit', 'class=default') ?>

</form>


Добавляем модуль в apps/backend/modules/security/actions/actions.class.php:


public function executeLogin()

{

if ($this->getRequestParameter('login') == 'admin' && $this->getRequestParameter('password') == 'password')

{

$this->getUser()->setAuthenticated(true);



return $this->redirect('main/index');

}

else

{

$this->getRequest()->setError('login', 'incorrect entry');



return $this->forward('security', 'index');

}

}


Редактируем :


public function executeIndex()

{

}


в apps/backend/config/settings.yml добавляем:


 


all:
.actions:
login_module: security
login_action: index

Проверяем


http://localhost/index.php/

http://localhost/backend.php/


$ symfony cc





суббота, 1 марта 2008 г.

Продолжаем строить blog

Сообщения и коментарии обычно располагают на одной странице. Это и нужно нам сделать.


Редактируем файл prod/apps/blog/modules/post/actions/actions.class.php и меняем метод executeShow():



public function executeShow()
{
$this->post = PostPeer::retrieveByPk($this->getRequestParameter('id'));
$this->forward404Unless($this->post);

$c = new Criteria();
$c->add(CommentPeer::POST_ID, $this->getRequestParameter('id'));
$c->addAscendingOrderByColumn(CommentPeer::CREATED_AT);
$this->comments = CommentPeer::doSelect($c);
}


Модифицирум шаблон для показа сообщений и коментариев prod/apps/blog/modules/post/templates/showSuccess.php:



...
<?php use_helper('Text', 'Date') ?>

<hr />
<?php if ($comments) : ?>
<p><?php echo count($comments) ?> comment
<?php if (count($comments) > 1) : ?>s
<?php endif; ?> to this post.</p>
<?php foreach ($comments as $comment): ?>
<p><em>posted by <?php echo $comment->getAuthor() ?> on
<?php echo format_date($comment->getCreatedAt()) ?>
</em></p>
<div class="comment" style="margin-bottom:10px;">
<?php echo simple_format_text($comment->getBody()) ?>
</div>
<?php endforeach; ?>
<?php endif; ?>



Проверяем:


http://localhost/blog_dev.php/post/show?id=1



При добавления коментария мы имеем возможность выбора соответствующего id сообщения, что не очень красиво.



Модифицируем modules/post/templates/showSuccess.php и добавим снизу:



<?php echo link_to('Add a comment', 'comment/create?post_id='.$post->getId()) ?>


Изменим в modules/comment/templates/editSuccess.php:



<tr>
<th>Post:</th>
<td><?php echo object_select_tag($comment, 'getPostId', array (
'related_class' => 'Post',
)) ?></td>
</tr>


на:

<?php if ($sf_params->has('post_id')): ?>
<?php echo input_hidden_tag('post_id',$sf_params->get('post_id')) ?>
<?php else: ?>
<tr>
<th>Post*:</th>
<td><?php echo object_select_tag($comment, 'getPostId',
array('related_class' => 'Post')) ?></td>
</tr>
<?php endif; ?>

Для атоматического редиректа форм при добавлении коментариев изменим в modules/comment/actions/actions.class.php метод executeUpdate():

public function executeUpdate ()
{
if (!$this->getRequestParameter('id', 0))
{
$comment = new Comment();
}
else
{
$comment = CommentPeer::retrieveByPk($this->getRequestParameter('id'));
$this->forward404Unless($comment);
}

$comment->setId($this->getRequestParameter('id'));
$comment->setPostId($this->getRequestParameter('post_id'));
$comment->setAuthor($this->getRequestParameter('author'));
$comment->setEmail($this->getRequestParameter('email'));
$comment->setBody($this->getRequestParameter('body'));

$comment->save();

return $this->redirect('post/show?id='.$comment->getPostId());
}



Это уже похоже на веб дневник.

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

понедельник, 25 февраля 2008 г.

Строим Blog на Symfony

Имеем:

  1. установленный XAMPP на Windows в каталоге C;\xampp;
  2. развернут framework Symfony;
  3. Apache22 поднят на localhost:80;
  4. пользователем MySQL5 является root с паролем 123;
  5. в php поднят PEAR.

Хотим:
  1. Создать проект на Symfony;
  2. Создать приложение Blog в проекте.


Дальше идет вольный пересказ наставления, взятого с symfony-project.org.

Создаём проект prod

Создаём каталог С:\xampp\htdocs\prod

  1. cd С:\xampp\htdocs\prod
  2. С:\xampp\htdocs\prod> symfony init-project prod

Создаём приложение blog
  • С:\xampp\htdocs\prod> symfony init-app blog

Проектируем базу данных prod, содержащую две таблицы post и comment

  • Редактируем файл С:\xampp\htdocs\prod\config\schema.yml:


propel:
post:
id: ~
title: varchar(255)
excerpt: longvarchar
body: longvarchar
created_at: ~
comment:
id: ~
post_id: ~
author: varchar(255)
email: varchar(255)
body: longvarchar
created_at: ~

Генерим модель, т.е. class Post и class Comment, которые появятся в E:\xampp\htdocs\prod\lib\model

  • С:\xampp\htdocs\prod> symfony propel-build-model

Генерим базу данных

  • С:\xampp\htdocs\prod> symfony propel-build-sql

Получаем скрипт E:\xampp\htdocs\prod\data\sql\lib.model.schema.sql

SET FOREIGN_KEY_CHECKS = 0;

#-----------------------------------------------------------------------------
#-- post
#-----------------------------------------------------------------------------

DROP TABLE IF EXISTS `post`;


CREATE TABLE `post`
(
`id` INTEGER NOT NULL AUTO_INCREMENT,
`title` VARCHAR(255),
`excerpt` TEXT,
`body` TEXT,
`created_at` DATETIME,
PRIMARY KEY (`id`)
)Type=MyISAM;

#-----------------------------------------------------------------------------
#-- comment
#-----------------------------------------------------------------------------

DROP TABLE IF EXISTS `comment`;


CREATE TABLE `comment`
(
`id` INTEGER NOT NULL AUTO_INCREMENT,
`post_id` INTEGER,
`author` VARCHAR(255),
`email` VARCHAR(255),
`body` TEXT,
`created_at` DATETIME,
PRIMARY KEY (`id`),
INDEX `comment_FI_1` (`post_id`),
CONSTRAINT `comment_FK_1`
FOREIGN KEY (`post_id`)
REFERENCES `post` (`id`)
)Type=MyISAM;

# This restores the fkey checks, after having unset them earlier
SET FOREIGN_KEY_CHECKS = 1;

Создаем базу данных prod

  • http://localhost/phpmyadmin/

Редактируем права доступа к базе
  • c:\xampp\htdocs\prod\config\databases.yml


all:
propel:
class: sfPropelDatabase
param:
dsn: mysql://root:123@localhost/prod



  • c:\xampp\htdocs\prod\config\propel.ini


propel.targetPackage = lib.model
propel.packageObjectModel = true
propel.project = prod
propel.database = mysql
propel.database.createUrl = mysql://root:123@localhost/
propel.database.url = mysql://root:123@localhost/prod



  • Наполняем базу данных

С:\xampp\htdocs\prod> symfony propel-insert-sql

Создаем виртуальный хост для проекта

  • С:\xampp\apache\conf\extra\httpd-vhosts.conf

<Directory "c:/xampp/php/pear/data/symfony/web/sf">
Allow from All
</directory>

<virtualhost>
DocumentRoot "c:/xampp/htdocs/prod/web"
DirectoryIndex index.php
Alias /sf "c:/xampp/php/pear/data/symfony/web/sf"

<directory>
AllowOverride All
Order deny,allow
Allow from all
</directory>
</virtualhost>

  • С:\xampp\apache\conf\httpd.conf
Listen 89

  • Прегружаем httpd

  • Создаем приложения
  1. c:\xampp\htdocs\prod> symfony propel-generate-crud blog post Post
  2. c:\xampp\htdocs\prod> symfony propel-generate-crud blog comment Comment
  3. c:\xampp\htdocs\prod> symfony clear-cache

  • Проверяем работу

  1. http://localhost:89/blog_dev.php/post

  2. http://localhost:89/blog_dev.php/comment