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

воскресенье, 13 апреля 2008 г.

Вопросы и ответы

propel:

  _attributes:   { noXsd: false, defaultIdMethod: none, package: lib.model }

 

  ask_question:

    _attributes: { phpName: Question, idMethod: native }

    id:          { type: integer, required: true, primaryKey: true, autoIncrement: true }

    user_id:     { type: integer, foreignTable: ask_user, foreignReference: id }

    title:       { type: longvarchar }

    body:        { type: longvarchar }

    created_at:  ~

    updated_at:  ~

 

  ask_answer:

    _attributes: { phpName: Answer, idMethod: native }

    id:          { type: integer, required: true, primaryKey: true, autoIncrement: true }

    question_id: { type: integer, foreignTable: ask_question, foreignReference: id }

    user_id:     { type: integer, foreignTable: ask_user, foreignReference: id }

    body:        { type: longvarchar }

    created_at:  ~

 

  ask_user:

    _attributes: { phpName: User, idMethod: native }

    id:          { type: integer, required: true, primaryKey: true, autoIncrement: true }

    nickname:    { type: varchar(50), required: true, index: true }

    first_name:  varchar(100)

    last_name:   varchar(100)

    created_at:  ~

 

  ask_interest:

    _attributes: { phpName: Interest, idMethod: native }

    question_id: { type: integer, foreignTable: ask_question, foreignReference: id, primaryKey: true }

    user_id:     { type: integer, foreignTable: ask_user, foreignReference: id, primaryKey: true }

    created_at:  ~

 

  ask_relevancy:

    _attributes: { phpName: Relevancy, idMethod: native }

    answer_id:   { type: integer, foreignTable: ask_answer, foreignReference: id, primaryKey: true }

    user_id:     { type: integer, foreignTable: ask_user, foreignReference: id, primaryKey: true }

    score:       { type: integer }

    created_at:  ~

 

symfony propel-build-model 

symfony propel-build-sql 

mysql -u youruser -p prod < data/sql/lib.model.schema.sql 

symfony propel-insert-sql 

symfony propel-generate-crud frontend question Question 

symfony cc frontend config 

http://prod/question 

 


Шаблон

В apps/frontend/templates/layout.php) меняем:


<!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 echo include_http_metas() ?>

<?php echo include_metas() ?>

<?php echo include_title() ?>

<link rel="shortcut icon" href="/favicon.ico" />

</head>

<body>

  <div id="header">

    <ul>

      <li><?php echo link_to('about', '@homepage') ?></li>

    </ul>

    <h1><?php echo link_to(image_tag('prod_logo.gif', 'alt=prod'), '@homepage') ?></h1>

  </div>

  <div id="content">

    <div id="content_main">

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

      <div class="verticalalign"></div>

    </div>

    <div id="content_bar">

      <!-- Nothing for the moment -->

      <div class="verticalalign"></div>

    </div>

  </div>

</body>

</html>

Добавим стили в frontend/config/view.yml:

stylesheets:    [main, layout]

Переопределим default homepage


prod/apps/frontend/config/routing.yml:


homepage:

  url:   /

  param: { module: question, action: list }

Определим данные для теста


Создать prod/data/fixtures/

Создать test_data.yml:


User:

  anonymous:

    nickname:   anonymous

    first_name: Anonymous

    last_name:  Coward

  fabien:

    nickname:   fabpot

    first_name: Fabien

    last_name:  Potencier

  francois:

    nickname:   francoisz

    first_name: François

    last_name:  Zaninotto

Question:

  q1:

    title: What shall I do tonight with my girlfriend?

    user_id: fabien

    body:  |

      We shall meet in front of the Dunkin'Donuts before dinner, 

      and I haven't the slightest idea of what I can do with her. 

      She's not interested in programming, space opera movies nor insects.

      She's kinda cute, so I really need to find something 

      that will keep her to my side for another evening.

  q2:

    title: What can I offer to my step mother?

    user_id: anonymous

    body:  |

      My stepmother has everything a stepmother is usually offered

      (watch, vacuum cleaner, earrings, del.icio.us account). 

      Her birthday comes next week, I am broke, and I know that 

      if I don't offer her something sweet, my girlfriend 

      won't look at me in the eyes for another month.

  q3:

    title: How can I generate traffic to my blog?

    user_id: francois

    body:  |

      I have a very swell blog that talks 

      about my class and mates and pets and favorite movies.

Interest:

  i1: { user_id: fabien, question_id: q1 }

  i2: { user_id: francois, question_id: q1 }

  i3: { user_id: francois, question_id: q2 }

  i4: { user_id: fabien, question_id: q2 }

Batch skeleton


Создать файл load_data.php в prod/batch/:


<?php 

define('SF_ROOT_DIR',    realpath(dirname(__FILE__).'/..'));

define('SF_APP',         'frontend');

define('SF_ENVIRONMENT', 'dev');

define('SF_DEBUG',       true);

require_once(SF_ROOT_DIR.DIRECTORY_SEPARATOR.'apps'.DIRECTORY_SEPARATOR.SF_APP.DIRECTORY_SEPARATOR.'config'.DIRECTORY_SEPARATOR.'config.php');

// initialize database manager 

$databaseManager = new sfDatabaseManager();

$databaseManager->initialize();

?> 

Импорт данных 

Добавить код до конца?> в prod/batch/load_data.php :


$data = new sfPropelData();

$data->loadData(sfConfig::get('sf_data_dir').DIRECTORY_SEPARATOR.'fixtures');

$ cd /home/sfprojects/prod/batch

$ php load_data.php

Проверяем:


http://prod/frontend_dev.php

Доступ к данным


Метод executeList() в prod/apps/frontend/modules/question/actions/action.class.php и шаблон

prod/apps/frontend/modules/question/templates/listSuccess.php:

actions.class.php:


public function executeList ()

{ 

  $this->questions = QuestionPeer::doSelect(new Criteria());

} 

listSuccess.php:

...

<?php foreach ($questions as $question): ?>

<tr>

    <td><?php echo link_to($question->getId(), 'question/show?id='.$question->getId()) ?></td>

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

    <td><?php echo $question->getBody() ?></td>

    <td><?php echo $question->getCreatedAt() ?></td>

    <td><?php echo $question->getUpdatedAt() ?></td>

  </tr>

<?php endforeach; ?>

Изменим шаблон  question/list

В файле listSuccess.php из prod/apps/frontend/modules/question/templates/ изменим:


<?php use_helper('Text') ?>

<h1>popular questions</h1> 

<?php foreach($questions as $question): ?>

  <div class="question">

    <div class="interested_block">

      <div class="interested_mark" id="mark_<?php echo $question->getId() ?>">

        <?php echo count($question->getInterests()) ?>

      </div>

    </div>

    <h2><?php echo link_to($question->getTitle(), 'question/show?id='.$question->getId()) ?></h2>

    <div class="question_body">

      <?php echo truncate_text($question->getBody(), 200) ?>

    </div>

  </div>

<?php endforeach; ?>

http://prod/frontend_dev.php/

Просмотр


http://prod/frontend_dev.php/question/show/id/2

prod/apps/frontend/modules/question/actions/actions.class.php :


public function executeShow()

 {

   $this->question = QuestionPeer::retrieveByPk($this->getRequestParameter('id'));

   $this->forward404Unless($this->question);

 }

Модификация showSuccess.php 

frontend/modules/question/templates/showSuccess.php:


<?php use_helper('Date') ?>

<div class="interested_block">

  <div class="interested_mark" id="mark_<?php echo $question->getId() ?>">

    <?php echo count($question->getInterests()) ?>

  </div>

</div>

<h2><?php echo $question->getTitle() ?></h2>

<div class="question_body">

  <?php echo $question->getBody() ?>

</div>

<div id="answers">

<?php foreach ($question->getAnswers() as $answer): ?>

  <div class="answer">

    posted by <?php echo $answer->getUser()->getFirstName().' '.$answer->getUser()->getLastName() ?> 

    on <?php echo format_date($answer->getCreatedAt(), 'p') ?>

    <div>

      <?php echo $answer->getBody() ?>

    </div>

  </div>

<?php endforeach; ?>

</div>

Добавим данные answer и relevancy  в data/fixtures/test_data.yml:

Answer:

  a1_q1:

    question_id: q1

    user_id:     francois

    body:        |

      You can try to read her poetry. Chicks love that kind of things.

  a2_q1:

    question_id: q1

    user_id:     fabien

    body:        |

      Don't bring her to a donuts shop. Ever. Girls don't like to be

      seen eating with their fingers - although it's nice. 

  a3_q2:

    question_id: q2

    user_id:     fabien

    body:        |

      The answer is in the question: buy her a step, so she can 

      get some exercise and be grateful for the weight she will

      lose.

  a4_q3:

    question_id: q3

    user_id:     fabien

    body:        |

Модификация модели

prod/lib/model/User.php:


public function __toString()

{ 

  return $this->getFirstName().' '.$this->getLastName();

} 

prod/apps/frontend/modules/question/templates/showSuccess.php 

posted by <?php echo $answer->getUser() ?> 

файл  showSuccess.php:

