Skip to content

Instantly share code, notes, and snippets.

@beaucollins
Last active January 25, 2019 21:31
Show Gist options
  • Select an option

  • Save beaucollins/802f6267fd4fc129fe2a86f109c2ce0e to your computer and use it in GitHub Desktop.

Select an option

Save beaucollins/802f6267fd4fc129fe2a86f109c2ce0e to your computer and use it in GitHub Desktop.
<?php
// snip
function get_validator( $event_type ) {
$class_name_default = 'Happytools\\Scheduler\\' . strtok( $event_type, ':' ) . '_Event_Validator';
$class_name_or_validator = apply_filters( 'happytools_event_validator', null, $event_type );
if ( $class_name_or_validator === null ) {
$class_name_or_validator = $class_name_default;
}
/**
* If the returned class_name_or_validator is an already
* instantiated instance of Event_Validator return it as
* is.
*/
if ( $class_name_or_validator instanceof Event_Validator ) {
return $class_name_or_validator;
}
return class_exists( $class_name_or_validator ) ? new $class_name_or_validator() : false;
}
<?php
namespace Happytools\Events;
use Happytools\Scheduler\Event_Validator;
use Exception;
/**
* Creates a validator that can be used with the EventStore that uses a composed
* set of validations in a single callable
*/
class Validation_Engine extends Event_Validator {
/**
* Creates a Validation_Engine instance for the given namespace and validator function.
*/
public static function namespace( string $event_namespace, callable $validations ): Event_Validator {
return new self( $event_namespace, $validations );
}
private $event_namespace;
private $validations;
function __construct( string $event_namespace, callable $validations ) {
$this->event_namespace = $event_namespace;
$this->validations = $validations;
}
/**
* Callback to be used with `happytools_event_validator` hook. Returns itself as
* the validator to use when the event_type matches the event_namespace _and_ there
* is no existing validator registered.
*/
public function detect_event( $class_name, $event_type ) {
// Someone already said they're validating this event
// we aren't going to handle it.
if ( $class_name !== null ) {
return $class_name;
}
$parts = explode( ':', $event_type );
if ( $parts[0] === $this->event_namespace ) {
return $this;
}
return null;
}
/**
* Validates events for this event_namespace
*/
public function validate( $event ) {
$prefix = $this->event_namespace . ':' ;
if ( strpos( $event['type'], $prefix) !== 0 ) {
return new WP_Error( 'happytools-validation-engine', 'Incorrect event namespace: ' . $event );
}
/**
* Run the base validations provided by Event_Validator. If `true` returned
* we know that it passed the parent validations. If non-true literal returned
* abort validations and return error.
*/
$result = parent::validate( $event );
if ($result !== true) {
return $result;
}
/**
* Run all of the validators by reducing them to true or a WP_Error.
*/
$validator = $this->validations;
return $validator( $event );
}
}
/**
* Creates a callable that receives an event source event and returns true if the
* subtype of the event matches the provided $type
*
* @example
*
* subtype_is( 'my-subtype' )( [ 'type' => 'main-type:my-subtype' ] ); // => true
* subtype_is( 'other-subtype' )( [ 'type' => 'main-type:my-subtype' ] ); // => false
*
* @return callable
*/
function subtype_is( string $type ): callable {
return function( $event ) use ( $type ) {
$event_subtype = substr($event['type'], strpos( $event['type'], ':' ) + 1);
return $event_subtype === $type;
};
}
/**
* Given a detect callable and a validate callable, first checks if $detect()
* returns true and if so, returns the result of $validate
*
* @return callable function that receives an event source event and returns true if valid
*/
function validate_when( callable $detect, callable $validate ): callable {
return function ( $event ) use ( $detect, $validate ) {
if( $detect( $event ) ) {
return $validate( $event );
}
return true;
};
}
/**
* Given a subtype string and a callable $validator runs the validator when
* an event's subtype matches.
*
* @return callable that receives an event source event and returns true if valid
*/
function validate_subtype( string $subtype, callable $validator ): callable {
return validate_when( subtype_is( $subtype ), $validator );
}
/**
* Given an associated array of validators, runs the corresponding validator when
* the "subtype" of the event matches the key of the associative array
*
* A validator is any callable.
*
* @see { validate_subtype }
*
* @example
* validate_subtypes([
* 'my-special-event' => 'function_to_call_for_special_event'
* ])
*/
function validate_subtypes(array $validators): callable {
return function( $event ) use ( $validators ) {
foreach( $validators as $subtype => $validator ) {
$result = validate_subtype( $subtype, $validator)( $event );
if ( $result !== true ) {
return $result;
}
}
return true;
};
}
function validate_all(array $validators): callable {
return function( $event ) use ( $validators ) {
foreach( $validators as $validator ) {
$result = $validator( $event );
if ( $result !== true ) {
return $result;
}
}
return true;
};
}
function validate_version_exists($event) {
return new WP_Error( 'happytools-validation-engine', 'not implemented', [
'event' => $event,
]);
}
<?php
namespace Happytools\Subscriptions;
use Happytools\Events\Validation_Engine;
class Subscription {
static public function register_events() {
$validator = self::validator();
add_filter( 'happytools_event_validator', [$validator, 'detect_event'], null, 2);
}
static function validator() {
/**
* Creates a validator for all events that have a type matching
*
* subscriptions:*
*/
return new Validation_Engine('subscriptions', \Happytools\Events\validate_subtypes([
/**
* Validations for events of subsriptions:created
*/
'created' => function( $event ) {
return new \WP_Error('happytools', 'not implemented: ' . $event['type']);
},
/**
* Validations for events of subscriptions:delete
*/
'deleted' => \Happytools\Events\validate_all([
/**
* Function that checks for the aggregate_uuid has an existing
* version. If there isn't an existing version then it's not
* possible to delete.
*/
function() {
return new WP_Error('happytools-subscriptions', 'Deleting not implemented');
}
])
]));
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment