Krzysztof Biernacki programista PHP
Temat: [sf 1.4] Admin generator i własne rozwiązanie galerii...
Witam.W sieci natknąłem się na tutorial, który pokazuje krok po kroku w jaki sposób stworzyć galerię zdjęć na bazie admin-generatora - http://blog.karolsojko.com/index.php/2010/01/symfony-t...
Wszystko by było idealnie, gdyby nie problem z zapamiętywaniem pozycji (order dla obrazków) na liście (przesuwam na liście wybrane zdjęcia, ustawiam im kolejność, po czym po kliknięciu na button 'Zapisz' - w formularzu - ord nie jest w ogóle zapisywany do bazy danych). Zupełnie nie wiem, gdzie szukać przyczyny powyższego błędu. Może ktoś rzuci okiem i podpowie, co z tym fantem zrobić.
Na początek zawartość pliku schema.yml dla modułu gallery:
Image:
actAs:
Timestampable: ~
columns:
id:
type: integer(4)
primary: true
notnull: true
autoincrement: true
gallery_id:
type: integer(4)
notnull: true
name:
type: string(255)
notnull: true
description:
type: clob(65535)
thumb:
type: string(100)
image:
type: string(100)
notnull: true
ord:
type: integer(4)
notnull: true
relations:
modGallery:
class: ModGallery
local: gallery_id
foreign: id
foreignAlias: images
foreignType: many
owningSide: true
indexes:
fk_Image_Gallery:
fields: [gallery_id]
options:
charset: utf8
collate: utf8_unicode_ci
ModGallery:
actAs:
Timestampable: ~
columns:
id:
type: integer(4)
primary: true
notnull: true
autoincrement: true
slug:
type: string(255)
unique: true
title:
type: string(255)
add_button:
type: enum
values: ['true','false']
default: 'false'
keywords:
type: clob(65535)
description:
type: clob(65535)
text:
type: clob(65535)
delay:
type: integer(2)
relations:
module:
class: Module
local: id
foreign: id
foreignAlias: modGallerys
foreignType: one
owningSide: true
indexes:
fk_ModGallery_Module1:
fields: [id]
options:
charset: utf8
collate: utf8_unicode_ci
Zawartość pliku BackendEmbedImageForm.class.php:
class BackendEmbedImageForm extends ImageForm
{
public function configure() {
$this->disableCSRFProtection();
unset($this['gallery_id'], $this['thumb'], $this['ord'], $this['created_at'], $this['updated_at']);
$this->widgetSchema['name'] = new sfWidgetFormInput(array(), array('size' => 122, 'class' => 'artInput'));
$this->widgetSchema['image'] = new sfWidgetFormInputFileEditable(array(
'file_src' => sfConfig::get('app_gallery_thumbs_dir').$this->getObject()->getImage(),
'is_image' => true,
'edit_mode' => !$this->isNew(),
'template' => '%file% %input%'
));
$this->widgetSchema['description'] = new sfWidgetFormTextarea(array(), array('rows' => 7, 'cols' => 120, 'class' => 'no-editor'));
$this->widgetSchema->setLabels(array(
'name' => 'Tytuł zdjęcia',
'description' => 'Opis zdjęcia',
'image' => 'Plik graficzny'
));
$this->validatorSchema['name'] = new sfValidatorString(array(
'min_length' => 3,
'max_length' => 255), array(
'required' => 'Wpisz tytuł zdjęcia.',
'min_length' => 'Tytuł zdjęcia jest za krótki. Musi składać się z co najmniej %min_length% znaków.',
'max_length' => 'Tytuł zdjęcia jest za długi. Może składać się z co najwyżej %max_length% znaków.'
));
$this->validatorSchema['image'] = new myImageValidatorFile(array(
'mime_types' => array('image/jpg', 'image/jpeg', 'image/jp_', 'application/jpg', 'application/x-jpg', 'image/pjpeg', 'image/pipeg', 'image/vnd.swiftview-jpeg', 'image/x-xbitmap',
'image/gif', 'image/x-xbitmap', 'image/gi_',
'image/png', 'application/png', 'application/x-png'),
'max_size' => 1000000,
'min_width' => '640',
'min_height' => '480',
'path' => sfConfig::get('app_gallery_thumbs_dir'),
'required' => false
), array(
'min_width' => 'Wybrane zdjęcie ma zbyt małą szerokość (%width% px). Minimum to %min_width% px.',
'min_height' => 'Wybrane zdjęcie ma zbyt małą wysokość (%height% px). Minimum to %min_height% px.',
'max_size' => 'Wybrany plik graficzny jest za duży. Maksymalny rozmiar wynosi 1 MB.',
'mime_types' => 'Nieprawidłowy format graficzny pliku. Obsługiwane formaty - JPG/JPEG, PNG, GIF.'
));
$this->validatorSchema['description'] = new sfValidatorString(array('max_length' => 500, 'required' => false), array(
'max_length' => 'Skrócony opis zdjęcia jest za długi. Może składać się z co najwyżej %max_length% znaków.'
));
}
Zawartość pliku Image.class.php:
class Image extends BaseImage
{
public function save(Doctrine_Connection $conn = null) {
$uploadImagePath = sfConfig::get('app_gallery_images_dir').'/';
$uploadThumbPath = sfConfig::get('app_gallery_thumbs_dir').'/';
$pictMaxWidth = sfConfig::get('app_gallery_maxWidth'); // Maksymalna szerokość miniaturki zdjęcia
$pictMaxHeight = sfConfig::get('app_gallery_maxHeight'); // Maksymalna wysokość miniaturki zdjęcia
$imagePrefix = 'image_';
$thumbPrefix = 'thumb_';
if ($this->isModified()) {
$image = new sfThumbnail('', '', true, true, 100);
$image->loadFile($uploadThumbPath.$this->getImage());
$image->save($uploadImagePath.$imagePrefix.$this->getImage());
$thumb = new sfThumbnail('', $pictMaxHeight, true, true, 90);
$thumb->loadFile($uploadThumbPath.$this->getImage());
$thumb->save($uploadThumbPath.$thumbPrefix.$this->getImage());
unlink($uploadThumbPath.$this->getImage());
}
$this->_set('thumb', $thumbPrefix.$this->getImage());
$this->_set('image', $imagePrefix.$this->getImage());
return parent::save($conn);
}
}
Zawartość pliku ModgalleryForm.class.php:
class ModGalleryForm extends BaseModGalleryForm
{
public function configure() {
unset($this['gallery_id'], $this['ord'], $this['thumb'], $this['created_at'], $this['updated_at']);
$this->setWidgets(array(
'title' => new sfWidgetFormInput(array(), array('size' => 122, 'class' => 'artInput')),
'keywords' => new sfWidgetFormInput(array(), array('size' => 122, 'class' => 'artInput')),
'description' => new sfWidgetFormTextarea(array(), array('rows' => 7, 'cols' => 120, 'class' => 'no-editor')),
'text' => new sfWidgetFormTextarea()
));
$this->setValidators(array(
'title' => new sfValidatorString(array('min_length' => 3, 'max_length' => 255), array(
'required' => 'Wpisz tytuł galerii.',
'min_length' => 'Tytuł galerii jest za krótki. Musi składać się z co najmniej %min_length% znaków.',
'max_length' => 'Tytuł galerii jest za długi. Może składać się z co najwyżej %max_length% znaków.'
)),
'keywords' => new sfValidatorString(array('required' => false
)),
'description' => new sfValidatorString(array('required' => false
)),
'text' => new sfValidatorString(array('required' => false
))
));
$this->widgetSchema->setNameFormat('gallery[%s]');
// Embed form
$imageForm = new BackendEmbedImageForm();
$this->embedForm('image', $imageForm);
$this->widgetSchema['image']->setLabel('Nowe zdjęcie');
}
public function bind(array $taintedValues = null, array $taintedFiles = null) {
if (is_null($taintedValues['image']['name']) || strlen($taintedValues['image']['name']) === 0 ) {
unset($this->embeddedForms['image'], $taintedValues['image']);
$this->validatorSchema['image'] = new sfValidatorPass();
} else {
$this->embeddedForms['image']->getObject()->setModGallery($this->getObject());
}
$output = parent::bind($taintedValues, $taintedFiles);
foreach ($this->embeddedForms as $name=>$form) {
$this->embeddedForms[$name]->isBound = true;
$this->embeddedForms[$name]->values = $this->values[$name];
}
return $output;
}
}
Zawartość pliku sortList.js:
$(document).ready(function() {
$("#images-list").sortable({
handle : '.handle',
update : function () {
var order = $('#images-list').sortable('serialize');
$("#info").load("sort-images?"+order);
}
});
});
Zawartość pliku konfiguracyjnego routing.yml:
modgallery:
class: sfDoctrineRouteCollection
options:
model: ModGallery
module: gallery
prefix_path: /gallery
column: id
with_wildcard_routes: true
modgallery_sort_images:
url: /gallery/:id/sort-images
param: { module: gallery, action: sortImages }
modgallery_delete_image:
url: /gallery/:id/delete
param: { module: gallery, action: deleteImage }
Fragment pliku actions.class.php:
public function executeSortImages(sfWebRequest $request) {
foreach($request->getParameter('listItem') as $position => $item) {
$image = Doctrine::getTable('Image')->findOneById($item);
if($image != null) {
$image->setOrd($position);
$image->save();
}
}
return sfView::NONE;
}
Zawartość pliku konfuguracyjnego generator.yml:
<?php $i18n = sfContext::getInstance()->getI18n() ?>
generator:
class: sfDoctrineGenerator
param:
model_class: Modgallery
theme: admin
non_verbose_templates: true
with_show: false
singular: ~
plural: ~
route_prefix: modgallery
with_doctrine_route: true
actions_base_class: sfActions
config:
actions:
_new: { label: "Dodaj galerię", credentials: [superadmin, useradmin] }
fields:
title: { label: Tytuł }
created_at: { label: Data utworzenia }
updated_at: { label: Data aktualizacji }
keywords: { label: Słowa kluczowe }
description: { label: Skrócony opis (description) }
text: { label: Treść }
list:
title: Zarządzanie galeriami zdjęć
display: [id, title, created_at, updated_at]
sort: [id, asc]
max_per_page: 25
actions:
_new: { credentials: [superadmin, useradmin] }
batch_actions:
_delete: { credentials: [superadmin, useradmin] }
object_actions:
_edit: { credentials: [superadmin] }
_delete: { credentials: [superadmin, useradmin] }
filter:
display: [title, created_at, updated_at]
fields:
created_at: { }
updated_at: { }
form:
display:
"Zdjęcia": [~showImages, image]
"Galeria": [title, keywords, description, text]
edit:
title: Edycja galerii zdjęć - "%%title%%"
new:
title: Dodaj galerię zdjęć
Zawartość pliku components.class.php:
public function executeShowImages(sfWebRequest $request) {
$request->getParameter('id') ? $galleryId = $request->getParameter('id') : $galleryId = 1;
if ($galleryId) {
$q = Doctrine_Query::create()->from('Image i')
->where('i.gallery_id = ?', $galleryId)
->orderBy('i.ord ASC');
$this->images = $q->execute();
} else
$this->redirect('@modgallery');
}
Zawartość pliku _showImages.php:
<?php use_stylesheet('backend/theme/sjagd/imageList.css'); ?>
<?php use_javascript('backend/sortList.js'); ?>
<?php use_helper('jQuery'); ?>
<?php jq_add_plugins_by_name(array('sortable')); ?>
<?php
use_stylesheet('/highslide/highslide');
use_javascript('/highslide/highslide-full');
use_helper('JavascriptBase');
echo javascript_tag("
hs.graphicsDir = 'highslide/graphics/';
hs.outlineType = 'rounded-white';
hs.dimmingOpacity = 0.75;
hs.fadeInOut = true;
hs.align = 'center';
hs.captionEval = 'this.a.title';
hs.addSlideshow({
slideshowGroup: 'group1',
interval: 3000,
repeat: false,
useControls: true,
fixedControls: 'fit',
overlayOptions: {
opacity: '0.75',
position: 'bottom center',
offsetX: '0',
offsetY: '-15',
hideOnMouseOut: true
}
});
var config1 = {
slideshowGroup: 'group1',
thumbnailId: 'gallery-opener1',
numberPosition: 'caption',
transitions: ['expand', 'crossfade']
};
");
$thumbsPath = sfConfig::get('app_gallery_thumbs_dir').'/';
$imagesPath = sfConfig::get('app_gallery_images_dir').'/';
$noThumb = '__noThumb.jpg';
?>
<?php if (empty($images[0])): ?>
<div class="info"><?php echo __('Brak zdjęć w galerii.') ?></div>
<?php endif; ?>
<div id="info"></div>
<div id="imagesList">
<ul id="images-list">
<?php foreach ($images as $image): ?>
<li id="listItem_<?php echo $image->getId(); ?>">
<?php echo image_tag('/sfDoctrinePlugin/images/arrow.png', array('alt' => __('Przesuń'), 'title' => __('Przesuń'), 'size' => '16x16', 'class' => 'handle')) . __('Przesuń') ?>
<div class="spacerSmall"><strong><?php echo $image->getName(); ?></strong></div>
<?php if ($image->getThumb() && is_file($thumbsPath.$image->getThumb()) && $image->getImage() && is_file($imagesPath.$image->getImage())): ?>
<div class="sf_admin_form_row sf_admin_text sf_admin_form_field_image">
<?php if ($image->getDescription() != ''): ?>
<div style="float: right; width: 600px; height: auto"><?php echo $image->getDescription() ?></div>
<?php endif; ?>
<div>
<label for="image_url"><?php echo __('Podgląd zdjęcia') ?></label>
<a href="<?php echo $imagesPath.$image->getImage() ?>" class="highslide" onclick="return hs.expand(this,{wrapperClassName: 'borderless floating-caption', dimmingOpacity: 0.75, align: 'center'})"><img src="<?php echo $thumbsPath.$image->getThumb() ?>" title="" alt="" /></a>
</div>
</div>
<?php elseif ($image->getThumb() && is_file($thumbsPath.$image->getThumb()) && !$image->getImage() && !is_file($imagesPath.$image->getImage())): ?>
<div class="sf_admin_form_row sf_admin_text sf_admin_form_field_image">
<?php if ($image->getDescription() != ''): ?>
<div style="float: right; width: 600px; height: auto"><?php echo $image->getDescription() ?></div>
<?php endif; ?>
<div>
<label for="image_url"><?php echo __('Podgląd zdjęcia') ?></label>
<?php echo image_tag('/'.$thumbsPath.$image->getThumb(), array('title' => '', 'alt' => '')); ?>
</div>
</div>
<?php elseif ($image->getThumb() && is_file($thumbsPath.$image->getThumb()) && !is_file($imagesPath.$image->getImage())): ?>
<div class="sf_admin_form_row sf_admin_text sf_admin_form_field_image">
<?php if ($image->getDescription() != ''): ?>
<div style="float: right; width: 600px; height: auto"><?php echo $image->getDescription() ?></div>
<?php endif; ?>
<div>
<label for="image_url"><?php echo __('Podgląd zdjęcia') ?></label>
<?php echo image_tag('/'.$thumbsPath.$image->getThumb(), array('title' => '', 'alt' => '')); ?>
</div>
</div>
<?php else: ?>
<div class="sf_admin_form_row sf_admin_text sf_admin_form_field_image">
<?php if ($image->getDescription() != ''): ?>
<div style="float: right; width: 600px; height: auto"><?php echo $image->getDescription() ?></div>
<?php endif; ?>
<div>
<?php echo image_tag('/'.$thumbsPath.$noThumb, array('title' => 'Brak zdjęcia', 'alt' => __('Brak zdjęcia'))); ?>
</div>
</div>
<?php endif; ?>
<?php echo jq_link_to_remote(image_tag('/sfDoctrinePlugin/images/delete.png', array(
'title' => __('Skasuj'),
'alt' => __('Skasuj'))) . __('Skasuj'), array(
'confirm' => __('Czy na pewno chcesz usunąć wybrane zdjęcie?'),
'url' => '@modgallery_delete_image?id=' . $image->getId(),
'complete' => '$("#listItem_' . $image->getId() . '").hide();',
), array('style' => 'background-image: none;')); ?>
</li>
<?php endforeach; ?>
</ul>
</div>