Niezalogowany [ logowanie ]
Subskrybuj kanał ATOM Kanał ATOM

Autor wpisu: Kamil Adryjanek, dodany: 20.10.2012 13:27, tagi: symfony2, php

Today i would like to share my recent experience on forms and data dependent fields. Playing with Symfony2 forms some time ago i was looking for best solutions of adding fields to forms that depend on the data / Doctrine object – there was nothing about it in the official Symfony documentation. I thought, as many other developers that the best / easiest way is to pass the current object in form constuctor. Today i know it was wrong but what is the recommended solution? Is there any easy way to add / remove form fields?

Imagine a scenario:

Implementing form in the old way i will write code:

<?php

namespace My\AdminBundle\Form;

use My\AdminBundle\Entity\User;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class UserType extends AbstractType
{
    protected $user = null;

    public function __construct(User $user)
    {
      $this->user = $user;
    }

    public function buildForm(FormBuilderInterface $builder, array $options)
    {
      $builder
        ->add('firstName', 'text', array('label' => 'First name'))
        ->add('lastName', 'text', array('label' => 'Last name'))
        ->add('email', 'email', array('label' => 'Email address'))
        ;
      // add permissions for none admin users
      if (!$this->user->isAdmin()) {
        $builder
          ->add('permissions', 'entity', array(
        'label'   => 'Access Permisson',
        'class'   => 'AdminBundle:Permission',
        'multiple'  => true,
        'expanded'  => true
      ))
      }
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'My\AdminBundle\Entity\User'
        ));
    }

    public function getName()
    {
        return 'my_adminbundle_usertype';
    }
}

But according to Bernhard Schussek the recommended way of playing with dependent fields in Symfony forms is to add / remove fields using EventListeneres on form events. Using FormEvent we can access our data object ($event->getData()), current form ($event->getForm()) and determine which fields add or remove accoridng to User object.

Yes, it may seem a bit complicated but i will try to show it in UserType example:

<?php

namespace My\AdminBundle\Form;

use My\AdminBundle\Entity\User;
use Symfony\Component\Form\FormEvent;
use Symfony\Component\Form\FormEvents;
use Symfony\Component\Form\AbstractType;
use Symfony\Component\Form\FormBuilderInterface;
use Symfony\Component\OptionsResolver\OptionsResolverInterface;

class UserType extends AbstractType
{
    public function buildForm(FormBuilderInterface $builder, array $options)
    {
      $builder
        ->add('firstName', 'text', array('label' => 'First name'))
        ->add('lastName', 'text', array('label' => 'Last name'))
        ->add('email', 'email', array('label' => 'Email address'))
        ;
      $formFactory = $builder->getFormFactory();
      // add permissions for none admin users
      $builder->addEventListener(FormEvents::PRE_SET_DATA,
        function (FormEvent $event) use ($formFactory) {
          if (!$event-&gt;getData()->isAdmin()) {
            $event->getForm()->add($formFactory->createNamed(
              'permissions', 'entity', null, array(
                'label'   => 'Access Permisson',
                'class'   => 'AdminBundle:Permission&quot',
                'multiple'  => true,
                'expanded'  => true
            )));
          }
        }
      );
    }

    public function setDefaultOptions(OptionsResolverInterface $resolver)
    {
        $resolver->setDefaults(array(
            'data_class' => 'My\AdminBundle\Entity\User'
        ));
    }

    public function getName()
    {
        return 'my_adminbundle_usertype';
    }
}

Maybe it’s better, maybe it’s recommended way of adding dependent fields but in my opinion it also quite complicated. What about forms where we have many dependent fields? It’s a lot of code just for one filed. It really needs simplification. list of online casinos

Autor wpisu: bastard13, dodany: 20.10.2012 12:54, tagi: oop

usprawiedliwienie

Na wstępie zaznaczam, że wpis nie jest przede wszystkim o wzorcu Factory (choć pojawia się on tutaj), wątkiem przewodnim nie są również interfejsy (chociaż i one się pojawią:). Najistotniejszym elementem tego wpisu jest próba przedstawienia procesu analizy, dzięki któremu usuwamy zbędne zależności pomiędzy klasami, a powiązania przestają opierać się na konkretnych implementachach. Czytaj więcej »

Autor wpisu: zleek, dodany: 19.10.2012 11:36, tagi: css, xhtml

Bardzo często dostając projekt graficzny od grafika widzimy, że zostały tam zamieszczone niestandardowe czcionki. Pół biedy jak czcionki te są użyte na elementach, które mogą zostać wycięte i wstawione na stronę w postaci grafik. Problem pojawia się wtedy, gdy sam tekst dostarczany do elementów strony występuje przy użyciu takiej czcionki. Jest jednak na to rada. [...]

Autor wpisu: Vokiel, dodany: 12.10.2012 01:30, tagi: php

PHPCon PL 2012

Chciałem zrobić wpis zaraz po powrocie, ale byłem zbyt wyczerpany ;) Chwila moment i już dwa tygodnie minęły od tegorocznego spotkania PHPCon Poland.

Podobnie jak w latach ubiegłych, spotkanie odbyło się w Hotelu „Przedwiośnie” w Mąchocicach Kapitulnych koło Kielc (btw jeszcze raz wielkie dzięki Łukasz za podwózkę!). Tym razem jednak termin wrześniowy (28 – 30 września) zamiast październikowego z drugiej edycji. Moim zdaniem dobry wybór – bez problemu dało się wytrzymać na sobotnim grillu kilka godzin w jednej bluzie (w przeciwieństwie do ubiegłego roku).

Ponownie ilość chętnych przewyższyła możliwości pojemnościowe, rejestracja została zakończona przed czasem – już w połowie sierpnia

Agenda

W tym roku, wzorem lat ubiegłych, także pojawili się zagraniczni prelegenci: Wim Godden, Thijs Feryn oraz Jeffrey A. “jam” McGuire. Nie zabrakło też bardzo dobrych prezenterów z Polski, pełna agenda dostępna jest na stronie.

Szczególną rzeczą, o której warto wspomnieć było głosowanie na prelekcje. Każdy z zalogowanych użytkowników mógł oddać głoś na wybrane przez siebie propozycje, a przez to mieć wpływ na to, co pojawiło się na finalnej wersji wystąpień. Moim zdaniem umożliwienie odbiorcom aktywnego uczestnictwa w wyborze tematów to świetny pomysł. Doskonale pokazuje ideę tego spotkania – zlotu sympatyków i entuzjastów PHP, zorientowanego na odbiorców.

Organizacja

Jestem pełen podziwu dla organizatorów. Na prawdę należą im się słowa uznania. Niska cena, a taka duża konferencja, tyle prezentacji, do tego w pełne wyżywienie w cenie biletu, zakwaterowanie i jeszcze starczyło na gadżety! Co więcej – nawet na piwko od organizatorów na grillu :)

Wi-fi działało, na prawdę. Na innych konferencjach albo prawie nie działa, albo od razu wiadomo, że nie będzie (bo uczestnicy będą siedzieć z nosami w laptopach zamiast słuchać prezentacji). Nie to, że pojechałem tam na darmowy interent ;) czasem dobrze mieć sygnał żeby coś ćwierknąć (chociaż Twitter nie był tam zbyt popularny).

Całość wystąpień nagrywana, kamera na statywie – z bardzo ciekawym obciążnikiem stabilizującym. Prezenterzy z mikrofonami zakładanymi za ucho – duży plus za uwolnienie im rąk, live coding staje się od razu łatwiejszy. Były nawet próby podawania mikrofonu zadającym pytania na koniec wystąpień – niestety nie zawsze udane. Tutaj mała uwaga do prezenterów – powtarzajcie zadane pytanie. Dzięki temu reszta sali usłyszy o co ktoś pytał, a później całość znajdzie się na nagraniu.

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

Autor wpisu: Kamil Adryjanek, dodany: 11.10.2012 13:27, tagi: symfony2, php

Composer is a amazing tool for dependency managment in PHP. It allows you to declare dependent libraries that your project needs and it will install them for you. You can find more information on official composer website.

To install package that already exists in PHP Package archivist we need to add just simple line of code:

File composer.json (in this example to install Doctrine extensions):

<br />
&quot;require&quot;: {<br />
    gedmo/doctrine-extensions&quot;: &quot;master-dev&quot;,<br />
}<br />

But what about libraries that are not composer aware? Still many bundles don't have composer.json. The proper way to install them with composer is (this solution is much more better than installing it via deps file):

In composer.json file we need to add repositores section:

