<?php namespace WPDesk\Forms\Form; use Psr\Container\ContainerInterface; use WPDesk\Forms\ContainerForm; use WPDesk\Forms\Field; use WPDesk\Forms\FieldProvider; use WPDesk\Forms\Form; use WPDesk\Persistence\ElementNotExistsException; use WPDesk\Persistence\PersistentContainer; use WPDesk\View\Renderer\Renderer; class FormWithFields implements Form, ContainerForm, FieldProvider { use Field\Traits\HtmlAttributes; /** @var string Unique form_id. */ protected $form_id = 'form'; /** @var array Updated data. */ private $updated_data; /** @var Field[] Form fields. */ private $fields; /** * FormWithFields constructor. * * @param Field[] $fields * @param string $form_id */ public function __construct( array $fields, string $form_id = 'form' ) { $this->fields = $fields; $this->form_id = $form_id; $this->set_action( '' ); $this->set_method( 'POST' ); } /** Set Form action attribute. */ public function set_action( string $action ): self { $this->attributes['action'] = $action; return $this; } public function get_action(): string { return $this->attributes['action']; } /** Set Form method attribute ie. GET/POST. */ public function set_method( string $method ): self { $this->attributes['method'] = $method; return $this; } public function get_method(): string { return $this->attributes['method']; } public function is_submitted(): bool { return null !== $this->updated_data; } /** @return void */ public function add_field( Field $field ) { $this->fields[] = $field; } public function is_active(): bool { return true; } /** * Add more fields to form. * * @param Field[] $fields Field to add to form. * * @return void */ public function add_fields( array $fields ) { array_map( [ $this, 'add_field' ], $fields ); } public function is_valid(): bool { foreach ( $this->fields as $field ) { $field_value = $this->updated_data[ $field->get_name() ] ?? $field->get_default_value(); $field_validator = $field->get_validator(); if ( ! $field_validator->is_valid( $field_value ) ) { return false; } } return true; } /** * Add array to update data. */ public function handle_request( array $request = [] ) { if ( $this->updated_data === null ) { $this->updated_data = []; } foreach ( $this->fields as $field ) { $data_key = $field->get_name(); if ( isset( $request[ $data_key ] ) ) { $this->updated_data[ $data_key ] = $field->get_sanitizer()->sanitize( $request[ $data_key ] ); } } } /** * Data could be saved in some place. Use this method to transmit them to form. * * @return void */ public function set_data( ContainerInterface $data ) { foreach ( $this->fields as $field ) { $data_key = $field->get_name(); if ( $data->has( $data_key ) ) { try { $this->updated_data[ $data_key ] = $data->get( $data_key ); } catch ( ElementNotExistsException $e ) { $this->updated_data[ $data_key ] = false; } } } } /** Renders only fields without form. */ public function render_fields( Renderer $renderer ): string { $content = ''; $fields_data = $this->get_data(); foreach ( $this->get_fields() as $field ) { $content .= $renderer->render( $field->should_override_form_template() ? $field->get_template_name() : 'form-field', [ 'field' => $field, 'renderer' => $renderer, 'name_prefix' => $this->get_form_id(), 'value' => $fields_data[ $field->get_name() ] ?? $field->get_default_value(), 'template_name' => $field->get_template_name(), ] ); } return $content; } public function render_form( Renderer $renderer ): string { $content = $renderer->render( 'form-start', [ 'form' => $this, 'method' => $this->get_method(), // backward compat. 'action' => $this->get_action(), // backward compat. ] ); $content .= $this->render_fields( $renderer ); $content .= $renderer->render( 'form-end' ); return $content; } public function put_data( PersistentContainer $container ) { foreach ( $this->get_fields() as $field ) { $data_key = $field->get_name(); if ( empty( $data_key ) ) { continue; } if ( ! isset( $this->updated_data[ $data_key ] ) ) { $container->set( $data_key, $field->get_default_value() ); } else { $container->set( $data_key, $this->updated_data[ $data_key ] ); } } } public function get_data(): array { $data = $this->updated_data; foreach ( $this->get_fields() as $field ) { $data_key = $field->get_name(); if ( ! isset( $data[ $data_key ] ) ) { $data[ $data_key ] = $field->get_default_value(); } } return $data; } public function get_fields(): array { $fields = $this->fields; usort( $fields, static function ( Field $a, Field $b ) { return $a->get_priority() <=> $b->get_priority(); } ); return $fields; } public function get_form_id(): string { return $this->form_id; } public function get_normalized_data(): array { return $this->get_data(); } }