Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion .gitattributes
Original file line number Diff line number Diff line change
@@ -1,2 +1,10 @@
# Auto detect text files and perform LF normalization
* text=auto

/.github export-ignore
/bin export-ignore
/tests export-ignore
/.gitignore export-ignore
/.gitattributes export-ignore
/phpunit.xml export-ignore
/phpcs.xml export-ignore
/README.md export-ignore
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,4 @@ Homestead.json
.DS_Store
composer.lock
phpunit-report.xml
phpcs-report.xml
674 changes: 0 additions & 674 deletions LICENSE

This file was deleted.

342 changes: 289 additions & 53 deletions README.md

Large diffs are not rendered by default.

3 changes: 0 additions & 3 deletions phpunit.xml
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,6 @@
<testsuite name="Unit">
<directory suffix="Test.php">./tests/Unit</directory>
</testsuite>
<testsuite name="Integration">
<directory suffix="Test.php">./tests/Integration</directory>
</testsuite>
</testsuites>
<coverage processUncoveredFiles="true">
<include>
Expand Down
50 changes: 50 additions & 0 deletions src/Contracts/Rule.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php
/**
* Rule contract.
*
* @package WpMVC\RequestValidator\Contracts
* @author WpMVC
* @license MIT
*/

namespace WpMVC\RequestValidator\Contracts;

defined( "ABSPATH" ) || exit;

/**
* Interface Rule
*
* @package WpMVC\RequestValidator\Contracts
*/
interface Rule {
/**
* Get the unique name of the rule.
*
* @return string
*/
public static function get_name(): string;

/**
* Determine if the validation rule passes.
*
* @param string $attribute
* @param mixed $value
* @return bool
*/
public function passes( string $attribute, $value ): bool;

/**
* Get the validation error message.
*
* @return string
*/
public function get_message(): string;

/**
* Replace placeholders in the given message.
*
* @param string $message
* @return string
*/
public function replace_placeholders( string $message ): string;
}
221 changes: 53 additions & 168 deletions src/DateTime.php
Original file line number Diff line number Diff line change
@@ -1,159 +1,40 @@
<?php
/**
* DateTime trait.
*
* @package WpMVC\RequestValidator
* @author WpMVC
* @license MIT
*/

namespace WpMVC\RequestValidator;

defined( "ABSPATH" ) || exit;

use DateTime as PhpDateTime;

