porno porno izle rokettube
Ergebnis 1 bis 4 von 4

Thema: Wie ist eine MultiCheckbox mit aus Objekten kommenden Werten zu handhaben?

  1. #1
    Erfahrener Benutzer
    Registriert seit
    22.11.2009
    Beiträge
    171
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Standard Wie ist eine MultiCheckbox mit aus Objekten kommenden Werten zu handhaben?

    Hallo zusammen!

    Die Frage ist etwas verwirrend formuliert, ich versuche zu erklären, was ich meine:

    Ich habe ein verschachteltes Formular mit mehreren Sub-Fieldsets. Dieses Formular ist parallel zu einem verschachtelten Objekt aufgebaut, also in etwa wie:

    Code:
    [TypeFoo: 'use_as_base_fieldset' => true]
    property $a int
    property $b TypeB
        property $c string
        property $d TypeD
            property $e string
            property $f string
        property $g TypeG
            property $h string
            property $i array (mit Elementen TypeI)
    ...
    
    [MyForm] > [FieldsetFoo]
    element 'a' Text
    fieldset FieldsetB
        element 'c' string
        fieldset FieldsetD
            element 'e' string
            element 'f' string
        fieldset FieldsetG
            element 'h' string
            collection CollectionI
    ...
    Mit $myForm->bind($myTypeFoo) binde ich das Objekt ans Formular und der Input wird automatisch ins Objekt hydriert. Dank bind(...) erhalte ich aus dem Formular ein fertiges TypeFoo-Objekt. Ebenso funktioniert es in der entgegengesetzten Richtung: Zum Editieren eines einmal persistierten Objekts hole ich es aus der Datenbank, übergebe dem Formular und erhalte ein fertiges Formular mit vorausgefüllten Feldern.

    Alles funktionierte bestens, bis ein MultiCheckbox Element ins Spiel kam. Die Objekt-Property dahinter ist ein Array mit Elementen vom Typ Protocol (jedes Protocol hat Eigenschaften id und name, die für die MultiCheckBox entsprechend als value und label dienen sollen). Beim Speichern muss ich tricksen: Ich bekomme nämlich nicht mehr das fertige Objekt aus dem Formular. Die Property protocols ist nämlich nicht, wie eigenlicht designt, ein Array von Protocol-Objekten, sondern ein Array von value=>label Arrays, aus dem ich dann in einem Zwischenschritt "manuell" ein Array von Protocol-Objekten erstelle, um das TypeFoo-Objekt zu komplettieren und an das Model zum Persistieren zu übergeben. (Hässlicher Workaround, aber funktioniert.) Das eigentliche Problem tritt aber beim Edit-Formular auf. Der FormMultiCheckBox View Helper erwartet fir die MultipleCheckbox einfache Werte und versucht die Protocol-Objekte im Array von Element#options['value_options'] zu finden, was natürlich nicht klappt und nur zu einer Notice führt:

    Notice: Object of class My\DataObject\Protocol could not be converted to int in /var/www/path/to/project/vendor/zendframework/zend-form/src/View/Helper/FormMultiCheckbox.php on line 202
    Da stößt mein oben beschriebener hässlicher Workaround wohl an seine Grenzen und muss verworfen werden.

    Wie kann man das sauber lösen und ein Array von Objekten für ein MultiCheckBox Element nutzen?

    Danke schon mal!
    Geändert von Kaiuwe (10.06.2016 um 06:18 Uhr)


  2. #2
    Super-Moderator Avatar von Kaiuwe
    Registriert seit
    30.12.2006
    Beiträge
    5.513
    Thanks
    3
    Thanked 352 Times in 283 Posts

    Standard

    Zitat Zitat von automatix Beitrag anzeigen
    Hässlicher Workaround, aber funktioniert.
    Scheinbar funktioniert dieser nicht, denn ansonsten hättest du keine Probleme.

    Grundsätzlich ist der Vorgang beim Formularen wie folgt:

    1. Objekt wird an Formular gebunden
    2. Hydrator extrahiert die Daten aus dem Objekt
    3. Werte können für die einzelnen Formularfelder gesetzt werden


    Dein Problem liegt also beim 2. Punkt. Wie sieht denn dein Hydrator dazu aus?
    Zum Zend Framework stehen jedem folgende Quellen zum Nachschlagen zur Verfügung:

  3. #3
    Erfahrener Benutzer
    Registriert seit
    22.11.2009
    Beiträge
    171
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Standard

    Messerscharf analysiert! :)

    Ja, das Problem liegt im Hydrator. Aber die Lösung gefällt mir nicht. Die läge nämlich darin, einen speziellen Hydrator für das (bzw. jedes) MultiCheckbox-Feld zu schreiben. Und bei dem Hydrator müsste die extract(...) -- anders als bei gewöhnlichen HydratorInterface-Implementierungen -- anstatt eines Arrays mit den Objekt-Daten, einen Integer-Wert (in dem Fall die $id) liefern. Das designtechnisch aus zwei Gründen bedenklich:

    1. Wenn man ohnehin schon einen Hydrator für Protocol hat, muss man einen zweiten speziell für den MultiCheckbox-Fall schreiben.

    2. Wie schon oben angesprochen, verhält sich dann die ProtocolHydrator#extract(...) nicht wie normalerweise erwartet und bricht das HydratorInterface. Zwar nicht formell, weil der Ausgabe-Typ nicht zur Signatur der Methode gehört, aber jedenfalls logisch.

    Hier eine mögliche Implementierung:

    FooHydratorFactory

    PHP-Code:
    namespace My\Hydrator\Factory;
    use 
    Zend\ServiceManager\FactoryInterface;
    use 
    Zend\ServiceManager\ServiceLocatorInterface;
    use 
    My\DataObject\Protocol;
    use 
    My\Hydrator\Strategy\Entity\GenericCollectionStrategy;
    class 
    FooHydratorFactory implements FactoryInterface
    {
        public function 
    createService(ServiceLocatorInterface $serviceLocator)
        {
            
    $fooHydrator $serviceLocator->get('Zend\Hydrator\ClassMethods');
            
    $protocolHydrator $serviceLocator->get('My\Hydrator\ProtocolHydrator');
            
    $fooHydrator->addStrategy('protocols', new GenericCollectionStrategy($protocolHydrator, new Protocol()));
            
    // no naming map
            
    return $fooHydrator;
        }

    ProtocolHydratorFactory

    PHP-Code:
    namespace My\Hydrator\Factory;
    use 
    Zend\ServiceManager\FactoryInterface;
    use 
    Zend\ServiceManager\ServiceLocatorInterface;
    use 
    My\Hydrator\ProtocolHydrator;
    class 
    ProtocolHydratorFactory implements FactoryInterface
    {
        public function 
    createService(ServiceLocatorInterface $serviceLocator)
        {
            return new 
    ProtocolHydrator();
        }

    ProtocolHydrator

    PHP-Code:
    namespace My\Hydrator;
    use 
    Zend\Hydrator\ClassMethods;
    use 
    My\DataObject\Protocol;
    class 
    ProtocolHydrator extends ClassMethods
    {
        public function 
    extract($object)
        {
            return 
    $object->getId();
        }
        public function 
    hydrate(array $data$object)
        {
            
    // An array with one int value for the ID is expected, e.g.:
            // [123]
            
    $dataValues array_values($data);
            
    $id array_shift($dataValues);
            return 
    parent::hydrate(['id' => $id], $object);
        }

    GenericCollectionStrategy

    PHP-Code:
    use Zend\Hydrator\Strategy\StrategyInterface;
    use 
    Zend\Hydrator\HydratorInterface;
    class 
    GenericCollectionStrategy implements StrategyInterface
    {
        private 
    $hydrator;
        private 
    $prototype;
        
    // constructor
        
    public function getPrototype()
        {
            return 
    $this->prototype ? clone $this->prototype null;
        }
        
    // getters, setters...
        
    public function extract($objects)
        {
            
    $collection = [];
            if (
    is_array($objects) || $objects instanceof \Traversable) {
                foreach (
    $objects as $object) {
                    
    $prototypeClass get_class($this->prototype);
                    
    $collection[] = is_object($object) && $object  instanceof $prototypeClass $this->hydrator->extract($object) :  $object;
                }
            }
            return 
    $collection;
        }
        public function 
    hydrate($array)
        {
            
    $collection = [];
            if (
    is_array($array)) {
                foreach (
    $array as $element) {
                    
    // the original clean variant
                    // $collection[] = is_array($element) ? $this->hydrator->hydrate($element, $this->getPrototype()) : $element;
                    // the variant for non-array elements
                    
    $element is_array($element) ? $element : [$element];
                    
    $collection[] = $this->hydrator->hydrate($element$this->getPrototype());
                }
            }
            return 
    $collection;
        }

    Das funktioniert, aber schön bzw. sauber ist anders.

    UPDATE

    Ich sagte, die Lösung ist nicht schön. Und wie es bei unschönen Lösungen meistens ist, verletzen sie nicht nur das feine Ästhetik-Gefühl des Entwicklers, sondern führen früh oder spät zu Problemen. Also, diese Lösung hat die Einschränkung, dass das Hydrating (i.S.d. HydratorInterface#hydrate(...)) nicht funktioniert. Damit es geht, musste die GenericCollectionStrategy#hydrate(...) angepasst und die ProtocolHydrator#hydrate(...) auf eine fast bizarre Weise implementiert werden.

    Ich sehe das alles weniger als eine Lösung, sondern eher als einen Workaround.

    Wie kann das Problem eleganter -- also unter Vermeideung dieses ganzen Gefrickels -- gelöst werden?
    Geändert von automatix (11.06.2016 um 17:49 Uhr)


  4. #4
    Neuer Benutzer
    Registriert seit
    02.08.2017
    Beiträge
    1
    Thanks
    0
    Thanked 0 Times in 0 Posts

    Standard

    Sorry for the English, but I thought it would be helpful if I mentioned the doctrine-module for ZF has a 'ObjectMultiCheckbox' meant to solve this problem.
    As a new user, I'm not able to post the link.

Ähnliche Themen

  1. Exception-Codes wie handhaben?
    Von akkie im Forum PHP X-Talk
    Antworten: 8
    Letzter Beitrag: 07.03.2011, 04:47
  2. DropDown mit Werten aus DB füllen
    Von Beginner im Forum Formulare
    Antworten: 28
    Letzter Beitrag: 17.05.2010, 19:50
  3. Antworten: 7
    Letzter Beitrag: 10.06.2009, 12:08
  4. ZEND_Form, Combobox mit Werten aus DB füllen
    Von Ragnaroek im Forum Formulare
    Antworten: 2
    Letzter Beitrag: 29.09.2008, 15:11
  5. Zend_Form addMultiOptions mit Werten aus DB füllen
    Von Salvatore im Forum Formulare
    Antworten: 5
    Letzter Beitrag: 19.08.2008, 12:20

Stichworte

Lesezeichen

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •