0

Ich habe eine komplexe verschachtelte (Reihenfolge) Zend\Form, die mehrfach bearbeitet werden kann. Der Benutzer erstellt zunächst eine Bestellung, muss diese jedoch nicht sofort platzieren. Er kann einfach die Bestellung speichern (oder genauer: ihre Daten) und sie später bearbeiten. In diesem Fall lädt die Anwendung ein Order-Objekt (mit all seiner verschachtelten Struktur) und bind s es in das Formular. Die wichtigsten Schritte sind:Wie bekomme ichData() von einem Zend Form vor der Validierung in Zend Framework 2/3?

  1. ID der Reihenfolge von der Anfrage von ID
  2. $orderForm->bind($orderObject) ...

Jetzt

  • erhalten das Order Objekt bekommen ich die Daten fangen will und Serialisieren Sie es zu JSON. (Der Hintergrund: Klonen von Formularen - im nächsten Schritt sollte ein leeres neues Formular erstellt werden und es sollte übergeben werden; nach dem Speichern erhalten wir einen Klon.) Es sollte zwischen 2 und 3 passieren. Also ich versuche

    $formData = $this->orderForm->getData(); 
    $formJson = json_encode($formData, JSON_UNESCAPED_SLASHES); 
    

    und erhalte die Fehlermeldung:

    Zend\Form\Form::getData cannot return data as validation has not yet occurred

    Nun, ich könnte versuchen, um ihn herum und validate Form zu arbeiten:

    $formIsValid = $this->orderForm->isValid(); 
    

    aber es führt nur zu weitere Probleme:

    Zend\InputFilter\BaseInputFilter::setData expects an array or Traversable argument; received NULL

    Gibt es eine Möglichkeit, die Formulardaten vor der Validierung zu erhalten?

  • +0

    Die letzte Fehlermeldung besagt, dass die Daten, die Sie mit der setData-Methode festlegen möchten, null sind. Sie müssen Ihr Formular mit Daten füllen, bevor Sie es validieren. Lass uns deinen Weg umgestalten. Erstens: Holen Sie sich die ID der Bestellung. Zweitens: Holen Sie das Auftragsobjekt durch die ID. Drittens: Extrahieren Sie die Daten Ihres Auftragsobjekts mit einem Hydrator. Viertens: Geben Sie die extrahierten Daten (Array) über die Methode setData Ihres Formulars an das Formular weiter. Fünftens: bestätige es. Sechstens: Holen Sie sich die gefilterten, validierten Daten Ihres Formulars über die getData-Methode. Sie können das Bestellobjekt nicht direkt an Ihr Formular binden. – Marcel

    Antwort

    0

    Okay, der Kommentarraum ist viel zu klein, um alles über das zu sagen, was Sie archivieren wollen. Lassen Sie uns jeden einzelnen Schritt, den Sie im Startpost erwähnt haben, umgestalten. Dies wird uns zu Ihrem Ziel führen. Es geht um Hydration.

    Dies ist ein kleines Beispiel, wie eine Bestelleinheit mit Produkten darin aussehen könnte. Nach der Auftragsentität folgt die Produkteinheit, die wir für dieses Beispiel benötigen.

    namespace Application\Entity; 
    
    class Order implements \JsonSerializable 
    { 
        /** 
        * ID of the order 
        * @var integer 
        */ 
        protected $orderID; 
    
        /** 
        * Array of \Application\Entity\Product   
        * @var array 
        */ 
        protected $products; 
    
        public function getOrderID() : integer 
        { 
         return $this->orderID; 
        } 
    
        public function setOrderID(integer $orderID) : Order 
        { 
         $this->orderID = $orderID; 
         return $this; 
        } 
    
        public function getProducts() 
        { 
         if ($this->products == null) { 
          $this->products = []; 
         } 
    
         return $this->products; 
        } 
    
        public function setProducts(array $products) : Order 
        { 
         $this->products = $products; 
         return $this; 
        } 
    
        /** 
        * @see \JsonSerializable::jsonSerialize() 
        */ 
        public function jsonSerialize() 
        { 
         return get_object_vars($this); 
        } 
    } 
    

    Die folgende Einheit stellt ein Produkt dar.

    class Product implements \JsonSerializable 
    { 
        protected $productID; 
    
        protected $name; 
    
        public function getProductID() : integer 
        { 
         return $this->productID; 
        } 
    
        public function setProductID(integer $productID) : Product 
        { 
         $this->productID = $productID; 
         return $this; 
        } 
    
        public function getName() : string 
        { 
         return $this->name; 
        } 
    
        public function setName(string $name) : Product 
        { 
         $this->name = $name; 
         return $this; 
        } 
    
        /** 
        * @see \JsonSerializable::jsonSerialize() 
        */ 
        public function jsonSerialize() 
        { 
         return get_object_vars($this); 
        } 
    } 
    

    Oben sehen Sie unsere Entität, die eine einzelne Bestellung mit mehreren möglichen Produkten darstellt. Das zweite Element Produkte kann ein Array mit Product entities sein. Diese Entität repräsentiert die Datenstruktur unserer einfachen Reihenfolge.

    An dieser Stelle benötigen wir ein Formular, das diese Objekte als Objekte für die darin enthaltenen Daten verwendet. Eine mögliche Fabrik für unser Formular könnte so aussehen.

    namespace Application\Form\Factory; 
    
    class OrderFormFactory implements FactoryInterface 
    { 
        public function createService(ServiceLocatorInterface $serviceLocator) 
        { 
         $parentLocator = $serviceLocator->getServiceLocator(); 
         $inputFilter = $parentLocator->get('InputFilterManager')->get(OrderInputFiler::class); 
         $hydrator = new ClassMethods(false); 
         $entity = new OrderEntity(); 
    
         return (new OrderForm()) 
          ->setInputFilter($inputFilter) 
          ->setHydrator($hydrator) 
          ->setObject($entity); 
        } 
    } 
    

    Dies ist die Fabrik für unser Formular. Wir setzen einen Hydrator, einen Eingabefilter und eine Entität für das Formular. Du musst also nichts binden. Der folgende Code zeigt, wie Daten mit diesem Formular behandelt werden.

    // retrieve an order from database by id 
    // This returns a order entity as result 
    $order = $this->getServiceLocator()->get(OrderTableGateway::class)->fetchById($id); 
    
    // Extract the order data from object to array assumed the 
    // retrieved data from data base is an OrderEntity object 
    // the hydrator will use the get* methods of the entity and returns an array 
    $data = (new ClassMethods(false))->extract($order); 
    
    // fill the form with the extracted data 
    $form = $this->getServiceLocator()->get('FormElementManager')->get(OrderForm::class); 
    $form->setData($data); 
    
    if ($form->isValid()) { 
    
        // returns a validated order entity 
        $order = $form->getData(); 
    } 
    

    Es ist absolut nicht möglich, Daten von einem Formular zu erhalten, das noch nicht validiert ist. Sie müssen die Formulardaten validieren und danach können Sie die gefilterten/validierten Daten aus dem Formular abrufen. Hydratoren und Einheiten werden Ihnen sehr helfen, wenn Sie mit vielen Daten umgehen müssen.