summaryrefslogblamecommitdiffstats
path: root/includes/class-giglogadmin-concert.php
blob: a4513db858c0398cc0b2e92dc0114a5accfe39b5 (plain) (tree)
1
2
3
4
5
6
7
8
9
10
11
     









                                                                               
 
                                                
 


                                                           

                               
                                                                 
                         
                               
                                          
                                         


                                   
                             

                                            
                       
 





                                               
 
 
           
                                                                       
          


                                                                      

                                                                       
           


                                                                                             
                                                                                     





                                                                                                                       

                                           









                                                                                         
                 

                                    
             

         
           
                                                
          
                                                              
                            
           
                                                       













                                                                           

         










                                                                                      







                                                                                                                                  
 
                                     
                                                                











                                                                                            
 
                                 
 
                                                   
             


         




                                                                      
                                                        

                                 
                                                                                                



                                                       
                                                                                                
                                                                                


                                    
                                                                                                        



                                                            
                                                                                                      
                                                                


                                    
                                                                                                     



                                                          
                                                                                                  



                                                        

                                                                                    

                                    
 
                                 
                              

             
                                

         





                                                                        
                                                                                                       

                         


                                                        

                                                   
                    


                                                                                     
                                                                                                                        
 
                            


                                                                  
                                                    



                                                                              
              
 
                             

                        

                         

                                                   

                                
                                 

                                 
                                                                                                

                              
                              
                                    
                                                                                                
                              

                                       
                                                                                                                 
                              
 



                                                 
                                  
                                                   
                              
 
                                 
                                                  
                              
                 

             
                                      
                                                               
             
 



                                                 
                                                  
                                                  
 










                                                                               
                                                                           

                                             
                                                                                 

                         
                                                          

                                                                
                                                    
 
                                                                                    

         


                                                                  
                                                                               

                      
                                                                       

                         
                                                         

                                                                
                                              



                                       
           















                                                                               

                                    
                                       

                         
                             

                                                  
                                                                 



                                                                     
              
 
                                       


                                                                                                                     
             
 
                                   
                                                 
                                             

                                             

         


                                          

                                              

         


                                     

                                                    
         



                                    

                                 
         



                                          

                                                     
         



                                                 
                                   
                                                         
         



                                                 
                                     
                                                             
         
 


                                            
                                        
                                  

         




                                                                   

                                                       

         




                                                     
                                         
                                                         
         
 





                                                                   

                                                                              
         
 




                                                                      

                                                                                    
         
 


                                                      



                                                       


                                                             


                                                       

     
<?php
/**
 * Class to handle concerts
 *
 * @package giglogadmin
 *
 * SPDX-FileCopyrightText: 2021 Andrea Chirulescu <andrea.chirulescu@gmail.com>
 * SPDX-FileCopyrightText: 2021 Harald Eilertsen <haraldei@anduin.net>
 *
 * SPDX-License-Identifier: AGPL-3.0-or-later
 */

