diff --git a/src/Data/NinjaFormsDataSource.php b/src/Data/NinjaFormsDataSource.php new file mode 100644 index 0000000..ec8bdcf --- /dev/null +++ b/src/Data/NinjaFormsDataSource.php @@ -0,0 +1,267 @@ +<?php +/** + * Ninja Forms Data Source + * + * @since $ver$ + * @package DataKit\Plugin\Data + */ + +namespace DataKit\Plugin\Data; + +use DataKit\DataViews\Data\BaseDataSource; +use DataKit\DataViews\Data\MutableDataSource; +use DataKit\DataViews\Data\Exception\DataNotFoundException; +use NinjaForms\Includes\Factories\SubmissionFilterFactory; +use NinjaForms\Includes\Factories\SubmissionAggregateFactory; + +/** + * Data source backed by a Ninja Forms form. + * + * @since $ver$ + */ +class NinjaFormsDataSource extends BaseDataSource implements MutableDataSource { + + /** + * The form ID. + * + * @var int + * @since $ver$ + */ + private int $form_id; + + /** + * The form object. + * + * @var \NF_Abstracts_ModelFactory + * @since $ver$ + */ + private $form; + + /** + * Microcache for the "current" entries. + * + * @var array + * @since $ver$ + */ + private array $entries; + + /** + * Microcache for the data source fields. + * + * @var array + * @since $ver$ + */ + private array $fields; + + /** + * Constructor. + * + * @since $ver$ + * + * @param int $form_id The form ID. + * + * @throws DataNotFoundException When the data source could not be instantiated. + */ + public function __construct( int $form_id ) { + + if ( ! class_exists( 'Ninja_Forms' ) ) { + throw new DataNotFoundException( esc_html__( 'Data source cannot be used, as Ninja Forms is not available.', 'dk-datakit' ) ); + } + + $this->form = \Ninja_Forms()->form( $form_id )->get(); + + if ( ! $this->form ) { + throw new DataNotFoundException( sprintf( esc_html__( 'Ninja Forms data source (%d) not found', 'dk-datakit' ), $form_id ) ); + } + + $this->form_id = $form_id; + } + + /** + * Get the unique identifier for this data source. + * + * @since $ver$ + * + * @return string The unique identifier. + */ + public function id(): string { + return sprintf( 'ninja-forms-%d', $this->form_id ); + } + + /** + * Get data IDs based on the current query. + * + * @since $ver$ + * + * @todo Implement searching and sorting. + * + * @param int $limit The number of items to return. + * @param int $offset The number of items to skip. + * + * @return array An array of data IDs. + */ + public function get_data_ids( int $limit = 100, int $offset = 0 ): array { + + if ( ! $this->form ) { + return []; + } + + $current_page = floor( $offset / $limit ) + 1; + + // Initialize the meta query with the existing condition + $meta_query = [ + [ + 'key' => '_form_id', + 'value' => $this->form_id, + 'compare' => '=', // Optional: specify the comparison operator + ], + // TODO: Implement search and sorting. + ]; + + // Initialize the main query arguments + $args = [ + 'post_type' => 'nf_sub', + 'posts_per_page' => $limit, + 'paged' => $current_page, + 'post_status' => [ 'active', 'publish' ], // Array of post statuses + 'meta_query' => $meta_query, + ]; + + // Execute the query + $subs = get_posts( $args ); + + return wp_list_pluck( $subs, 'ID' ); + } + + /** + * Get data by ID. + * + * @since $ver$ + * + * @param string $id The ID of the data to retrieve. + * + * @return array The data associated with the given ID. + * @throws DataNotFoundException If the data is not found. + */ + public function get_data_by_id( string $id ): array { + $submission = $this->entries[ $id ] ?? $this->get_single_submission( $id ); + + if ( ! $submission ) { + throw DataNotFoundException::with_id( $this, $id ); + } + + return $this->format_submission( $submission ); + } + + /** + * Format a submission for output. + * + * @since $ver$ + * + * @param \NF_Database_Models_Submission $submission The submission to format. + * + * @return array The formatted submission data. + */ + private function format_submission( \NF_Database_Models_Submission $submission ): array { + $formatted = [ + 'id' => $submission->get_seq_num(), + 'date_submitted' => $submission->get_sub_date(), + 'status' => $submission->get_status(), + ]; + + $field_values = $submission->get_field_values(); + foreach ( $field_values as $field_id => $value ) { + $formatted[ $field_id ] = $value; + } + + return $formatted; + } + + /** + * Get the total count of items in the data source. + * + * @since $ver$ + * + * @todo Implement filters and search. + * + * @return int The total count of items. + */ + public function count(): int { + $params = []; + + return sizeof( \Ninja_Forms()->form( $this->form_id )->get_subs( $params ) ); + } + + /** + * Check if the current user can delete items. + * + * @since $ver$ + * + * @return bool Whether the current user can delete items. + */ + public function can_delete(): bool { + return current_user_can( 'delete_posts' ); // TODO: Is there a better capability to check? + } + + /** + * Delete data by ID. + * + * @since $ver$ + * + * @param string ...$ids The IDs of the data to delete. + */ + public function delete_data_by_id( string ...$ids ): void { + foreach ( $ids as $id ) { + if ( ! current_user_can( 'delete_post', $id ) ) { + continue; + } + + $sub = \Ninja_Forms()->form( $this->form_id )->get_sub( $id ); + if ( $sub ) { + $sub->delete(); + } + } + } + + /** + * Get the fields available in this data source. + * + * @since $ver$ + * + * @return array An array of available fields. + */ + public function get_fields(): array { + if ( ! empty( $this->fields ) ) { + return $this->fields; + } + + $form_fields = \Ninja_Forms()->form( $this->form_id )->get_fields(); + + $fields = [ + 'id' => __( 'ID', 'dk-datakit' ), + 'date_submitted' => __( 'Date Submitted', 'dk-datakit' ), + 'status' => __( 'Status', 'dk-datakit' ), + ]; + + foreach ( $form_fields as $field ) { + $fields[ $field->get_id() ] = $field->get_setting( 'label' ); + } + + $this->fields = $fields; + + return $this->fields; + } + + /** + * Get a single submission by ID. + * + * @since $ver$ + * + * @param string $id The ID of the submission to retrieve. + * + * @return \NF_Database_Models_Submission|null The submission object, or null if not found. + */ + private function get_single_submission( string $id ): ?\NF_Database_Models_Submission { + return \Ninja_Forms()->form( $this->form_id )->get_sub( $id ); + } +}