<div class="interested_block">

  <div class="interested_mark" id="mark_<?php echo $question->getId() ?>">

    <?php echo count($question->getInterests()) ?>

  </div>

</div>

создадим _interested_user.php файл в prod/apps/frontend/modules/question/templates/:

<div class="interested_mark" id="mark_<?php echo $question->getId() ?>">

  <?php echo count($question->getInterests()) ?>

</div>

Изменим код в  listSuccess.php и showSuccess.php) на:

<div class="interested_block">

  <?php include_partial('interested_user', array('question' => $question)) ?>

</div>

Добавим поле User 
$ symfony propel-build-ысруьф
$ symfony propel-сщтмуке-ньд-ысруьф

В prod/config/schema.xml добавим ask_question :


<column name="interested_users" type="integer" default="0" /> 


propel:
_attributes:
defaultIdMethod: native
noxsd: true
ask_question:
_attributes:
phpName: Question
id:
type: integer
required: true
primaryKey: true
autoIncrement: true
user_id:
type: integer
foreignTable: ask_user
foreignReference: id
title:
type: longvarchar
body:
type: longvarchar
created_at:
type: timestamp
updated_at:
type: timestamp
interested_users:
type: integer
default: 0
stripped_title:
type: varchar
size: 255
_uniques:
unique_stripped_title:
- stripped_title
ask_answer:
_attributes:
phpName: Answer
id:
type: integer
required: true
primaryKey: true
autoIncrement: true
question_id:
type: integer
foreignTable: ask_question
foreignReference: id
user_id:
type: integer
foreignTable: ask_user
foreignReference: id
body:
type: longvarchar
created_at:
type: timestamp
relevancy_up:
type: integer
default: 0
relevancy_down:
type: integer
default: 0
ask_user:
_attributes:
phpName: User
id:
type: integer
required: true
primaryKey: true
autoIncrement: true
nickname:
type: varchar
size: 50
first_name:
type: varchar
size: 100
last_name:
type: varchar
size: 100
created_at:
type: timestamp
ask_interest:
_attributes:
phpName: Interest
question_id:
type: integer
primaryKey: true
foreignTable: ask_question
foreignReference: id
user_id:
type: integer
primaryKey: true
foreignTable: ask_user
foreignReference: id
created_at:
type: timestamp
ask_relevancy:
_attributes:
phpName: Relevancy
answer_id:
type: integer
primaryKey: true
foreignTable: ask_answer
foreignReference: id
user_id:
type: integer
primaryKey: true
foreignTable: ask_user
foreignReference: id
score:
type: integer
created_at:
type: timestamp


Перестроим модель:

$ symfony propel-build-model

$ symfony propel-build-sql

$ mysql -u youruser -p prod < data/sql/lib.model.schema.sql

$ php batch/load_data.php

$ mysql -u youruser -p prod -e "alter table ask_question add interested_users int default '0'"

Модифицируем метод save() объекта Interest


prod/lib/model/Interest.php:


public function save($con = null)

{  

    $ret = parent::save($con);

    // update interested_users in question table

    $question = $this->getQuestion();

    $interested_users = $question->getInterestedUsers();

    $question->setInterestedUsers($interested_users + 1);

    $question->save($con);

    return $ret;

} 

Для зашиты от обновления при транзакциях:

public function save($con = null)

{ 

  $con = Propel::getConnection();

  try

  {

    $con->begin();

    $ret = parent::save($con);

    // update interested_users in question table

    $question = $this->getQuestion();

    $interested_users = $question->getInterestedUsers();

    $question->setInterestedUsers($interested_users + 1);

    $question->save($con);

    $con->commit();

    return $ret;

  }

  catch (Exception $e)

  {

    $con->rollback();

    throw $e;

  }

} 

изменим template

в _interested_user.php заменим:


<?php echo count($question->getInterests()) ?>

на

<?php echo $question->getInterestedUsers() ?>

.


  • Добавим answer в schema.xml


<column name="relevancy_up" type="integer" default="0" /> 

<column name="relevancy_down" type="integer" default="0" /> 

Перестроим модель 

$ symfony propel-build-model

$ symfony propel-build-sql

$ mysql -u youruser -p prod < data/sql/lib.model.schema.sql


  • Заменим метод->save()в классе Relevancy в lib/model/Relevancy.php


public function save($con = null)

{

  $con = Propel::getConnection();

  try

  {

    $con->begin();

    $ret = parent::save();

    // update relevancy in answer table

    $answer = $this->getAnswer();

    if ($this->getScore() == 1)

    {

      $answer->setRelevancyUp($answer->getRelevancyUp() + 1);

    }

    else

    {

      $answer->setRelevancyDown($answer->getRelevancyDown() + 1);

    }

    $answer->save($con);

    $con->commit();

    return $ret;

  }

  catch (Exception $e)

  {

    $con->rollback();

    throw $e;

  }

}