if ( ! class_exists( 'GiglogAdmin_Concert' ) ) {

    /**
     * Class to hold all information about a given concert.
     */
    class GiglogAdmin_Concert {

        // phpcs:disable Squiz.Commenting.VariableComment.Missing
        private ?int $id;
        private ?string $cname;
        private ?GiglogAdmin_Venue $venue;
        private DateTimeImmutable $cdate;
        private ?string $tickets;
        private ?string $eventlink;
        private ?int $status;
        private array $roles;
        private ?DateTimeImmutable $created;
        private ?DateTimeImmutable $updated;
        // phpcs:enable

        public const STATUS_NONE = 0;
        public const STATUS_ACCRED_REQ = 1;
        public const STATUS_PHOTO_APPROVED = 2;
        public const STATUS_TEXT_APPROVED = 3;
        public const STATUS_ALL_APPROVED = 4;
        public const STATUS_REJECTED = 5;


        /**
         * Constructs a new concert object from an array of attributes.
         *
         * The attributes are expected to be named as in the database,
         * so this constructor can be used to construct the object
         * directly from the database row.
         *
         * @param object $attrs an object or array with the attributes.
         */
        public function __construct( object $attrs ) {
            $this->id = isset( $attrs->id ) ? $attrs->id : null;
            $this->cname = isset( $attrs->wpgconcert_name ) ? $attrs->wpgconcert_name : null;
            $this->cdate = new DateTimeImmutable( $attrs->wpgconcert_date ?? 'now' );
            $this->tickets = isset( $attrs->wpgconcert_tickets ) ? $attrs->wpgconcert_tickets : null;
            $this->eventlink = isset( $attrs->wpgconcert_event ) ? $attrs->wpgconcert_event : null;
            $this->status = isset( $attrs->wpgconcert_status ) ? $attrs->wpgconcert_status : 0;
            $this->roles = isset( $attrs->wpgconcert_roles ) ? json_decode( $attrs->wpgconcert_roles, true ) : array();
            $this->created = isset( $attrs->created ) ? new DateTimeImmutable( $attrs->created ) : null;
            $this->updated = isset( $attrs->updated ) ? new DateTimeImmutable( $attrs->updated ) : null;

            if ( isset( $attrs->venue ) ) {
                if ( isset( $attrs->wpgvenue_name ) && isset( $attrs->wpgvenue_city ) ) {
                    $venue_attrs = (object) array(
                        'id' => $attrs->venue,
                        'wpgvenue_name' => $attrs->wpgvenue_name,
                        'wpgvenue_city' => $attrs->wpgvenue_city,
                    );

                    $this->venue = new GiglogAdmin_Venue( $venue_attrs );
                } else {
                    $this->venue = GiglogAdmin_Venue::get( $attrs->venue );
                }
            } else {
                $this->venue = null;
            }
        }

        /**
         * Return the concert with the given id.
         *
         * @param int $id Database id of the concert to fetch.
         * @return null|self
         */
        public static function get( int $id ) : ?self {
            $gigs = self::find_concerts( array( 'id' => $id ) );
            $count = count( $gigs );

            if ( $count > 1 ) {
                error_log(
                    "Found more than one concert with the same id ({$id})."
                    . ' This should not happen!'
                );
                wp_die( 'Oops! Something went wrong', 500 );
            } else if ( $count != 1 ) {
                return null;
            } else {
                return array_shift( $gigs );
            }
        }

        /**
         * Create a new concert object.
         *
         * @param string $name  The concert description.
         * @param int    $venue_id The id of the venue where the concert will be held.
         * @param string $date  The date of the concert.
         * @param string $ticketlink    URL where tickets can be bough.
         * @param string $eventlink     URL for more information about concert.
         *
         * @throws GiglogAdmin_DuplicateConcertException If concert is a duplicate.
         */
        public static function create( string $name, int $venue_id, string $date, string $ticketlink, string $eventlink ): ?self {
            $gigs = self::find_concerts(
                array(
					'name' => $name,
					'venue_id' => $venue_id,
					'date' => $date,
                )
            );

            if ( ! empty( $gigs ) ) {
                throw new GiglogAdmin_DuplicateConcertException(
                    "Duplicate concert: name: {$name}, venue_id: {$venue_id}, date: {$date}"
                );
            } else {
                $concert = new GiglogAdmin_Concert(
                    (object) array(
						'wpgconcert_name' => $name,
						'venue' => $venue_id,
						'wpgconcert_date' => $date,
						'wpgconcert_tickets' => $ticketlink,
						'wpgconcert_event' => $eventlink,
                    )
                );

                $concert->save();

                return self::get( $concert->id() );
            }
        }


        /**
         * Update a concert with new content and save to database.
         *
         * @param object $attrs Object or array of changed attributes.
         */
        public function update( object $attrs ) : bool {
            $need_update = false;

            if ( isset( $attrs->wpgconcert_name ) && $attrs->wpgconcert_name != $this->cname ) {
                $this->cname = $attrs->wpgconcert_name;
                $need_update = true;
            }

            if ( isset( $attrs->wpgconcert_date ) && $attrs->wpgconcert_date != $this->cdate ) {
                $this->cdate = new DateTimeImmutable( $attrs->wpgconcert_date );
                $need_update = true;
            }

            if ( isset( $attrs->wpgconcert_tickets ) && $attrs->wpgconcert_tickets != $this->tickets ) {
                $this->tickets = $attrs->wpgconcert_tickets;
                $need_update = true;
            }

            if ( isset( $attrs->wpgconcert_event ) && $attrs->wpgconcert_event != $this->eventlink ) {
                $this->eventlink = $attrs->wpgconcert_eventlink;
                $need_update = true;
            }

            if ( isset( $attrs->wpgconcert_status ) && $attrs->wpgconcert_status != $this->status ) {
                $this->status = $attrs->wpgconcert_status;
                $need_update = true;
            }

            if ( isset( $attrs->wpgconcert_roles ) && $attrs->wpgconcert_roles != $this->roles ) {
                $this->roles = $attrs->wpgconcert_roles;
                $need_update = true;
            }

            if ( isset( $attrs->venue ) && $attrs->venue != $this->venue()->id() ) {
                $this->venue = GiglogAdmin_Venue::get( $attrs->venue );
                $need_update = true;
            }

            if ( $need_update ) {
                $this->save();
            }

            return $need_update;
        }

        /**
         * Build a query with given filters.
         *
         * @param array $filter     Filters to include in the query.
         * @param bool  $count      Only return count of result if true.
         */
        private static function _build_query( array $filter = array(), bool $count = false ) : string {
            global $wpdb;

            $ct = "{$wpdb->prefix}giglogadmin_concerts";
            $vt = "{$wpdb->prefix}giglogadmin_venues";

            if ( $count ) {
                $query = "SELECT count({$ct}.id) ";
            } else {
                $query = "SELECT {$ct}.*, {$vt}.wpgvenue_name, {$vt}.wpgvenue_city ";
            }

            $query .= "FROM {$ct} LEFT JOIN {$vt} ON {$ct}.venue = {$vt}.id WHERE wpgconcert_date >= CURRENT_TIMESTAMP";

            $keymap = array(
                'id' => $wpdb->prefix . 'giglogadmin_concerts.id',
                'name' => 'wpgconcert_name',
                'date' => 'wpgconcert_date',
                'month' => 'MONTH(wpgconcert_date)',
                'venue_id' => $wpdb->prefix . 'giglogadmin_venues.id',
                'venue' => $wpdb->prefix . 'giglogadmin_venues.wpgvenue_name',
                'city' => $wpdb->prefix . 'giglogadmin_venues.wpgvenue_city',
                'currentuser' => 'wpgconcert_roles',
            );

            $where = array();
            $offset = 0;
            $limit = 15;
            $page = null;

            foreach ( $filter as $key => $value ) {
                switch ( $key ) {
                    case 'name':
                    case 'date':
                    case 'month':
                    case 'venue':
                    case 'city':
                        array_push( $where, $keymap[ $key ] . $wpdb->prepare( '=%s', $value ) );
                        break;

                    case 'id':
                    case 'venue_id':
                        array_push( $where, $keymap[ $key ] . $wpdb->prepare( '=%d', $value ) );
                        break;

                    case 'currentuser':
                        array_push( $where, $keymap[ $key ] . $wpdb->prepare( ' like %s', esc_like( $value ) ) );
                        break;

                    case 'page':
                        $page = intval( $value );
                        break;

                    case 'offset':
                        $offset = intval( $value );
                        break;

                    case 'limit':
                        $limit = intval( $value );
                        break;
                }
            }

            if ( ! empty( $where ) ) {
                $query .= ' AND ' . implode( ' and ', $where );
            }

            if ( $page !== null ) {
                $offset = ( $page - 1 ) * $limit;
            }

            $query .= ' ORDER BY wpgconcert_date';
            $query .= " LIMIT {$offset},{$limit}";

            return $query;
        }

        /**
         * Return an array of concert objects optionally limited by a specified
         * filter.
         *
         * Valid filters are:
         *   - 'venue_id' => int : only include concerts at the given venue
         *   - 'city' => string  : only include concerts in the given city
         *
         * @param array<string, mixed> $filter Filter to use for the query.
         * @return array<GiglogAdmin_Concert>
         */
        public static function find_concerts( array $filter = array() ) : array {
            global $wpdb;

            $query = self::_build_query( $filter, false );

            // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
            $results = $wpdb->get_results( $query );

            return array_map( fn( $c ) => new GiglogAdmin_Concert( $c ), $results );
        }

        /**
         * Return the number of objects matching the given filter.
         *
         * @param array<string, mixed> $filter The filter to use for the query.
         * @return int
         */
        public static function count( array $filter = array() ) : int {
            global $wpdb;

            $query = self::_build_query( $filter, true );

            // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
            $count = $wpdb->get_var( $query );

            return $count ? $count : 0;
        }

        /**
         * Return number of pages with the limit of concerts/page
         * specified in the filter.
         *
         * @param array<string, mixed> $filter The filter to use for the query.
         * @return number of pages.
         */
        public static function count_pages( array $filter = array() ) : int {
            if ( ! isset( $filter['limit'] ) ) {
                $filter['limit'] = 15;
            }

            $num_concerts = self::count( $filter );
            return ( intval( $num_concerts / $filter['limit'] ) ) + 1;
        }

        /**
         * Save concert to database.
         */
        public function save() : void {
            global $wpdb;

            $columns = array(
                'wpgconcert_name' => $this->cname,
                'venue' => $this->venue->id(),
                'wpgconcert_date' => $this->cdate->format( 'c' ),
                'wpgconcert_tickets' => $this->tickets,
                'wpgconcert_event' => $this->eventlink,
                'wpgconcert_status' => $this->status,
                'wpgconcert_roles' => wp_json_encode( $this->roles ),
            );

            if ( null !== $this->id ) {
                $res = $wpdb->update( $wpdb->prefix . 'giglogadmin_concerts', $columns, array( 'id' => $this->id ) );
            } else {
                $res = $wpdb->insert( $wpdb->prefix . 'giglogadmin_concerts', $columns );
            }

            if ( false === $res ) {
                $wpdb->print_error( __METHOD__ );
            } elseif ( null === $this->id ) {
                $this->id = $wpdb->insert_id;
            }
        }

        /**
         * Return database id for concert.
         */
        public function id() : int {
             return $this->id ? $this->id : 0;
        }

        /**
         * Return the concert "name".
         */
        public function cname() : string {
            return $this->cname ? $this->cname : '';
        }

        /**
         * Return the concert venue.
         */
        public function venue() {
             return $this->venue;
        }

        /**
         * Return the date of the concert.
         */
        public function cdate() : DateTimeImmutable {
             return $this->cdate;
        }

        /**
         * Return the ticket url for the concert.
         */
        public function tickets() {
             return $this->tickets ? $this->tickets : '';
        }

        /**
         * Return the event link for the concert.
         */
        public function eventlink() {
             return $this->eventlink ? $this->eventlink : '';
        }

        /**
         * Return the status of the concert.
         */
        public function status() : int {
             return $this->status;
        }

        /**
         * Set the status of the concert.
         *
         * @param int $new_status   The new status for the concert.
         */
        public function set_status( int $new_status ) {
             $this->status = $new_status;
        }

        /**
         * Return the roles defined for this concert.
         *
         * @return array<string, string>
         */
        public function roles() : array {
            return $this->roles ? $this->roles : array();
        }

        /**
         * Assign a role for the concert to the given user.
         *
         * @param string $role  The role to assign.
         * @param string $username  The user to assign the role to.
         */
        public function assign_role( string $role, string $username ) : void {
            $this->roles[ $role ] = $username;
        }

        /**
         * Unassign any roles for this concert for the given user.
         *
         * @param string $username  The user to remove from the roles.
         */
        public function remove_user_from_roles( string $username ) : void {
            $this->roles = array_filter( $this->roles, fn( $u) => $u != $username );
        }

        /**
         * Return creation time of the concert object.
         */
        public function created() : DateTimeImmutable {
            return $this->created;
        }

        /**
         * Return time of last update to this concert object.
         */
        public function updated() : DateTimeImmutable {
            return $this->updated;
        }
    }
}