felixarntz/plugin-lib

View on GitHub
src/db-objects/traits/status-manager-trait.php

Summary

Maintainability
C
1 day
Test Coverage
<?php
/**
 * Trait for managers that support statuses
 *
 * @package Leaves_And_Love\Plugin_Lib
 * @since 1.0.0
 */

namespace Leaves_And_Love\Plugin_Lib\DB_Objects\Traits;

use Leaves_And_Love\Plugin_Lib\DB_Objects\Model_Status_Manager;
use Leaves_And_Love\Plugin_Lib\DB_Objects\Model_Status;

if ( ! trait_exists( 'Leaves_And_Love\Plugin_Lib\DB_Objects\Traits\Status_Manager_Trait' ) ) :

    /**
     * Trait for managers.
     *
     * Include this trait for managers that support statuses.
     *
     * @since 1.0.0
     */
    trait Status_Manager_Trait {
        /**
         * The status property of the model.
         *
         * @since 1.0.0
         * @var string
         */
        protected $status_property = 'status';

        /**
         * Internal storage for pending status changes.
         *
         * @since 1.0.0
         * @var array
         */
        protected $pending_status_changes = array();

        /**
         * The status manager service definition.
         *
         * @since 1.0.0
         * @static
         * @var string
         */
        protected static $service_statuses = Model_Status_Manager::class;

        /**
         * Registers a new status.
         *
         * @since 1.0.0
         *
         * @param string $slug Unique slug for the status.
         * @param array  $args Optional. Array of status arguments. Default empty.
         * @return bool True on success, false on failure.
         */
        public function register_status( $slug, $args = array() ) {
            return $this->statuses()->register( $slug, $args );
        }

        /**
         * Retrieves a status object.
         *
         * @since 1.0.0
         *
         * @param string $slug Unique slug of the status.
         * @return Model_Status|null Type object, or null it it does not exist.
         */
        public function get_status( $slug ) {
            return $this->statuses()->get( $slug );
        }

        /**
         * Queries for multiple status objects.
         *
         * @since 1.0.0
         *
         * @param array $args Array of query arguments.
         * @return array Array of status objects.
         */
        public function query_statuses( $args ) {
            return $this->statuses()->query( $args );
        }

        /**
         * Unregisters an existing status.
         *
         * @since 1.0.0
         *
         * @param string $slug Unique slug of the status.
         * @return bool True on success, false on failure.
         */
        public function unregister_status( $slug ) {
            return $this->statuses()->unregister( $slug );
        }

        /**
         * Returns the name of the status property in a model.
         *
         * @since 1.0.0
         *
         * @return string Name of the status property.
         */
        public function get_status_property() {
            return $this->status_property;
        }

        /**
         * Prepares data for triggering a hook for transitioning the status property on a model.
         *
         * @since 1.0.0
         *
         * @param null  $pre   Null value from the pre-filter.
         * @param Model $model The model to modify.
         * @return null The unmodified pre-filter value.
         */
        public function maybe_set_transition_status_property_data( $pre, $model ) {
            $status_property = $this->get_status_property();

            $primary_property = $this->get_primary_property();
            if ( empty( $model->$primary_property ) ) {
                return $pre;
            }

            $old_model_data = $this->fetch( $model->$primary_property );
            $this->pending_status_changes[ $model->$primary_property ] = $old_model_data->$status_property;

            return $pre;
        }

        /**
         * Triggers a hook for transitioning the status property on a model, if necessary.
         *
         * @since 1.0.0
         *
         * @param bool|WP_Error $result Result of the sync process.
         * @param Model         $model  The model to modify.
         * @return null The unmodified post-filter value.
         */
        public function maybe_transition_status_property( $result, $model ) {
            if ( is_wp_error( $result ) && in_array( $result->get_error_code(), array( 'db_insert_error', 'db_update_error' ), true ) ) {
                return $result;
            }

            $primary_property = $this->get_primary_property();
            $status_property  = $this->get_status_property();

            $old_status = '';
            if ( false !== strpos( current_filter(), '_add_' ) ) {
                $old_status = $this->statuses()->get_default();
            } elseif ( ! empty( $this->pending_status_changes[ $model->$primary_property ] ) ) {
                $old_status = $this->pending_status_changes[ $model->$primary_property ];
                unset( $this->pending_status_changes[ $model->$primary_property ] );
            }

            if ( ! empty( $old_status ) && ! empty( $model->$status_property ) && $old_status !== $model->$status_property ) {
                $prefix        = $this->get_prefix();
                $singular_slug = $this->get_singular_slug();

                /**
                 * Fires when the status property of a model has changed.
                 *
                 * @since 1.0.0
                 *
                 * @param string $new_status New status of the model.
                 * @param string $old_status Old status of the model.
                 * @param Model  $model      The model object.
                 */
                do_action( "{$prefix}transition_{$singular_slug}_{$status_property}", $model->$status_property, $old_status, $model );
            }

            return $result;
        }

        /**
         * Renders a status select field for the misc publishing area of the model edit page.
         *
         * @since 1.0.0
         *
         * @param int|null $id    Current model ID, or null if new model.
         * @param Model    $model Current model object.
         */
        public function render_status_select( $id, $model ) {
            if ( ! method_exists( $this, 'get_status_property' ) ) {
                return;
            }

            $capabilities = $this->capabilities();

            $status_property = $this->get_status_property();
            $current_status  = $model->$status_property;

            if ( $capabilities && $capabilities->user_can_publish( null, $id ) ) {
                $statuses = $this->statuses()->query();
            } else {
                $statuses = $this->statuses()->query(
                    array(
                        'public'   => false,
                        'slug'     => $current_status,
                        'operator' => 'OR',
                    )
                );
            }

            if ( empty( $statuses ) ) {
                return;
            }

            ?>
            <div class="misc-pub-section">
                <div id="post-status-select">
                    <label for="post-status"><?php echo esc_html( $this->get_message( 'edit_page_status_label' ) ); ?></label>
                    <select id="post-status" name="<?php echo esc_attr( $status_property ); ?>">
                        <?php foreach ( $statuses as $status ) : ?>
                            <option value="<?php echo esc_attr( $status->slug ); ?>"<?php selected( $current_status, $status->slug ); ?>><?php echo esc_html( $status->label ); ?></option>
                        <?php endforeach; ?>
                    </select>
                </div>
            </div>
            <?php
        }
    }

endif;