434 lines
8.7 KiB
PHP
434 lines
8.7 KiB
PHP
<?php
|
|
/**
|
|
* Abstract for posts repository
|
|
*
|
|
* @package PUM
|
|
* @copyright Copyright (c) 2023, Code Atlantic LLC
|
|
*/
|
|
|
|
if ( ! defined( 'ABSPATH' ) ) {
|
|
exit;
|
|
}
|
|
|
|
/**
|
|
* Class PUM_Abstract_Repository_Posts
|
|
*
|
|
* Interface between WP_Query and our data needs. Essentially a query factory.
|
|
*/
|
|
abstract class PUM_Abstract_Repository_Posts implements PUM_Interface_Repository {
|
|
|
|
/**
|
|
* WordPress query object.
|
|
*
|
|
* @var WP_Query
|
|
*/
|
|
protected $query;
|
|
|
|
/**
|
|
* Array of hydrated object models.
|
|
*
|
|
* @var array
|
|
*/
|
|
protected $cache = [
|
|
'objects' => [],
|
|
'queries' => [],
|
|
];
|
|
|
|
/**
|
|
* @var string
|
|
*/
|
|
protected $model;
|
|
|
|
/**
|
|
* Should return a valid post type to test against.
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function get_post_type() {
|
|
return 'post';
|
|
}
|
|
|
|
/**
|
|
* Initialize the repository.
|
|
*/
|
|
protected function init() {
|
|
$this->query = new WP_Query();
|
|
$this->reset_strict_query_args();
|
|
}
|
|
|
|
public function __construct() {
|
|
$this->init();
|
|
}
|
|
|
|
/**
|
|
* @return array
|
|
*/
|
|
public function default_query_args() {
|
|
return [];
|
|
}
|
|
|
|
/**
|
|
* @var array
|
|
*/
|
|
protected $strict_query_args = [];
|
|
|
|
/**
|
|
* Returns an array of default strict query args that can't be over ridden, such as post type.
|
|
*
|
|
* @return array
|
|
*/
|
|
protected function default_strict_query_args() {
|
|
return [
|
|
'post_type' => $this->get_post_type(),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Returns an array of enforced query args that can't be over ridden, such as post type.
|
|
*
|
|
* @return array
|
|
*/
|
|
protected function get_strict_query_args() {
|
|
return $this->strict_query_args;
|
|
}
|
|
|
|
/**
|
|
* Sets a specific query arg to a strict value.
|
|
*
|
|
* @param $key
|
|
* @param null $value
|
|
*/
|
|
protected function set_strict_query_arg( $key, $value = null ) {
|
|
$this->strict_query_args[ $key ] = $value;
|
|
}
|
|
|
|
/**
|
|
* Returns an array of enforced query args that can't be over ridden, such as post type.
|
|
*
|
|
* @return array
|
|
*/
|
|
protected function reset_strict_query_args() {
|
|
$this->strict_query_args = $this->default_strict_query_args();
|
|
|
|
return $this->strict_query_args;
|
|
}
|
|
|
|
/**
|
|
* @param array $args
|
|
*
|
|
* @return array
|
|
*/
|
|
protected function _build_wp_query_args( $args = [] ) {
|
|
$args = wp_parse_args( $args, $this->default_query_args() );
|
|
|
|
$args = $this->build_wp_query_args( $args );
|
|
|
|
return array_merge( $args, $this->get_strict_query_args() );
|
|
}
|
|
|
|
/**
|
|
* @param array $args
|
|
*
|
|
* @return array
|
|
*/
|
|
protected function build_wp_query_args( $args = [] ) {
|
|
return $args;
|
|
}
|
|
|
|
/**
|
|
* @param int $id
|
|
*
|
|
* @return WP_Post|PUM_Abstract_Model_Post
|
|
* @throws \InvalidArgumentException
|
|
*/
|
|
public function get_item( $id ) {
|
|
if ( ! $this->has_item( $id ) ) {
|
|
throw new InvalidArgumentException( sprintf( __( 'No %1$s found with id %2$d.', 'popup-maker' ), $this->get_post_type(), $id ) );
|
|
}
|
|
|
|
return $this->get_model( $id );
|
|
}
|
|
|
|
/**
|
|
* @param $field
|
|
* @param $value
|
|
*
|
|
* @return PUM_Abstract_Model_Post|\WP_Post
|
|
*/
|
|
public function get_item_by( $field, $value ) {
|
|
global $wpdb;
|
|
|
|
$id = $wpdb->get_var( $wpdb->prepare( "SELECT ID FROM $wpdb->posts WHERE %s = %s", $field, $value ) );
|
|
|
|
if ( ! $id || ! $this->has_item( $id ) ) {
|
|
throw new InvalidArgumentException( sprintf( __( 'No user found with %1$s %2$s.', 'popup-maker' ), $field, $value ) );
|
|
}
|
|
|
|
return $this->get_model( $id );
|
|
}
|
|
|
|
/**
|
|
* @param int $id
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function has_item( $id ) {
|
|
return get_post_type( $id ) === $this->get_post_type();
|
|
}
|
|
|
|
/**
|
|
* @param $args
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function get_args_hash( $args ) {
|
|
return md5( serialize( $args ) );
|
|
}
|
|
|
|
/**
|
|
* @param array $args
|
|
*
|
|
* @return WP_Post[]|PUM_Abstract_Model_Post[]
|
|
*/
|
|
public function get_items( $args = [] ) {
|
|
/** Reset default strict query args. */
|
|
$this->reset_strict_query_args();
|
|
|
|
$args = $this->_build_wp_query_args( $args );
|
|
|
|
$hash = $this->get_args_hash( $args );
|
|
|
|
if ( ! isset( $this->cache['queries'][ $hash ] ) ) {
|
|
/**
|
|
* Initialize a new query and return it.
|
|
*
|
|
* This also keeps the query cached for potential later usage via $this->get_last_query();
|
|
*/
|
|
$this->query->query( $args );
|
|
|
|
$this->cache['queries'][ $hash ] = (array) $this->query->posts;
|
|
|
|
}
|
|
|
|
/** @var array $posts */
|
|
$posts = $this->cache['queries'][ $hash ];
|
|
|
|
/**
|
|
* Only convert to models if the model set is valid and not the WP_Post default.
|
|
*/
|
|
foreach ( $posts as $key => $post ) {
|
|
$posts[ $key ] = $this->get_model( $post );
|
|
}
|
|
|
|
return $posts;
|
|
}
|
|
|
|
/**
|
|
* @param array $args
|
|
*
|
|
* @return int
|
|
*/
|
|
public function count_items( $args = [] ) {
|
|
/** Reset default strict query args. */
|
|
$this->reset_strict_query_args();
|
|
|
|
/** Set several strict query arg overrides, no matter what args were passed. */
|
|
$this->set_strict_query_arg( 'fields', 'ids' );
|
|
$this->set_strict_query_arg( 'posts_per_page', 1 );
|
|
|
|
/** We don't use $this->query here to avoid returning count queries via $this->>get_last_query(); */
|
|
$query = new WP_Query( $this->_build_wp_query_args( $args ) );
|
|
|
|
return (int) $query->found_posts;
|
|
}
|
|
|
|
/**
|
|
* @return \WP_Query
|
|
*/
|
|
public function get_last_query() {
|
|
return $this->query;
|
|
}
|
|
|
|
/**
|
|
* Assert that data is valid.
|
|
*
|
|
* @param array $data
|
|
*
|
|
* @throws InvalidArgumentException
|
|
*
|
|
* TODO Add better Exceptions via these guides:
|
|
* - https://www.brandonsavage.net/using-interfaces-for-exceptions/
|
|
* - https://www.alainschlesser.com/structuring-php-exceptions/
|
|
*
|
|
* if ( isset( $data['subject'] ) && ! $data['subject'] ) {
|
|
* throw new InvalidArgumentException( 'The subject is required.' );
|
|
* }
|
|
*/
|
|
abstract protected function assert_data( $data );
|
|
|
|
/**
|
|
* @param array $data
|
|
*
|
|
* @return WP_Post|PUM_Abstract_Model_Post
|
|
* @throws InvalidArgumentException
|
|
*/
|
|
public function create_item( $data ) {
|
|
|
|
$data = wp_parse_args(
|
|
$data,
|
|
[
|
|
'content' => '',
|
|
'title' => '',
|
|
'meta_input' => [],
|
|
]
|
|
);
|
|
|
|
$this->assert_data( $data );
|
|
|
|
$post_id = wp_insert_post(
|
|
[
|
|
'post_type' => $this->get_post_type(),
|
|
'post_status' => 'publish',
|
|
'post_title' => $data['title'],
|
|
'post_content' => $data['content'],
|
|
'meta_input' => $data['meta_input'],
|
|
],
|
|
true
|
|
);
|
|
|
|
if ( is_wp_error( $post_id ) ) {
|
|
throw new InvalidArgumentException( $post_id->get_error_message() );
|
|
}
|
|
|
|
return $this->get_item( $post_id );
|
|
}
|
|
|
|
/**
|
|
* @param int $id
|
|
* @param array $data
|
|
*
|
|
* @return WP_Post|PUM_Abstract_Model_Post
|
|
* @throws Exception
|
|
*/
|
|
public function update_item( $id, $data ) {
|
|
|
|
$this->assert_data( $data );
|
|
|
|
/** @var WP_Post|PUM_Abstract_Model_Post $original */
|
|
$original = $this->get_item( $id );
|
|
|
|
$post_update = [];
|
|
|
|
foreach ( $data as $key => $value ) {
|
|
if ( $original->$key === $value ) {
|
|
continue;
|
|
}
|
|
|
|
switch ( $key ) {
|
|
default:
|
|
$post_update[ $key ] = $value;
|
|
break;
|
|
case 'title':
|
|
$post_update['post_title'] = $value;
|
|
break;
|
|
case 'content':
|
|
$post_update['post_content'] = $value;
|
|
break;
|
|
|
|
case 'custom_meta_key':
|
|
update_post_meta( $id, '_custom_meta_key', $value );
|
|
}
|
|
}
|
|
|
|
if ( count( $post_update ) ) {
|
|
$post_update['ID'] = $id;
|
|
wp_update_post( $post_update );
|
|
}
|
|
|
|
return $this->get_item( $id );
|
|
}
|
|
|
|
/**
|
|
* @param $post
|
|
*
|
|
* @return string
|
|
*/
|
|
protected function get_post_hash( $post ) {
|
|
return md5( serialize( $post ) );
|
|
}
|
|
|
|
/**
|
|
* @param $post
|
|
*
|
|
* @return bool
|
|
*/
|
|
protected function cached_model_exists( $post ) {
|
|
return isset( $this->cache['objects'][ $post->ID ] ) && $this->get_post_hash( $post ) === $this->cache['objects'][ $post->ID ]['hash'];
|
|
}
|
|
|
|
/**
|
|
* @param int|WP_Post $id
|
|
*
|
|
* @return WP_Post|PUM_Abstract_Model_Post
|
|
*/
|
|
protected function get_model( $id ) {
|
|
$post = is_a( $id, 'WP_Post' ) ? $id : get_post( $id );
|
|
|
|
/**
|
|
* Only convert to models if the model set is valid and not the WP_Post default.
|
|
*/
|
|
$model = $this->model;
|
|
if ( ! $model || 'WP_Post' === $model || ! class_exists( $model ) || is_a( $post, $model ) ) {
|
|
return $post;
|
|
}
|
|
|
|
if ( ! $this->cached_model_exists( $post ) ) {
|
|
$object = new $model( $post );
|
|
|
|
$this->cache['objects'][ $post->ID ] = [
|
|
'object' => $object,
|
|
'hash' => $this->get_post_hash( $post ),
|
|
];
|
|
}
|
|
|
|
return $this->cache['objects'][ $post->ID ]['object'];
|
|
}
|
|
|
|
/**
|
|
* @param int $id
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function delete_item( $id ) {
|
|
return EMPTY_TRASH_DAYS && (bool) wp_trash_post( $id );
|
|
}
|
|
|
|
/**
|
|
* @param int $id
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function is_item_trashed( $id ) {
|
|
return get_post_status( $id ) === 'trash';
|
|
}
|
|
|
|
/**
|
|
* @param int $id
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function untrash_item( $id ) {
|
|
return (bool) wp_untrash_post( $id );
|
|
}
|
|
|
|
/**
|
|
* @param int $id
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function force_delete_item( $id ) {
|
|
return (bool) wp_delete_post( $id, true );
|
|
}
|
|
|
|
}
|