Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM    Subskrybuj kanał ATOM dla tagu symfony Kanał ATOM (tag: symfony)

Autor wpisu: Damian Rusinek, Piotr Wierzgała, dodany: 23.02.2010 21:56, tagi: symfony

Jest to bardzo prosty i krótki wpis mówiący jak dodać biblioteki Zenda do projektu Symfony. Mimo, że to wymaga kilka linijek kodu, to często muszę tego używać i niestety ciągle zapominam :)

Na początku trzeba oczywiście skopiować folder Zend z bibliotekami. Należy go umieścić w folderze /lib/vendor.

Files structure

Następnie jeszcze kilka linijek w głównym pliku konfiguracji ProjectConfiguration.php

require_once dirname(__FILE__).'/..\lib\vendor\symfony\lib/autoload/sfCoreAutoload.class.php';
sfCoreAutoload::register();

class ProjectConfiguration extends sfProjectConfiguration
{
  public function setup()
  {
  	set_include_path(sfConfig::get('sf_lib_dir').'/vendor'.PATH_SEPARATOR.get_include_path());
  	require_once sfConfig::get('sf_lib_dir').'/vendor/Zend/Loader/Autoloader.php';
  	Zend_Loader_Autoloader::getInstance();

  	$this->enablePlugins('sfDoctrinePlugin');
  }
}

I to by było na tyle :)

Autor wpisu: Wojciech Sznapka, dodany: 01.02.2010 23:48, tagi: symfony, php

Symfony is very powerful PHP framework, one of the most popular in the PHP world. In big projects you should probably noticed, that there isn’t easy way to extend core classes, which aren’t returned by factories, for example actions classes. Every generated module has actions.class.php, which inherits from sfActions. What, if we want to have [...]

Autor wpisu: Wojciech Sznapka, dodany: 25.01.2010 21:32, tagi: symfony, php, doctrine

Few minutes ago Brent Shaffer asked on the Twitter Which is more standard, „public static function” or „static public function”? I was curious about it, so I’ve checked which convention is used in my favourite Symfony Project. Of course, I haven’t got enough time to check it manually, class by class, so I wrote simple [...]

Autor wpisu: Piotr Śliwa, dodany: 24.01.2010 07:22, tagi: php, symfony

Nie raz spotkałem się z problemem implementacji wielostronicowych formularzy w projektach w których uczestniczyłem, zazwyczaj były to formularze rejestracji, które składały się z 2-4 kroków. Podstawowe problemy które należy rozwiązać przy wykonywaniu formularza tego typu:

  • możliwie jak najprostszy, spójny i elastyczny sposób przetwarzania formularza, aby ewentualne dodanie nowego pola lub całego formularza kosztowało jak najmniej nakładu pracy
  • napisanie kodu, który będzie można również wykorzystać w przyszłości w innym projekcie
Istnieją dwa główne mechanizmy przechowywania danych z formularzy z poprzednich stron / kroków. Na pierwszy rzut oka zaprzęgnięcie sesji w tym celu wydaje się dobrym rozwiązaniem, jednakże czy tak w rzeczywistości jest? Sesja może wygasnąć podczas wypełniania długiego formularza lub też formularz może nie zostać w pełni wypełniony, co skutkuje przechowywaniem śmieci w sesji (rzutuje to również na wydajność). Oczywiście, można napisać coś w rodzaju garbage collection aby rozwiązać ten drugi problem, ale jest też inne rozwiązanie - przekazywanie danych z poprzednich kroków w ukrytych polach formularza. To również nie jest doskonałe, ale w mojej ocenie przysparza mniej problemów niż sesja.

Jeśli wiemy w jaki sposób przekazywać dane między żądaniami, zobaczmy jak to by wyglądało w praktyce.

(pseudokod)