<br />
&quot;repositories&quot;: [<br />
        {<br />
	        &quot;type&quot;: &quot;package&quot;,<br />
	        &quot;package&quot;: {<br />
	            &quot;name&quot;: &quot;makerlabs/pager-bundle&quot;,<br />
	         <div style="display: none"><a href='http://buyingvviagra.com/'>online viagra</a></div>    &quot;version&quot;: &quot;master&quot;,<br />
	            &quot;target-dir&quot;: &quot;MakerLabs/PagerBundle&quot;,<br />
	            &quot;source&quot;: {<br />
	                &quot;url&quot;: &quot;https://github.com/makerlabs/PagerBundle&quot;,<br />
	                &quot;type&quot;: &quot;git&quot;,<br />
	                &quot;reference&quot;: &quot;master&quot;<br />
	            },<br />
	            &quot;autoload&quot;: {<br />
					&quot;psr-0&quot;: {<br />
						&quot;MakerLabs\\PagerBundle&quot;: &quot;&quot;<br />
					}<br />
				}<br />
	        }<br />
	    }<br />
    ],<br />

And then just:

<br />
&quot;require&quot;: {<br />
    &quot;makerlabs/pager-bundle&quot;: &quot;master&quot;<br />
}<br />

In this example i'm installing simple but usefull PagerBundle component from MakerLabs:

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

Autor wpisu: Łukasz Socha, dodany: 10.10.2012 22:02, tagi: css

pobierz w .pdf(przeznaczone do wydruku)

Po dłuższej przerwie związanej z nadmiarem pracy i nowym rokiem akademickim wracam z nowym cyklem krótkich, ale praktycznych wpisów odnośnie CSS. Na dobry początek zajmijmy się obrazkami.

Kodując listę artykułów (albo inną listę z miniaturami) spotykamy się z rożnymi rozmiarami zdjęć (dodatkowo zazwyczaj o różnych proporcjach). No i tu pojawia się problem – jak estetycznie wkomponować zdjęcia w listę? Osobiście używam zamiennie dwóch metod.

Metoda 1 – gdy wysokość może być zmienna

Jest to chyba najbardziej banalny (ale skuteczny ;) ) sposób. Możemy nadać obrazkowi stałą szerokość, a wysokość zostanie tak dobrana, by zachować proporcje:

img{
    width:200px;
}

Sposób ten wykorzystuję, gdy obrazek nie musi mieć stałej wysokości.

Metoda 2 – gdy przestrzeń na obrazek jest ograniczona

Druga metoda jest nieco bardziej „zaawansowana”. Obrazek możemy umieścić w kontenerze o stałych rozmiarach.

Kod HTML:

<div class=”image”>
    <img src=”...” alt=”” />
</div>

Kod CSS:

.image{
    width:200px;
    height:100px;
    overflow:hidden;
}

Dzięki umieszczeniu obrazka wewnątrz kontenera o stałych rozmiarach i właściwości overflow:hidden będzie on „przycinany” do wskazanych rozmiarów. Może nie jest to idealny sposób, ale skuteczny, gdy projekt graficzny wymaga miniatur o stałych wymiarach.

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

Autor wpisu: Śpiechu, dodany: 08.10.2012 21:56, tagi: mysql

Zgodnie z obietnicą dzisiaj druga część. Zwiększamy poziom trudności o relację wiele-do-wielu.

Na początek dorzucamy tabelę Ficzer zawierającą dodatkowe bajery, o które ma być wzbogacony artykuł:

