get_items_sorted( $endpoint_id_or_sort ); } } /** * Registers a new data endpoint to the master registry. * * @since 3.0 * * @throws \EDD_Exception if the endpoint could not be validated. * * @param string $endpoint_id Reports data endpoint ID. * @param array $attributes { * Endpoint attributes. All arguments are required unless otherwise noted. * * @type string $label Endpoint label. * @type int $priority Optional. Priority by which to retrieve the endpoint. Default 10. * @type array $views { * Array of view handlers by type. * * @type array $view_type { * View type slug, with array beneath it. * * @type callable $data_callback Callback used to retrieve data for the view. * @type callable $display_callback Callback used to render the view. * @type array $display_args Optional. Array of arguments to pass to the * display_callback (if any). Default empty array. * } * } * } * @return bool True if the endpoint was successfully registered, otherwise false. */ public function register_endpoint( $endpoint_id, $attributes ) { $defaults = array( 'label' => '', 'priority' => 10, 'views' => array(), ); $attributes = array_merge( $defaults, $attributes ); $attributes['id'] = $endpoint_id; $attributes['views'] = Reports\parse_endpoint_views( $attributes['views'] ); // Bail if this endpoint ID is already registered. if ( $this->offsetExists( $endpoint_id ) ) { $message = sprintf( 'The \'%1$s\' endpoint already exists and cannot be registered.', $endpoint_id ); throw new Utils\Exception( $message ); } try { $valid = $this->validate_endpoint( $endpoint_id, $attributes ); } catch ( \EDD_Exception $exception ) { throw $exception; } if ( false === $valid ) { return false; } else { try { $return_value = parent::add_item( $endpoint_id, $attributes ); } catch ( \EDD_Exception $exception ) { throw $exception; } return $return_value; } } /** * Validates the endpoint attributes. * * @since 3.0 * * @throws \EDD_Exception if the `$label` or `$views` attributes are empty. * @throws \EDD_Exception if any of the `$views` sub-attributes are empty, except `$filters`. * * @param string $endpoint_id Reports data endpoint ID. * @param array $attributes Endpoint attributes. See register_endpoint() for full accepted attributes. * @return bool True if the endpoint is considered 'valid', otherwise false. */ public function validate_endpoint( $endpoint_id, $attributes ) { $is_valid = true; try { $this->validate_attributes( $attributes, $endpoint_id ); try { $this->validate_views( $attributes['views'], $endpoint_id ); } catch( \EDD_Exception $exception ) { edd_debug_log_exception( $exception ); $is_valid = false; throw $exception; } } catch( \EDD_Exception $exception ) { edd_debug_log_exception( $exception ); $is_valid = false; throw $exception; } return $is_valid; } /** * Builds an endpoint object from a registry entry. * * @since 3.0 * * @param string|Endpoint $endpoint Endpoint ID or object. * @param string $view_type View type to use when building the object. * @param string $report Optional. Report ID. Default null. * @return Endpoint|\WP_Error Endpoint object on success, otherwise a WP_Error object. */ public function build_endpoint( $endpoint, $view_type, $report = null ) { // If an endpoint object was passed, just return it. if ( $endpoint instanceof Endpoint ) { return $endpoint; } try { $_endpoint = $this->get_endpoint( $endpoint ); } catch( \EDD_Exception $exception ) { edd_debug_log_exception( $exception ); return new \WP_Error( 'invalid_endpoint', $exception->getMessage(), $endpoint ); } if ( ! empty( $_endpoint ) ) { if ( Reports\validate_endpoint_view( $view_type ) ) { $_endpoint['report'] = $report; $handler = Reports\get_endpoint_handler( $view_type ); if ( ! empty( $handler ) && class_exists( $handler ) ) { $_endpoint = new $handler( $_endpoint ); } else { $_endpoint = new \WP_Error( 'invalid_handler', sprintf( 'The handler for the \'%1$s\' view is invalid.', $view_type ), $handler ); } } else { $_endpoint = new \WP_Error( 'invalid_view', sprintf( 'The \'%1$s\' view is invalid.', $view_type ) ); } } return $_endpoint; } /** * Validates view properties for an incoming endpoint. * * @since 3.0 * * @throws \EDD_Exception if the view attributes is empty or it's not a valid view. * * @param array $views List of attributes to check. * @param string $endpoint_id Endpoint ID. * @return void */ public function validate_views( $views, $endpoint_id ) { $valid_views = Reports\get_endpoint_views(); $this->validate_attributes( $views, $endpoint_id ); foreach ( $views as $view => $attributes ) { if ( array_key_exists( $view, $valid_views ) ) { if ( ! empty( $valid_views[ $view ]['allow_empty'] ) ) { $skip = $valid_views[ $view ]['allow_empty']; } else { $skip = array(); } // View atts have already been parsed at this point, just validate them. $this->validate_view_attributes( $attributes, $view, $skip ); } else { throw Reports_Exceptions\Invalid_View::from( $view, __METHOD__, $endpoint_id ); } } } /** * Validates a list of endpoint view attributes. * * @since 3.0 * * @throws \EDD_Exception if a required view attribute is empty. * * @param array $attributes List of view attributes to check for emptiness. * @param string $view View slug. * @param array $skip Optional. List of view attributes to skip validating. * Default empty array. * @return void */ public function validate_view_attributes( $attributes, $view, $skip = array() ) { foreach ( $attributes as $attribute => $value ) { if ( in_array( $attribute, $skip, true ) ) { continue; } if ( empty( $value ) ) { throw Reports_Exceptions\Invalid_View_Parameter::from( $attribute, __METHOD__, $view ); } } } }