/**
* Trait DateTime
*
* Provides date and time validation and parsing utilities.
*
* @package WpMVC\RequestValidator
*/
trait DateTime {
private $format = 'Y-m-d';

protected function date_validator( string $input_name, string $format = '' ) {
if ( ! $this->wp_rest_request->has_param( $input_name ) ) {
return;
}

$value = $this->wp_rest_request->get_param( $input_name );

if ( ! empty( $format ) ) {
$this->format = $format;
}

$format = $this->get_format();

if ( ! empty( $value ) && $this->is_it_valid_date( $value, $format ) ) {
return;
}

$this->set_error( $input_name, 'date', [':attribute'], [$input_name] );
}

public function date_equals_validator( string $input_name, $date ) {
if ( ! $this->wp_rest_request->has_param( $input_name ) ) {
return;
}

$value = $this->wp_rest_request->get_param( $input_name );

if ( ! empty( $value ) ) {
$format = $this->get_format();

if ( ! $this->is_it_valid_date( $value, $format ) ) {
return;
}

$timestamp = $this->get_timestamp( $date, $format );
$input_timestamp = $this->get_timestamp( $value, $format );

if ( $input_timestamp === $timestamp ) {
return;
}
}

$this->set_error( $input_name, 'date_equals', [':attribute', ':date'], [$input_name, $date] );
}

public function before_validator( string $input_name, $date ) {
if ( ! $this->wp_rest_request->has_param( $input_name ) ) {
return;
}

$value = $this->wp_rest_request->get_param( $input_name );

if ( ! empty( $value ) ) {
$format = $this->get_format();

if ( ! $this->is_it_valid_date( $value, $format ) ) {
return;
}

$timestamp = $this->get_timestamp( $date, $format );
$input_timestamp = $this->get_timestamp( $value, $format );

if ( $input_timestamp < $timestamp ) {
return;
}
}

$this->set_error( $input_name, 'before', [':attribute', ':date'], [$input_name, $date] );
}

public function after_validator( string $input_name, $date ) {
if ( ! $this->wp_rest_request->has_param( $input_name ) ) {
return;
}

$value = $this->wp_rest_request->get_param( $input_name );

if ( ! empty( $value ) ) {
$format = $this->get_format();

if ( ! $this->is_it_valid_date( $value, $format ) ) {
return;
}

$timestamp = $this->get_timestamp( $date, $format );
$input_timestamp = $this->get_timestamp( $value, $format );

if ( $input_timestamp > $timestamp ) {
return;
}
}

$this->set_error( $input_name, 'after', [':attribute', ':date'], [$input_name, $date] );
}

protected function before_or_equal_validator( string $input_name, $date ) {
if ( ! $this->wp_rest_request->has_param( $input_name ) ) {
return;
}

$value = $this->wp_rest_request->get_param( $input_name );

if ( ! empty( $value ) ) {
$format = $this->get_format();

if ( ! $this->is_it_valid_date( $value, $format ) ) {
return;
}

$timestamp = $this->get_timestamp( $date, $format );
$input_timestamp = $this->get_timestamp( $value, $format );

if ( $input_timestamp < $timestamp || $input_timestamp === $timestamp ) {
return;
}
}

$this->set_error( $input_name, 'before_or_equal', [':attribute', ':date'], [$input_name, $date] );
}

protected function after_or_equal_validator( string $input_name, $date ) {
if ( ! $this->wp_rest_request->has_param( $input_name ) ) {
return;
}

$value = $this->wp_rest_request->get_param( $input_name );

if ( ! empty( $value ) ) {
$format = $this->get_format();

if ( ! $this->is_it_valid_date( $value, $format ) ) {
return;
}

$timestamp = $this->get_timestamp( $date, $format );
$input_timestamp = $this->get_timestamp( $value, $format );

if ( $input_timestamp > $timestamp || $input_timestamp === $timestamp ) {
return;
}
}

$this->set_error( $input_name, 'after_or_equal', [':attribute', ':date'], [$input_name, $date] );
}

/**
* The date/time format to use.
*
* @var string
*/
protected $format = 'Y-m-d';

/**
* Determine if a date string is valid for a given format.
*
* @param string $date
* @param string $format
* @return bool
*/
private function is_it_valid_date( $date, string $format ) {
if ( ! is_string( $date ) ) {
return false;
Expand All @@ -162,29 +43,33 @@ private function is_it_valid_date( $date, string $format ) {
return $input_date && $input_date->format( $format ) === $date;
}

/**
* Get the Unix timestamp for a given date string and format.
*
* @param string $date
* @param string $format
* @return int
*/
private function get_timestamp( string $date, string $format ) {
$date_array = date_parse_from_format( $format, $date );
return mktime(
! empty( $date_array['hour'] ) ? $date_array['hour'] : 12,
! empty( $date_array['minute'] ) ? $date_array['minute'] : 0,
! empty( $date_array['second'] ) ? $date_array['second'] : 0,
$date_array['month'],
$date_array['day'],
$date_array['year']
);
}
$request = property_exists( $this, 'validator' ) && $this->validator ? $this->validator->wp_rest_request : $this->wp_rest_request;

// If the date string matches a parameter in the request, use its value
if ( $request->has_param( $date ) ) {
$date = $request->get_param( $date );
}

$dt = PhpDateTime::createFromFormat( $format, $date );

if ( ! $dt ) {
return 0;
}

private function get_format() {
foreach ( $this->explode_rules as $key => $value ) {
$substrings = explode( ':', $value, 2 );
if ( $substrings[0] !== 'date' ) {
continue;
}
if ( isset( $substrings[1] ) ) {
return $substrings[1];
}
return $this->format;
// If the format doesn't include time components, createFromFormat might set them to current time or '?'
// We should ensure a consistent start-of-day for formats without time.
if ( strpos( $format, 'H' ) === false && strpos( $format, 'h' ) === false ) {
$dt->setTime( 0, 0, 0 );
}
return $this->format;

return $dt->getTimestamp();
}
}
Loading
Loading