Добавим Answer class в  модель:

public function getRelevancyUpPercent()

{

  $total = $this->getRelevancyUp() + $this->getRelevancyDown();

  return $total ? sprintf('%.0f', $this->getRelevancyUp() * 100 / $total) : 0;

}

public function getRelevancyDownPercent()

{

  $total = $this->getRelevancyUp() + $this->getRelevancyDown();

  return $total ? sprintf('%.0f', $this->getRelevancyDown() * 100 / $total) : 0;

}

Изменим question/templates/showSuccess.php на:

<div id="answers">

<?php foreach ($question->getAnswers() as $answer): ?>

  <div class="answer">

    <?php echo $answer->getRelevancyUpPercent() ?>% UP <?php echo $answer->getRelevancyDownPercent() ?> % DOWN

    posted by <?php echo $answer->getUser()->getFirstName().' '.$answer->getUser()->getLastName() ?> 

    on <?php echo format_date($answer->getCreatedAt(), 'p') ?>

    <div>

      <?php echo $answer->getBody() ?>

    </div>

  </div>

<?php endforeach; ?>

</div>

Добавим данные для тестирования в fixtures

Relevancy:

  rel1:

    answer_id: a1_q1

    user_id:   fabien

    score:     1

  rel2:

    answer_id: a1_q1

    user_id:   francois

    score:     -1

Альтернативная версия заголовка


в schema.xml добавим:


<column name="stripped_title" type="varchar" size="255" /> 

<unique name="unique_stripped_title"> 

  <unique-column name="stripped_title" />

</unique> 

Перестроим модель:

$ symfony propel-build-model

$ symfony propel-build-sql

$ mysql -u youruser -p prod < data/sql/lib.model.schema.sql

Custom class


создаем myTools.class.php в prod/lib/:


<?php 

class myTools

{ 

  public static function stripText($text)

  {

    $text = strtolower($text);

    // strip all non word chars

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

    // replace all white space sections with a dash

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

    // trim dashes

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

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

    return $text;

  }

} 

в prod/lib/model/Question.php добавим:

public function setTitle($v)

{ 

  parent::setTitle($v);

  $this->setStrippedTitle(myTools::stripText($v));

} 

Перегружаем изменения:

$ symfony cc

$ php batch/load_data.php

Меняем ссылки на действия show


в listSuccess.php строку


<h2><?php echo link_to($question->getTitle(), 'question/show?id='.$question->getId()) ?></h2>

Меняем на

<h2><?php echo link_to($question->getTitle(), 'question/show?stripped_title='.$question->getStrippedTitle()) ?></h2>

в actions.class.php:

public function executeShow()

{ 

  $c = new Criteria();

  $c->add(QuestionPeer::STRIPPED_TITLE, $this->getRequestParameter('stripped_title'));

  $this->question = QuestionPeer::doSelectOne($c);

  $this->forward404Unless($this->question);

} 

http://prod/frontend_dev.php/

Меняем routing правила


routing.yml в prod/apps/frontend/config/:


question:

  url:   /question/:stripped_title

  param: { module: question, action: show }

http://prod/frontend_dev.php/question/what-shall-i-do-tonight-with-my-girlfriend

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

Плагин sfJQueryTabs

= sfJQueryTabs plugin =

== Overview ==


Plugin генерирует динамическую панель управления на основе библиотеки jQuery в виде вкладок (http://stilbuero.de/jquery/tabs_3/).

== Installation ==

Установить plugin:


{{{

$ php symfony plugin-install http://plugins.symfony-project.com/sfJQueryTabsPlugin

}}}


== Configuration ==


* Разрешить plugin `sfJQueryTabs` в `settings.yml`.

`<my_project>/apps/frontend/config/settings.yml`:


all:
.settings:
enabled_modules: [default, sfJQueryTabs]

* Очистить cache


{{{

$ symfony cc

}}}


* Конфигурфция



Скопировать '''jquerytabs.yml''' в: <my_project>/plugins/sfJQueryTabs/config/examples/ to <my_project>/apps/frontend/config/

Отредактировать его
.



* Скопировать css и javascript



Copy or link (if your operation system supports it) <my_project>/plugins/sfJQueryTabsPlugin/web/* to <my_project>/web/sfJQueryTabsPlugin/


== Как вызвать? ==
{{{

http://<my_project>/<myapp>/sfJQueryTabs

}}}


== Contact ==

* Jordi Llonch ( jordi [at] laigu [dot] net ), [http://www.laigu.net]