<?php
// 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
require_once __DIR__ . '/venue.php';
if ( ! class_exists( 'GiglogAdmin_DuplicateConcertException' ) ) {
class GiglogAdmin_DuplicateConcertException extends Exception {
}
}
if ( ! class_exists( 'GiglogAdmin_Concert' ) ) {
require_once __DIR__ . '/venue.php';
class GiglogAdmin_Concert {
private ?int $id;
private ?string $cname;
private ?GiglogAdmin_Venue $venue;
private ?string $cdate;
private ?string $tickets;
private ?string $eventlink;
private ?int $status;
private array $roles;
private ?DateTimeImmutable $created;
private ?DateTimeImmutable $updated;
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.
*/
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 = isset( $attrs->wpgconcert_date ) ? $attrs->wpgconcert_date : null;
$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
* @return null|self
*/
static function get( int $id ) : ?self {
return self::find_concerts( array( 'id' => $id ) )[0];
}
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 $concert;
}
}
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 = $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;
}
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();
$lmt = array();
foreach ( $filter as $key => $value ) {
switch ( $key ) {
case 'name':
case 'date':
case 'month':
case 'venue':
case 'city':
array_push( $where, $wpdb->prepare( $keymap[ $key ] . '=%s', $value ) );
break;
case 'id':
case 'venue_id':
array_push( $where, $wpdb->prepare( $keymap[ $key ] . '=%d', $value ) );
break;
case 'currentuser':
array_push( $where, $wpdb->prepare( $keymap[ $key ] . ' like "%%%s%%"', $value ) );
break;
case 'offset':
array_push( $lmt, $value );
break;
case 'recperpage':
array_push( $lmt, $value );
break;
}
}
if ( ! empty( $where ) ) {
$query .= ' AND ' . implode( ' and ', $where );
}
$query .= ' ORDER BY wpgconcert_date';
if ( ! empty( $lmt ) ) {
$query .= ' LIMIT ' . implode( ', ', $lmt );
}
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
* @return array<GiglogAdmin_Concert>
*/
public static function find_concerts( array $filter = array() ) : array {
global $wpdb;
$query = self::_build_query( $filter, false );
$results = $wpdb->get_results( $query );
return array_map(
function( $c ) {
return new GiglogAdmin_Concert( $c );
},
$results
);
}
/**
* Return the number of objects matching the given filter.
*
* @param array<string, mixed> $filter
* @return int
*/
public static function count( array $filter = array() ) : int {
global $wpdb;
$query = self::_build_query( $filter, true );
$count = $wpdb->get_var( $query );
return $count ? $count : 0;
}
public function save() : void {
global $wpdb;
$columns = array(
'wpgconcert_name' => $this->cname,
'venue' => $this->venue->id(),
'wpgconcert_date' => $this->cdate,
'wpgconcert_tickets' => $this->tickets,
'wpgconcert_event' => $this->eventlink,
'wpgconcert_status' => $this->status,
'wpgconcert_roles' => wp_json_encode( $this->roles ),
);
if ( $this->id !== null ) {
$res = $wpdb->update( $wpdb->prefix . 'giglogadmin_concerts', $columns, array( 'id' => $this->id ) );
} else {
$res = $wpdb->insert( $wpdb->prefix . 'giglogadmin_concerts', $columns );
}
if ( $res === false ) {
$wpdb->print_error( __METHOD__ );
} elseif ( $this->id === null ) {
$this->id = $wpdb->insert_id;
}
}
public function id() {
return $this->id;
}
public function cname() {
return $this->cname;
}
public function venue() {
return $this->venue;
}
public function cdate() {
return $this->cdate;
}
public function tickets() {
return $this->tickets;
}
public function eventlink() {
return $this->eventlink;
}
public function status() {
return $this->status;
}
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;
}
public function assign_role( string $role, string $username ) : void {
$this->roles[ $role ] = $username;
}
public function remove_user_from_roles( string $username ) : void {
$this->roles = array_filter( $this->roles, fn( $u) => $u != $username );
}
public function created() : DateTimeImmutable {
return $this->created;
}
public function updated() : DateTimeImmutable {
return $this->updated;
}
}
}