diff --git a/README.md b/README.md index 519d15f6126e43583a27d05b0e777b8feaf9fbf6..c129e94afbe18c2c8ba172848d73a8b89bec7bf3 100644 --- a/README.md +++ b/README.md @@ -50,11 +50,11 @@ interface SettingsTab { /** * Use to set settings from database or defaults. * - * @param array|ContainerInterface $data Data to render. + * @param ContainerInterface $data Data to render. * * @return void */ - public function set_data( $data ); + public function set_data( ContainerInterface $data ); /** * Use to handle request data from POST. @@ -102,11 +102,11 @@ abstract class FieldSettingsTab implements SettingsTab { return $this->get_form()->render_form( $renderer ); } - public function set_data( $data ) { + public function set_data( ContainerInterface $data ) { $this->get_form()->set_data( $data ); } - public function handle_request( $request ) { + public function handle_request( array $request ) { $this->get_form()->handle_request( $request ); } diff --git a/changelog.txt b/changelog.txt index 10aef4ca0341dbc0807abb45731357d7bb41b917..0fba0c89e9be44c361a333de16592a94a70b686c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,11 +1,21 @@ # Changelog -## [3.0.0] - 2021-09-08 +## [3.0.0] ### Added - Added strong typing to all of the interfaces - Added fields sorting by priority field -### +- Normalized string escaping in all template files +- Added InputEmailField and EmailSerializer classes +### Changed +- All getters and setter in BasicField are now declared final +- FormWithFields accepts only ContainerInterface in ::set_data() method. Prepare data before passing it +### Removed - Removed deprecated classes +- Removed NoSerialize class + +## [2.4.7] - 2021-09-20 +### Fixed +- Add missing escaping functions in templates ## [2.4.6] - 2021-08-23 ### Fixed diff --git a/src/Field.php b/src/Field.php index 311d8eb2474614314d16e3d948fad8e74e86b427..08329e7f0a4166ed8d3551075b60117770dae779 100644 --- a/src/Field.php +++ b/src/Field.php @@ -91,5 +91,7 @@ interface Field { public function get_serializer(): Serializer; + public function has_serializer(): bool; + public function get_priority(): int; } diff --git a/src/Field/BasicField.php b/src/Field/BasicField.php index 2855357bf077cc810390d3246ed5fb02bf37220d..4c1dc0cf40c58b7eb0291921b66f1260f5c2b9f7 100644 --- a/src/Field/BasicField.php +++ b/src/Field/BasicField.php @@ -6,7 +6,6 @@ use WPDesk\Forms\Field; use WPDesk\Forms\Sanitizer; use WPDesk\Forms\Sanitizer\NoSanitize; use WPDesk\Forms\Serializer; -use WPDesk\Forms\Serializer\NoSerialize; use WPDesk\Forms\Validator; use WPDesk\Forms\Validator\ChainValidator; use WPDesk\Forms\Validator\RequiredValidator; @@ -22,7 +21,7 @@ abstract class BasicField implements Field { const DEFAULT_PRIORITY = 10; - /** @var array{default_value: string, possible_values?: string[], sublabel?: string, priority: int, label: string, description: string, description_tip: string, data: array<string|int>, serializer: ?Serializer} */ + /** @var array{default_value: string, possible_values?: string[], sublabel?: string, priority: int, label: string, description: string, description_tip: string, data: array<string|int>} */ protected $meta = [ 'priority' => self::DEFAULT_PRIORITY, 'default_value' => '', @@ -30,9 +29,41 @@ abstract class BasicField implements Field { 'description' => '', 'description_tip' => '', 'data' => [], - 'serializer' => null, ]; + public function should_override_form_template(): bool { + return false; + } + + public function get_type(): string { + return 'text'; + } + + public function get_validator(): Validator { + $chain = new ChainValidator(); + if ( $this->is_required() ) { + $chain->attach( new RequiredValidator() ); + } + + return $chain; + } + + public function get_sanitizer(): Sanitizer { + return new NoSanitize(); + } + + public function has_serializer(): bool { + return false; + } + + public function get_serializer(): Serializer { + throw new \BadMethodCallException('You must define your serializer in a child class.'); + } + + final public function get_name(): string { + return $this->attributes['name']; + } + final public function get_label(): string { return $this->meta['label']; } @@ -51,11 +82,6 @@ abstract class BasicField implements Field { return ! empty( $this->meta['description_tip'] ); } - /** Override method if you need. */ - public function should_override_form_template(): bool { - return false; - } - final public function get_description(): string { return $this->meta['description']; } @@ -80,10 +106,6 @@ abstract class BasicField implements Field { return $this; } - public function get_type(): string { - return 'text'; - } - final public function set_placeholder( string $value ): Field { $this->attributes['placeholder'] = $value; @@ -132,9 +154,6 @@ abstract class BasicField implements Field { return $this->attributes['id'] ?? sanitize_title( $this->get_name() ); } - public function get_name(): string { - return $this->attributes['name']; - } final public function is_multiple(): bool { return $this->attributes['multiple']; @@ -211,37 +230,10 @@ abstract class BasicField implements Field { return $this; } - public function get_validator(): Validator { - $chain = new ChainValidator(); - if ( $this->is_required() ) { - $chain->attach( new RequiredValidator() ); - } - - return $chain; - } - final public function is_required(): bool { return $this->attributes['required']; } - public function get_sanitizer(): Sanitizer { - return new NoSanitize(); - } - - final public function get_serializer(): Serializer { - if ( ! empty( $this->meta['serializer'] ) && $this->meta['serializer'] instanceof Serializer ) { - return $this->meta['serializer']; - } - - return new NoSerialize(); - } - - public function set_serializer( Serializer $serializer ): Field { - $this->meta['serializer'] = $serializer; - - return $this; - } - final public function get_priority(): int { return $this->meta['priority']; } diff --git a/src/Field/NoValueField.php b/src/Field/NoValueField.php index 90bbecb1d4c622e128c3b95c8d7a934ea2e6598d..53091700da201919178d7b2317dc7e222df105e2 100644 --- a/src/Field/NoValueField.php +++ b/src/Field/NoValueField.php @@ -8,7 +8,7 @@ namespace WPDesk\Forms\Field; * @package WPDesk\Forms */ abstract class NoValueField extends BasicField { - public function get_name(): string { - return ''; + public function __construct() { + $this->set_name( '' ); } } diff --git a/src/Field/ProductSelect.php b/src/Field/ProductSelect.php index 2a10e467a6392525b113efa0bd42202be852755b..8d8b5e63620d46d216ce67cede2f1477f02809b4 100644 --- a/src/Field/ProductSelect.php +++ b/src/Field/ProductSelect.php @@ -2,11 +2,22 @@ namespace WPDesk\Forms\Field; +use WPDesk\Forms\Serializer\ProductSelectSerializer; +use WPDesk\Forms\Serializer; + class ProductSelect extends SelectField { public function __construct() { $this->set_multiple(); } + public function has_serializer(): bool { + return true; + } + + public function get_serializer(): Serializer { + return new ProductSelectSerializer(); + } + public function get_template_name(): string { return 'product-select'; } diff --git a/src/Field/TimepickerField.php b/src/Field/TimepickerField.php index 84682545bd7be8f4dfcb00cb3c78f5eed86762e0..c7c1a5d12ad2c222720f2ce62392151c71fe5590 100644 --- a/src/Field/TimepickerField.php +++ b/src/Field/TimepickerField.php @@ -2,7 +2,18 @@ namespace WPDesk\Forms\Field; +use WPDesk\Forms\Serializer; +use WPDesk\Forms\Serializer\JsonSerializer; + class TimepickerField extends BasicField { + public function has_serializer(): bool { + return true; + } + + public function get_serializer(): Serializer { + return new JsonSerializer(); + } + public function get_template_name(): string { return 'timepicker'; } diff --git a/src/Form/FormWithFields.php b/src/Form/FormWithFields.php index ac0f159bda5a0c721ecb9ecd8995b902ed91b73a..de48e33d76b70c89a5f5aba5980b81e5f40260fc 100644 --- a/src/Form/FormWithFields.php +++ b/src/Form/FormWithFields.php @@ -94,8 +94,6 @@ class FormWithFields implements Form, ContainerForm, FieldProvider { /** * Add array to update data. - * - * @param array|ContainerInterface $request new data to update. */ public function handle_request( array $request = [] ) { if ( $this->updated_data === null ) { diff --git a/src/Persistence/FieldPersistenceStrategy.php b/src/Persistence/FieldPersistenceStrategy.php index 02f2d4ffd3a051c7abd34ca5c01d179afa7ad907..3102f1ce6f69d8f9dc6f790a9a885e92076d3e39 100644 --- a/src/Persistence/FieldPersistenceStrategy.php +++ b/src/Persistence/FieldPersistenceStrategy.php @@ -20,25 +20,29 @@ class FieldPersistenceStrategy { $this->persistence = $persistence; } - /** - * Save fields data. - */ + /** @return void */ public function persist_fields( FieldProvider $fields_provider, array $data ) { foreach ( $fields_provider->get_fields() as $field ) { $field_key = $field->get_name(); - $this->persistence->set( $field_key, $field->get_serializer()->serialize( $data[ $field_key ] ) ); + if ( $field->has_serializer() ) { + $this->persistence->set( $field_key, $field->get_serializer()->serialize( $data[ $field_key ] ) ); + } else { + $this->persistence->set( $field_key, $data[ $field_key ] ); + } } } - /** - * Load fields data. - */ + /** @return void */ public function load_fields( FieldProvider $fields_provider ): array { $data = []; foreach ( $fields_provider->get_fields() as $field ) { $field_key = $field->get_name(); try { - $data[ $field_key ] = $field->get_serializer()->unserialize( $this->persistence->get( $field_key ) ); + if ( $field->has_serializer() ) { + $data[ $field_key ] = $field->get_serializer()->unserialize( $this->persistence->get( $field_key ) ); + } else { + $data[ $field_key ] = $this->persistence->get( $field_key ); + } } catch ( NotFoundExceptionInterface $not_found ) { // TODO: Logger // LoggerFactory::get_logger()->info( "FieldPersistenceStrategy:: Field {$field_key} not found" ); diff --git a/src/Serializer/NoSerialize.php b/src/Serializer/NoSerialize.php deleted file mode 100644 index 371e8e75db3dd44eda7e9a0db99f9355e709729c..0000000000000000000000000000000000000000 --- a/src/Serializer/NoSerialize.php +++ /dev/null @@ -1,16 +0,0 @@ -<?php - -namespace WPDesk\Forms\Serializer; - -use WPDesk\Forms\Serializer; - -class NoSerialize implements Serializer { - public function serialize( $value ): string { - return (string) $value; - } - - public function unserialize( string $value ) { - return $value; - } - -} diff --git a/templates/header.php b/templates/header.php index e2384eae321d4ce9a89df6d87fa65527b2f61611..ec06536ea742126c9ee419c5a8a96fb8b03906fc 100644 --- a/templates/header.php +++ b/templates/header.php @@ -7,7 +7,6 @@ $header_size = (int) $field->get_meta_value( 'header_size' ) ?: 2; $classes = $field->has_classes() ? 'class="' . esc_attr( $field->get_classes() ) . '"' : ''; - ?> <?php if ( $field->has_label() ) : ?> diff --git a/templates/input-image.php b/templates/input-image.php index 9b5d63522fe8182d7bb4c1a40e62c91510f5cadd..5111c4c2c5af3cc159eb7e44597f4b46a5a5bf22 100644 --- a/templates/input-image.php +++ b/templates/input-image.php @@ -13,25 +13,17 @@ $media_container_id = 'media_' . sanitize_key( $field->get_id() ); id="<?php echo \esc_attr( $field->get_id() ); ?>"/> <div class="custom-img-container"> <?php if ( $value ) : ?> - <img src="<?php echo \esc_attr( $value ); ?>" alt="" width="100"/> + <img src="<?php echo \esc_url( $value ) ?>" alt="" width="100"/> <?php endif; ?> - </div> - <p class="hide-if-no-js"> - <a class="upload-custom-img - <?php - if ( $value ) : - ?> - hidden<?php endif ?>" href="<?php echo \esc_attr( $value ); ?>"> - <?php esc_html_e( 'Set image', 'wp-forms' ); ?> - </a> - <a class="delete-custom-img - <?php - if ( ! $value ) : - ?> - hidden<?php endif ?>" href="#"> - <?php esc_html_e( 'Remove image', 'wp-forms' ); ?> - </a> - </p> + </div> + <p class="hide-if-no-js"> + <a class="upload-custom-img <?php if ( $value ): ?>hidden<?php endif ?>" href="<?php echo \esc_url( $value ) ?>"> + <?php \esc_html_e( 'Set image', 'wp-forms' ) ?> + </a> + <a class="delete-custom-img <?php if ( ! $value ): ?>hidden<?php endif ?>" href="#"> + <?php \esc_html_e( 'Remove image', 'wp-forms' ) ?> + </a> + </p> </div> <script> jQuery( function ( $ ) {