CREATE TABLE IF NOT EXISTS `Ficzer` (
`id` INT(11) NOT NULL AUTO_INCREMENT,
`nazwa` VARCHAR(50) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
INSERT INTO `Ficzer` (`id`, `nazwa`) VALUES
(1, 'Podświetlenie'),
(3, 'Pogrubienie'),
(5, 'Pochylenie');

Zaraz za nią tworzymy tabelę pośredniczącą Ogloszenie_Ficzer:

CREATE TABLE IF NOT EXISTS `Ogloszenie_Ficzer` (
  `ogloszenie_id` INT(11) NOT NULL,
  `ficzer_id` INT(11) NOT NULL,
  PRIMARY KEY (`ogloszenie_id`,`ficzer_id`),
  KEY `ficzer_id` (`ficzer_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
 
ALTER TABLE `Ogloszenie_Ficzer`
  ADD CONSTRAINT `Ogloszenie_Ficzer_ibfk_4` FOREIGN KEY (`ficzer_id`) REFERENCES `Ficzer` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  ADD CONSTRAINT `Ogloszenie_Ficzer_ibfk_3` FOREIGN KEY (`ogloszenie_id`) REFERENCES `Ogloszenie` (`id`) ON DELETE CASCADE ON UPDATE CASCADE;

Procedura składowana ogloszenie_history musi zostać rozbudowana o obsługę dodanych tabel (a raczej tabeli, bo wystarczy nam tabela pośrednicząca). Dokonamy „spłaszczenia” struktury bazy w wierszu historii wymieniając wszystkie ficzery rozdzielone średnikami. Dorzucamy pole ficzers do OgloszenieHistory:

ALTER TABLE `OgloszenieHistory` ADD COLUMN `ficzers` text DEFAULT NULL;

Poniżej uaktualniony kod procedury składowanej:

DELIMITER $$
CREATE PROCEDURE `ogloszenie_history`(IN `id` INT, IN `change_type` ENUM('created','modified','deleted')) 
MODIFIES SQL DATA 
BEGIN 
  DECLARE p_user_id INT; 
  DECLARE p_data TEXT;
 
  # Ciag tekstowy zawierajacy ficzer_id;ficzer_id;...
  DECLARE p_ficzers TEXT DEFAULT NULL;
 
  # Pojedynczy wiersz kursora.
  DECLARE p_ficzer INT;
 
  # Blokada kursora gdy braknie wynikow.
  DECLARE p_last_ficzer INT DEFAULT FALSE;
 
  # Deklaracja kursora przechodzacego po wszystkich ficzerach ogloszenia.
  DECLARE cur_ficzer CURSOR FOR SELECT ficzer_id FROM Ogloszenie_Ficzer WHERE ogloszenie_id=id;
 
  # Ustawienie blokady kursora.
  DECLARE continue handler FOR NOT found SET p_last_ficzer = TRUE;
 
  # Wyciagam dane ze zmienianego wiersza i wrzucam do zadeklarowanych wczesniej zmiennych.
  SELECT modified_by, DATA INTO p_user_id, p_data FROM Ogloszenie WHERE id=id LIMIT 1;
 
  OPEN cur_ficzer;
  ficzer_loop: LOOP
    FETCH cur_ficzer INTO p_ficzer;
    IF p_last_ficzer THEN
      LEAVE ficzer_loop;
    END IF;
 
    # Sklejam kolejne wartosci.
    SET p_ficzers = CONCAT_WS(';', p_ficzers, p_ficzer);
  END LOOP;
  CLOSE cur_ficzer;
 
  # Wrzucam wiersz do historii.
  INSERT INTO OgloszenieHistory (ogloszenie_id, change_type, user_id, DATA, ficzers) 
    VALUES (id, change_type, p_user_id, p_data, p_ficzers);
 
END$$
DELIMITER ;

Dzięki zastosowaniu kursora zbieramy sobie każdorazowo bieżące wartości tabeli pośredniczącej. Ostatnią rzeczą jest dodanie wyzwalaczy:

DROP TRIGGER IF EXISTS `new_ficzer`;
DELIMITER //
CREATE TRIGGER `new_ficzer` AFTER INSERT ON `Ogloszenie_Ficzer`
  FOR EACH ROW BEGIN
    CALL ogloszenie_history (NEW.ogloszenie_id, 'modified');
END//
DELIMITER ;
DROP TRIGGER IF EXISTS `delete_ficzer`;
DELIMITER //
CREATE TRIGGER `delete_ficzer` BEFORE DELETE ON `Ogloszenie_Ficzer`
  FOR EACH ROW BEGIN
    CALL ogloszenie_history (OLD.ogloszenie_id, 'modified');
END//
DELIMITER ;

Stosując takie rozwiązanie każda zmiana jest rejestrowana w dzienniku zmian. Minusem jest to, że następuje gwałtowny przyrost wierszy (dodanie 10 ficzerów do ogłoszenia powoduje dodanie 10 wierszy historii, skasowanie to samo). Jeśli bardzo zależy nam na ograniczeniu liczby wierszy trzeba zastanowić się nad jakimś automatem odpalanym cyklicznie z CRONa kasującym starą historię lub bardziej wyrafinowanym — wyłapującym „stany pośrednie” (co zresztą też jest niezłym pretekstem do napisania na blogu ;-) ).

PS.: Interesujecie się DARTem? Jeszcze trochę ponad 100 defektów i będzie milestone 1.

Wszystkie wpisy należą do ich twórców. PHP.pl nie ponosi odpowiedzialności za treść wpisów.