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

пятница, 14 ноября 2008 г.

Symfony 1.2: file upload in admin

Это черновик

/backend/modules/author/lib/form/myAuthorForm.class.php

/**
* Author form.
*
* @package any
* @subpackage form
* @author Your name here
* @version SVN: $Id: sfPropelFormTemplate.php 10377 2008-07-21 07:10:32Z dwhittle $
*/
class myAuthorForm extends BaseAuthorForm
{
public function configure()
{
$this->setWidget('description', new myWidgetFormRichTextarea(array('editor'=>'fck')));
$values = $this->getValues();
$this->setWidget('pic', new myWidgetFormInputFileEditable(
array(
'is_image' => true,
'delete_label' => 'удалить'
)));
//$this->setWidget('pic', new sfWidgetFormInputFile());
$this->setWidget('avatar', new sfWidgetFormInputFile());
/* VALIDATORS */
$this->setValidators(array(
'f_name' => new sfValidatorString(
array(),
array('required' => 'Обязательное поле')
),
'l_name' => new sfValidatorString(
array(),
array('required' => 'Обязательное поле')
),
'email' => new sfValidatorEmail(
$options = array(),
$messages = array(
'invalid' => 'Введите правильный Email',
'required' => false)
),
'pic' => new sfValidatorFile(array(
'required' => false,
'max_size' => '102400', // bytes (1MB)
'mime_types' => array('image/png', 'image/jpeg',)
)),
));

//$this->widgetSchema->setNameFormat('%s');

$this->validatorSchema->setOption('allow_extra_fields', true);
$this->validatorSchema->setOption('filter_extra_fields', false);
}//configure

public function updateObject($values = null)
{
$object = parent::updateObject();
$path = sfConfig::get('sf_root_dir').DIRECTORY_SEPARATOR.
sfConfig::get('sf_web_dir_name').DIRECTORY_SEPARATOR.sfConfig::get('sf_upload_dir');
$object->setPic(str_replace($path.'/', '', $object->getPic()));
return $object;
}
/* do save*/
protected function doSave($con = null){
$values = $this->getValues();

$path = sfConfig::get('sf_root_dir').'/'.
sfConfig::get('sf_web_dir_name').'/'.sfConfig::get('sf_upload_dir');

if (isset($values['pic_delete'])){
$currentFile = $path.'/'.$this->getObject()->getPic();
if (is_file($currentFile)){
unlink($currentFile);
}
$this->getObject()->setPic('');
}

$file = $values['pic'];

if(!empty($file)){
if (file_exists(sfConfig::get('sf_upload_dir').'/'.$this->getObject()->getPic())){
@unlink($this->getObject()->getPic());
}
$filename = sha1($file->getOriginalName()).$file->getExtension($file->getOriginalExtension());
$path = sfConfig::get('sf_root_dir').DIRECTORY_SEPARATOR.sfConfig::get('sf_web_dir_name').DIRECTORY_SEPARATOR.sfConfig::get('sf_upload_dir');
$file->save($path.'/'.$filename);
}

return parent::doSave($con);
}
}//class

/lib/myWidgetFormInputFileEditable.class.php

