classes/class-alert.php

Summary

Maintainability
A
1 hr
Test Coverage
F
53%
<?php
/**
 * Manages a single alert, acting as a model.
 *
 * @package WP_Stream
 */

namespace WP_Stream;

/**
 * Class Alert
 *
 * @package WP_Stream
 */
class Alert {

    /**
     * Alert post ID
     *
     * @var int
     */
    public $ID;

    /**
     * Creation date
     *
     * @var string
     */
    public $date;

    /**
     * Status
     *
     * @var string
     */
    public $status;

    /**
     * Alert author ID
     *
     * @var int
     */
    public $author;

    /**
     * Alert type
     *
     * @var string
     */
    public $alert_type;

    /**
     * Alert meta data
     *
     * @var int
     */
    public $alert_meta;

    /**
     * Holds instance of plugin object
     *
     * @var Plugin
     */
    public $plugin;

    /**
     * Class constructor
     *
     * @param object $item Alert data.
     * @param Plugin $plugin Instance of plugin object.
     * @return void
     */
    public function __construct( $item, $plugin ) {
        $this->plugin = $plugin;

        $this->ID     = isset( $item->ID ) ? $item->ID : null;
        $this->status = isset( $item->status ) ? $item->status : 'wp_stream_disabled';
        $this->date   = isset( $item->date ) ? $item->date : null;
        $this->author = isset( $item->author ) ? $item->author : null;

        $this->alert_type = isset( $item->alert_type ) ? $item->alert_type : null;
        $this->alert_meta = isset( $item->alert_meta ) ? $item->alert_meta : array();
    }

    /**
     * Saves alert state.
     *
     * @todo Clean up/Remove unnecessary conditional statements.
     * @return int The Post ID of the alert.
     */
    public function save() {

        $args = array(
            'ID'           => $this->ID,
            'post_date'    => $this->date,
            'post_status'  => $this->status,
            'post_content' => '',
            'post_title'   => $this->get_title(),
            'post_author'  => $this->author,
            'post_type'    => Alerts::POST_TYPE,
        );

        // Remove empty "ID" field, if new post.
        if ( empty( $args['ID'] ) ) {
            unset( $args['ID'] );
        }

        // Create or update alert and assign the ID.
        $post_id = wp_insert_post( $args );
        if ( empty( $args['ID'] ) ) {
            $this->ID = $post_id;
        }

        // Save alert type and meta.
        $meta = array(
            'alert_type' => $this->alert_type,
            'alert_meta' => $this->alert_meta,
        );

        foreach ( $meta as $key => $value ) {
            $this->update_meta( $key, $value );
        }

        return $post_id;
    }

    /**
     * Process settings form data
     *
     * @todo Confirm if the function is necessary, it's currently unreference
     * anywhere else in the plugin.
     * @param array $data Processed post object data.
     * @return array New post object data.
     */
    public function process_settings_form( $data ) {

        $args = array(
            'post_date'   => $this->date,
            'post_status' => $this->status,
            'post_title'  => $this->get_title(),
            'post_author' => $this->author,
            'post_type'   => Alerts::POST_TYPE,
        );

        foreach ( $args as $key => $value ) {
            $data[ $key ] = $value;
        }

        $meta_input = array(
            'alert_type' => $this->alert_type,
            'alert_meta' => $this->alert_meta,
        );

        foreach ( $meta_input as $key => $value ) {
            $this->update_meta( $key, $value );
        }

        return $data;
    }

    /**
     * Query record meta
     *
     * @param string $meta_key Meta key to retrieve (optional). Otherwise will
     *  grab all meta data for the ID.
     * @param bool   $single Whether to only retrieve the first value (optional).
     *
     * @return mixed Single value if $single is true, array if false.
     */
    public function get_meta( $meta_key = '', $single = false ) {
        return get_post_meta( $this->ID, $meta_key, $single );
    }

    /**
     * Update record meta
     *
     * @param string $meta_key Meta key to update.
     * @param string $meta_value Value to update with.
     * @param string $prev_value Previous value to change (optional).
     * @return array
     */
    public function update_meta( $meta_key, $meta_value, $prev_value = '' ) {
        return update_post_meta( $this->ID, $meta_key, $meta_value, $prev_value );
    }

    /**
     * Determine the title of the alert.
     *
     * @todo enhance human readability
     * @return string The title of the alert
     */
    public function get_title() {

        $alert_type = $this->get_alert_type_obj()->name;

        $output = array();
        foreach ( array( 'action', 'author', 'context' ) as $trigger_type ) {
            $output[ $trigger_type ] = $this->plugin->alerts->alert_triggers[ $trigger_type ]->get_display_value( 'list_table', $this );
        }
        $title = '';
        foreach ( $this->plugin->alerts->alert_triggers as $trigger_type => $trigger_obj ) {
            $value  = $trigger_obj->get_display_value( 'list_table', $this );
            $title .= $value . ' > ';
        }
        $title = rtrim( $title, ' > ' );
        return $title;
    }

