-
Notifications
You must be signed in to change notification settings - Fork 27
dev!: handle property registration inside WP_Ability #54
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -100,21 +100,12 @@ class WP_Ability { | |
* @param array<string,mixed> $properties An associative array of properties for the ability. This should | ||
* include `label`, `description`, `input_schema`, `output_schema`, | ||
* `execute_callback`, `permission_callback`, and `meta`. | ||
* | ||
* @phpstan-param array{ | ||
* label: string, | ||
* description: string, | ||
* input_schema?: array<string,mixed>, | ||
* output_schema?: array<string,mixed>, | ||
* execute_callback: callable( array<string,mixed> $input): (mixed|\WP_Error), | ||
* permission_callback?: ?callable( array<string,mixed> $input ): (bool|\WP_Error), | ||
* meta?: array<string,mixed>, | ||
* ...<string, mixed>, | ||
* } $properties | ||
*/ | ||
public function __construct( string $name, array $properties ) { | ||
$this->name = $name; | ||
|
||
$this->validate_properties( $properties ); | ||
|
||
foreach ( $properties as $property_name => $property_value ) { | ||
Comment on lines
+107
to
109
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. An alternative approach is to replace the This would improve the DX both mapping and validation in the same step, but I'm not sure how flexible we want things to be at this initial stage vs once we've given the initial API + round of feedback time to percolate, so I went with the approach in the diff. e.g. (pseudocode) $properties = $this->prepare_args( $args );
if ( is_wp_error( $properties ) ) {
throw \InvalidArgumentException( $properties->getMessage() );
}
// This is still outside the function so extenders don't need to reimplement it.
foreach( $properties as $name => $value ) {
...
} There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. @gziolo / @felixarntz would love some specific thoughts on this if you have them. The more I think about it the more I feel like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, so you prefer to have The filter used with block types There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. My thoughts exactly. After the chat, I'll push a change with that approach. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not strongly opposed, but I also don't see the benefit of using To me it seems unnecessarily complex to rely on a method that can return Why not simply throw the exceptions? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Clarifying that my focus is on returning the array of (prepared) args instead of @@felixarntz I agree with you from a code quality POV From an implementer POV my thought was less "exceptions should be exceptional" and more "let's do it the WP™️ way 💪" :
(I drafted this before you both aligned yesterday on #53 and only saw after I pushed, so in my head this was still very much a proposal ). My takeaway from this conversation is that we're good not caring about that last point (between overloading and the filter if someone really, realy thinks shimming a DTO or VO into this api is a good idea, they have ways), so if y'all don't think it's outweighed by the first two (I don't), I'll use There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See #54 (comment). |
||
if ( ! property_exists( $this, $property_name ) ) { | ||
_doing_it_wrong( | ||
|
@@ -202,6 +193,76 @@ public function get_meta(): array { | |
return $this->meta; | ||
} | ||
|
||
/** | ||
* Validates the properties used to instantiate the ability. | ||
* | ||
* Errors are thrown as exceptions instead of \WP_Errors to allow for simpler handling and overloading. They are then | ||
* caught and converted to a WP_Error when by WP_Abilities_Registry::register(). | ||
* | ||
* @since n.e.x.t | ||
* | ||
* @see WP_Abilities_Registry::register() | ||
* | ||
* @param array<string,mixed> $properties An associative array of properties to validate. | ||
* | ||
* @return void | ||
* @throws \InvalidArgumentException if the properties are invalid. | ||
* | ||
* @phpstan-assert array{ | ||
* label: string, | ||
* description: string, | ||
* input_schema?: array<string,mixed>, | ||
* output_schema?: array<string,mixed>, | ||
* execute_callback: callable( array<string,mixed> $input): (mixed|\WP_Error), | ||
* permission_callback?: ?callable( array<string,mixed> $input ): (bool|\WP_Error), | ||
* meta?: array<string,mixed>, | ||
* ...<string, mixed>, | ||
* } $properties | ||
*/ | ||
protected function validate_properties( array $properties ) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The only changes here are that they're now There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I double-checked with the implementation @felixarntz used in the demo plugin and it seems to be compatible even with the strict checks for madatory properties: label, description and execute callback. |
||
if ( empty( $properties['label'] ) || ! is_string( $properties['label'] ) ) { | ||
justlevine marked this conversation as resolved.
Show resolved
Hide resolved
|
||
throw new \InvalidArgumentException( | ||
esc_html__( 'The ability properties must contain a `label` string.' ) | ||
); | ||
} | ||
|
||
if ( empty( $properties['description'] ) || ! is_string( $properties['description'] ) ) { | ||
justlevine marked this conversation as resolved.
Show resolved
Hide resolved
|
||
throw new \InvalidArgumentException( | ||
esc_html__( 'The ability properties must contain a `description` string.' ) | ||
); | ||
} | ||
|
||
if ( isset( $properties['input_schema'] ) && ! is_array( $properties['input_schema'] ) ) { | ||
throw new \InvalidArgumentException( | ||
esc_html__( 'The ability properties should provide a valid `input_schema` definition.' ) | ||
); | ||
} | ||
|
||
if ( isset( $properties['output_schema'] ) && ! is_array( $properties['output_schema'] ) ) { | ||
throw new \InvalidArgumentException( | ||
esc_html__( 'The ability properties should provide a valid `output_schema` definition.' ) | ||
); | ||
} | ||
|
||
if ( empty( $properties['execute_callback'] ) || ! is_callable( $properties['execute_callback'] ) ) { | ||
justlevine marked this conversation as resolved.
Show resolved
Hide resolved
|
||
throw new \InvalidArgumentException( | ||
esc_html__( 'The ability properties must contain a valid `execute_callback` function.' ) | ||
); | ||
} | ||
|
||
if ( isset( $properties['permission_callback'] ) && ! is_callable( $properties['permission_callback'] ) ) { | ||
throw new \InvalidArgumentException( | ||
esc_html__( 'The ability properties should provide a valid `permission_callback` function.' ) | ||
); | ||
} | ||
|
||
if ( isset( $properties['meta'] ) && ! is_array( $properties['meta'] ) ) { | ||
throw new \InvalidArgumentException( | ||
esc_html__( 'The ability properties should provide a valid `meta` array.' ) | ||
); | ||
} | ||
} | ||
|
||
/** | ||
* Validates input data against the input schema. | ||
* | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A small part of me thinks that we should change all the references of
properties
toargs
to bring it inline with other WP core naming, now that we've broken the direct dependency to add a validator. 🤷I could add it in this PR but i didnt want to obfuscate the discussion on #53
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have now
ability_class
which isn't strictly a property of the object, so I don't mind changing toargs
at this point. If you want to take care of it, let's put it into a separate PR to keep the current refactor lean.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 to changing this to use
$args
.