/*
* This file is part of the symfony package.
* (c) Fabien Potencier
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

/**
* sfWidgetFormInputFileEditable represents an upload HTML input tag with the possibility
* to remove a previously uploaded file.
*
* @package symfony
* @subpackage widget
* @author Fabien Potencier
* @version SVN: $Id: sfWidgetFormInputFileEditable.class.php 11544 2008-09-14 17:40:07Z fabien $
*/
class myWidgetFormInputFileEditable extends sfWidgetFormInputFile
{
/**
* Constructor.
*
* Available options:
*
* * file_src: The current image web source path (required)
* * edit_mode: A Boolean: true to enabled edit mode, false otherwise
* * is_image: Whether the file is a displayable image
* * with_delete: Whether to add a delete checkbox or not
* * delete_label: The delete label used by the template
* * template: The HTML template to use to render this widget
* The available placeholders are:
* * input (the image upload widget)
* * delete (the delete checkbox)
* * delete_label (the delete label text)
* * file (the file tag)
*
* In edit mode, this widget renders an additional widget named after the
* file upload widget with a "_delete" suffix. So, when creating a form,
* don't forget to add a validator for this additional field.
*
* @param array $options An array of options
* @param array $attributes An array of default HTML attributes
*
* @see sfWidgetFormInputFile
*/
protected function configure($options = array(), $attributes = array())
{
parent::configure($options, $attributes);

$this->setOption('type', 'file');
$this->setOption('needs_multipart', true);

//$this->addRequiredOption('file_src');
$this->addOption('file_src', '');
$this->addOption('is_image', false);
$this->addOption('edit_mode', true);
$this->addOption('with_delete', true);
$this->addOption('delete_label', 'remove the current file');
$this->addOption('template', '%file% %input% %delete% %delete_label%');
}

/**
* @param string $name The element name
* @param string $value The value displayed in this widget
* @param array $attributes An array of HTML attributes to be merged with the default HTML attributes
* @param array $errors An array of errors for the field
*
* @return string An HTML tag string
*
* @see sfWidgetForm
*/
public function render($name, $value = null, $attributes = array(), $errors = array())
{

$input = parent::render($name, $value, $attributes, $errors);

if (!$this->getOption('edit_mode'))
{
return $input;
}

if ($this->getOption('with_delete')){
$deleteName = ']' == substr($name, -1) ? substr($name, 0, -1).'_delete]' : $name.'_delete';
$delete = $this->renderTag('input', array_merge(array('type' => 'checkbox', 'name' => $deleteName), $attributes));
$deleteLabel = $this->renderContentTag('span', $this->getOption('delete_label'), array_merge(array('for' => $this->generateId($deleteName))));
} else {
$delete = '';
$deleteLabel = '';
}
if ($value){
$picLink = " || <a class='thickbox' target='_blank' href='/uploads/".$value."'>show me</a>";
} else {
$picLink = "";
$delete = '';
$deleteLabel = '';
}

return strtr($this->getOption('template'), array(
'%input%' => $input,
'%delete%' => $delete,
'%delete_label%' => $deleteLabel,
'%file%' => $this->getFileAsTag($attributes, $value))
).$picLink;
}

protected function getFileAsTag($attributes, $value=null)
{
if ($this->getOption('is_image'))
{
return false !== $value ? $this->renderTag('img', array_merge(array('src' => $value)), $attributes) : '';
}
else
{
return $this->getOption('file_src');
}
}
}

/backend/config/view.yml
default:
http_metas:
content-type: text/html
metas:
title: Admin
stylesheets: [main, thickbox]
javascripts: [jq/jquery.pack.js, jq/thickbox.pack.js]

вторник, 11 ноября 2008 г.

Symfony 1.2: вышло обновление - beta2

Очень оперативно работают парни, 10 дней прошло после выхода beta1, и вот вам обновление.
Список "фиксов" тут:
http://trac.symfony-project.org/query?status=closed&milestone=1.2.0+BETA2

Теперь о неприятном ;)
После обновления я сразу получил ошибку
500 | Internal Server Error | sfConfigurationException
The route "articles_collection" does not exist.


Видимо опять что то изменилось в системе роутинга, беглый просмотр офиц.сайта не дал ответа что далать, пришлось "методом научного тыка" сделать костыль.
articles_collection:
url: /article/:action/*

articles:
class: sfPropelRouteCollection
options:
model: Article
module: article
with_show: false
collection_actions: { filter: post, batch: post }

Не знаю, прав ли я???

среда, 5 ноября 2008 г.

Symfony 1.2: подводные камни

1. В схеме нельзя давать имя модели Comment, это имя теперь зарезервировано Propel 1.3, используйте BlogComment и т.п.

2. Новый админ-генератор использует routing.yml, перед генерацией админки надо обязательно вписать в него блок такого типа:
articles:
class: sfPropelRouteCollection
options:
model: BlogArticle
module: article
collection_actions: { filter: post, batch: post }

Внимание!!!
Блок вставлять в начало routing.yml иначе получите ошибку
404 | Not Found | sfError404Exception
Action "articles/index" does not exist.

3. Помимо генерации модели и форм командами propel:generate-model, propel:generate-forms, теперь еще надо генерировать и фильтры(при первом взгляде те же формы) командой propel:generate-filters. Либо просто propel:generate-all.

...to be continued...

среда, 15 октября 2008 г.

Symfony admin generator: is_published + AJAX

Часто приходится открывать запись на редактирование только ради того что бы поставить галочку "опубликовано"
Сделаем это нажатием на иконку статуса в списке.
Для работы с AJAX используем jQuery.
/backend/config/view.yml

default:
...
javascripts: [jq/jquery.pack.js]


/backend/templates/layout.php

<script>
jQuery(document).ready(function($){
$("body").after("<div id='result_div'></div>");
$("#result_div").html("<img style='padding: 20px' src='/images/loading.gif' align='absmiddle' /> обработка...");
$("#result_div").hide();
$("#result_div").css({
"background-color": "#ffffcc",
"opacity": "0.7",
"width": "40%",
"height": "auto",
"font-family": "Arial Tahoma",
"text-align": "center",
"vertical-align": "middle",
"border": "1px solid silver",
"position": "absolute",
"top": "40%",
"left": "30%",
"z-index": "9999"
});
});
</script>


Изменяем _is_published.php

<center>
<?php echo
link_to(
image_tag(sfConfig::get('sf_admin_web_dir')."/images/".
($myObject->getIsPublished() ? 'ok.png' : 'cancel.png'),
array('id' => 'switch_status_'.$myObject->getId())
),
"my_module/switchStatus?id=".$myObject->getId(),
array(
'class' => 'switch_status',
'rel' => 'switch_status_'.$myObject->getId(),
'pic_dir' => sfConfig::get('sf_admin_web_dir')."/images/",
)
);//link to
?>
</center>


Добавлем файл my_module/templates/_list_footer.php

<script>
$(document).ready(function() {
$(".switch_status").each( function (){
$(this).click( function (){
var popupX = Math.round( ($(window).width() - $("#result_div").width()) / 2) ;
var popupY = $(document).scrollTop() + Math.round($(window).height()/2) -
Math.round($("#result_div").height()/2);
$("#result_div").css({top: popupY+"px", left: popupX+"px"});
var pic_dir = $(this).attr("pic_dir")
var pic_id = $(this).attr("rel")
$("#result_div").slideDown("slow");

$.ajax({
type: "POST",
url: $(this).attr('href'),
data: "",
success: function(msg){
var pic_name = (msg == 1 ? "ok" : "cancel") + ".png"
$("#"+pic_id).attr("src", pic_dir + "/" + pic_name)
$("#result_div").slideUp("slow");
}
});//ajax
return false;
})//click
})//each
});
</script>


Добавляем новый метод executeSwitchStatus в модуль my_module

public function executeSwitchStatus($request){
$myObject = xxxPeer::retrieveByPk($this->getRequestParameter('id'));
$currentStatus = $myObject->getIsPublished();
$newStatus = ($currentStatus == 1 ? 0 : 1);

$myObject->setIsPublished($newStatus);
$myObject->save();

$isAjax = $request->isXmlHttpRequest();

if ($isAjax){
return $this->renderText($newStatus);
} else {
//do something if not AJAX
}//if
}//change status


Получаем

Symfony admin generator: маленькие улучшения

Очень часто в таблицах используется флажок is_published (bool)

Генератор админки его подхватывает, и ставит зеленую галочку, если is_published=1

Мы немного изменим такое поведение.
1. Создаем файл /backend/mymodule/templates/_is_published.php
и копируем в него следующее:

<center>
getIsPublished() ?
image_tag(sfConfig::get('sf_admin_web_dir').'/images/ok.png') :
image_tag(sfConfig::get('sf_admin_web_dir').'/images/cancel.png')
?>
</center>



В generator.yml

list:
fields:
...
is_published: { name: Статус }
...
display: [ ..., _is_published ]


Получаем