    /**
     * Retrieve current alert type object
     *
     * @return Alert_Type
     */
    public function get_alert_type_obj() {
        if ( array_key_exists( $this->alert_type, $this->plugin->alerts->alert_types ) ) {
            $obj = $this->plugin->alerts->alert_types[ $this->alert_type ];
        } else {
            $obj = new Alert_Type_None( $this->plugin );
        }
        return $obj;
    }

    /**
     * Check if record matches trigger criteria.
     *
     * @param int   $record_id Record ID.
     * @param array $recordarr Record data.
     * @return bool True if a positive match. False otherwise.
     */
    public function check_record( $record_id, $recordarr ) {
        return apply_filters( 'wp_stream_alert_trigger_check', true, $record_id, $recordarr, $this );
    }

    /**
     * Trigger alert for a specific record.
     *
     * @param int $record_id Record ID.
     * @param int $recordarr Record Data.
     */
    public function send_alert( $record_id, $recordarr ) {
        $this->get_alert_type_obj()->alert( $record_id, $recordarr, $this );
    }

    /**
     * Record Alerts triggered by a Record.
     *
     * This should be used any time an alert is triggered.
     *
     * Stores the post ID of an Alert triggered by a record.
     *
     * As an example, this exists so that its value(s) can then be used
     * to fetch meta from that Alert in later operations.
     *
     * This also creates the Alert triggered meta if not found.
     *
     * @see Alert_Type_Highlight::alert() for an example.
     *
     * @param object $record     The Record.
     * @param string $alert_slug The Alert Type slug.
     * @param array  $alert_meta Alert meta.
     *
     * @return bool If the meta was updated successfully.
     */
    public static function update_record_triggered_alerts( $record, $alert_slug, $alert_meta ) {
        if ( ! is_string( $alert_slug ) ) {
            return false;
        }

        if ( is_array( $record ) ) {
            $record = (object) $record;
        }
        if ( empty( $record->ID ) ) {
            return false;
        }
        $record           = new Record( $record );
        $alerts_triggered = $record->get_meta( Alerts::ALERTS_TRIGGERED_META_KEY, true );

        if ( empty( $alerts_triggered ) || ! is_array( $alerts_triggered ) ) {
            $alerts_triggered = array(
                $alert_slug => $alert_meta,
            );
        } elseif ( ! array_key_exists( $alert_slug, $alerts_triggered ) || ! is_array( $alerts_triggered[ $alert_slug ] ) ) {
            $alerts_triggered[ $alert_slug ] = $alert_meta;
        }
        return $record->update_meta( Alerts::ALERTS_TRIGGERED_META_KEY, $alerts_triggered );
    }

    /**
     * Get a meta value from the Alert that a Record has triggered.
     *
     * If a Record has triggered an Alert (post), this fetches a specific
     * Alert meta (i.e., "post meta") value from that Alert.
     *
     * First, it gets the array of Alerts that the Record has triggered.
     * Then, using the requested Alert Type, it grabs the first item (post ID) in
     * that Type.
     *
     * Using that ID, it fetches that Alert post's meta, then
     * returns the value of the requested setting (ie., "post meta" field).
     *
     * @see Alert_Type_Highlight::post_class() for an example.
     *
     * @param object $record The Record object.
     * @param string $alert_slug The slug of the Alert Type.
     * @param string $setting The requested meta value of the Alert.
     * @param mixed  $default The default value if no value is found.
     *
     * @return mixed
     */
    public function get_single_alert_setting_from_record( $record, $alert_slug, $setting, $default = false ) {
        if ( ! is_object( $record ) || ! is_string( $alert_slug ) || ! is_string( $setting ) ) {
            return false;
        }
        $record           = new Record( $record );
        $alerts_triggered = $record->get_meta( Alerts::ALERTS_TRIGGERED_META_KEY, true );

        // Ensure we have a meta array and that this record has triggered a highlight alert.
        if ( empty( $alerts_triggered ) || ! is_array( $alerts_triggered ) || ! array_key_exists( $alert_slug, $alerts_triggered ) ) {
            return false;
        }

        $values = $alerts_triggered[ $alert_slug ];
        if ( empty( $values ) ) {
            return false;
        }

        /**
         * Grab an Alert post ID.
         *
         * @todo Determine which Alert post takes priority.
         */
        if ( is_array( $values ) ) {
            $post_id = $values[0];
        } else {
            $post_id = $values;
        }

        if ( ! is_numeric( $post_id ) ) {
            return false;
        }

        $alert = $this->plugin->alerts->get_alert( $post_id );

        $value = ! empty( $alert->alert_meta[ $setting ] ) ? $alert->alert_meta[ $setting ] : $default;
        return $value;
    }
}