[PHP]
  1. $forms = array(/* tablica obiektów formularzy dla poszczególnych stron*/);
  2.  
  3. if(/*wysłano formularz*/)
  4. {
  5. $page = /*strona obecnego formularza, załóżmy że numerowanie zaczyna się od 0 */;
  6. $values = /*dane wysłane postem*/;
  7. $fail = null;//pierwszy formularz, który nie przeszedł walidacji
  8.  
  9. //waliduj wszystkie formularze do ostatnio wysłanego
  10. for($i=0; $i<$page; $i++)
  11. {
  12. if(!$forms[$i]->isValid($values))
  13. {
  14. $fail = $forms[$i];
  15. break;
  16. }
  17. }
  18.  
  19. //wystąpił błąd
  20. if($fail)
  21. {
  22. //wyświetl $i-ty formularz z komunikatami błędów
  23. //oraz poprawnie zweryfikowane formularze jako ukryte pola
  24. }
  25. else
  26. {
  27. if(/* wysłano i zweryfikowano formularze ze wszystkich stron */)
  28. {
  29. //zapisanie danych do bazy danych i przekierowanie
  30. }
  31. }
  32. }
  33.  
  34. if(!$fail)
  35. {
  36. //wyświetl obecny formularz
  37. echo $forms[$page];
  38. for($i=0; $i<$page; $i++)
  39. {
  40. //wyświetl poprzednie formularz jako ukryte pola formularzy
  41. }
  42. }

W powyższym rozwiązaniu cała logika obsługi wielostronicowego formularza jest skumulowana w jednym miejscu. To znacznie lepsze rozwiązanie niż obróbka formularzy z kolejnych kroków w innej akcji kontrolera. Dzięki powyższemu rozwiązaniu dodawanie kolejnych formularzy nie stanowi problemu, należy jedynie do tablicy $forms dodać kolejny obiekt formularza (lub tablicę reprezentującą formularz?) na odpowiednim miejscu oraz ewentualnie zmienić kod wykonywany po weryfikacji wszystkich formularzy.

Pierwszy punkt z listy przedstawionej na początku artykułu został spełniony: sposób przetwarzania jest dosyć prosty, spójny i elastyczny. Pozostaje problem przenośności kodu.

Plugin do obsługi wielostronicowych formularzy dla symfony

Swego czasu napisałem plugin do obsługi wielostronicowych formularzy dla frameworku symfony. Jego główne zadania to rozdzielanie wartości parametrów, walidacja poszczególnych formularzy oraz ukrycie przed programistą problemu przenoszenia danych między żądaniami.

Tworzenie własnego wielostronicowego formularza.

[PHP]
  1. class Form extends psPageableForm
  2. {
  3. public function setup()
  4. {
  5. $this->addForm(new Form1());
  6. $this->addForm(new Form2());
  7. $this->addForm(new Form3());
  8.  
  9. $this->setNameFormat('form[%s]');
  10. }
  11. }

Jednym ze sposobów stworzenia wielostronicowego formularza jest nadpisanie klasy psPageableForm i w metodzie setup (lub configure) dodanie kolejnych formularzy.

Przetwarzanie formularza tego typu będzie zbliżone do tego zaprezentowanego na pierwszym listingu - algorytm jest niemalże ten sam, z tą różnicą, że część zadań wykonują klasy pluginu.

[PHP]
  1. //kontroler
  2. public function executeProcessForm(sfWebRequest $request)
  3. {
  4. $page = (int) $request->getParameter('step', 1);
  5. $form = $request->hasAttribute('form') ? $request->getAttribute('form') : new Form();
  6. $form->setPage($page);
  7.  
  8. if($request->isMethod('post'))
  9. {
  10. //jeśli ta metoda została wywołana po błędzie walidacji poprzedniego formularza
  11. //nie przeprowadzaj walidacji
  12. if($request->getAttribute('return') != 1){
  13. $form->bind($request->getParameter('form'));
  14. if(!$form->isValid()){
  15. //numer strony to numer pierwszego niepoprawnego formularza
  16. $page = $form->getFirstInvalidForm()->getOption('page');
  17. $request->setParameter('step', $page);
  18.  
  19. //utawić atrybuty żądania, aby przekazać zwalidowany formularz
  20. $request->setAttribute('return', 1);
  21. $request->setAttribute('form', $form);
  22.  
  23. //wywołanie rekurencyjne akcji aby wyświetlić formularz
  24. //który nie przeszedł walidacji
  25. return $this->executeProcessForm($request);
  26.  
  27. //zweryfikowano ostatni formularz
  28. }elseif($page > $form->getPages()){
  29. //zapisanie danych do bazy
  30. $this->redirect(/*przekierowanie*/);
  31. }
  32. }
  33. }
  34. else
  35. {
  36. $form->setPage(1);
  37. }
  38.  
  39. $this->form = $form;
  40. }
  41.  
  42. //widok
  43. echo $form->getCurrentForm();
  44. //wyświetlenie ukrytych pól formularza
  45. echo $form->persist();

Czytaj dalej tutaj (rozwija treść wpisu)
Czytaj dalej na blogu autora...

Autor wpisu: Wojciech Sznapka, dodany: 28.10.2009 00:47, tagi: symfony, php

Ostatnio zetknąłem się z problemem wspólnych partiali dla wszystkich aplikacji w projekcie Symfony (dokładnie frontend i backend). Dokładniej, to te partiale były templatkami mailowymi, wysyłanymi zarówno przy zdarzeniach wygenerowanych w frontendzie jak i w panelu administracyjnym. Jako, że ponad wszystko cenię zasadę DRY (Don’t Repeat Yourself, czyli Nie Powtarzaj Się), chciałem, aby moje templatki były [...]

Autor wpisu: Łukasz Rodziewicz, dodany: 18.07.2009 23:12, tagi: php, symfony

Propel generators are very useful tool, they automate creating of most common CRUD modules. However default theme have serial issues. Mostly, html forms are based on tables and list is not a sfPropelPager.

But there is an easy way to make your own theme based on symfony default. You can find it into sf_pear_dir/data/generator/sfPropelModule/default and add/modify whatever you want. To use it in your app just putt it into sf_project_dir/data/geneator/sfPropelModule directory.

Then using symfony console script use “theme” argument:

empathon@aden ~/workspace/example $ symfony propel:generate-module backend author Author --with-show --theme=clean

I have create my own custom theme with forms on divs, pager, flash messege on delete and create/edit. You can download it here.

Udpate: Few errors fixed.

Autor wpisu: Łukasz Rodziewicz, dodany: 13.07.2009 04:56, tagi: php, symfony

That was tricky. I hope it will help somebody.

<?php
class SomeForm extends sfForm
{
	//..
 
	/**
	 * Return array of current errors
	 *
	 * @return array
	 */
	public function getErrorsArray()
	{
		$errors = $embedded_forms_name = array();
		foreach($this->getEmbeddedForms() as $embedded_form){
			$embedded_forms_name[] = $embedded_form->getName();
		}
		foreach($this as $field){
			if($field->hasError())
			{
				if(in_array($field->getName(), $embedded_forms_name)){
					foreach($field as $field_embedded){
						if($field_embedded->hasError()) $errors[$field->getName().'_'.$field_embedded->getName()] = $field_embedded->getError()->__toString();
					}
				} else {
					$errors[$field->getName()] = $field->getError()->__toString();
				}
			}
		}
		return $errors;
	}
}

For embedded forms it return embedded form name plus field name as a key. You got an idea ;-) It should be standard feature IMHO.

Update: Of course there is a easier way if you don’t have embedded forms:

//...
foreach ($this as $field) {
	$field->hasError() ? $errors[$field->getName()] = $field->getError()__toString() : null;
}

or

//...
foreach ($this->getErrorSchema()->getErrors() as $name => $error) {
	$errors[$name] = $error->getMessageFormat();
}
Wszystkie wpisy należą do ich twórców. PHP.pl nie ponosi odpowiedzialności za treść wpisów.