Jake Vanderwerf
23 hours ago f4be611c51473359e6d41780f0313c446079e9d3
inc/managers/FavouritesManager.php
@@ -1,6 +1,7 @@
<?php
namespace JVBase\managers;
use Exception;
use JVBase\registrar\Registrar;
if (!defined('ABSPATH')) {
@@ -18,8 +19,16 @@
   public function __construct()
   {
      $this->defineTables();
      $this->registerHooks();
   }
   protected function registerHooks():void
   {
      add_action('before_delete_post', [$this, 'cleanupPostFavourites']);
      add_action('delete_term', [$this, 'cleanupTermFavourites'], 10, 3);
      add_action('jvbUserRegistered', [$this, 'maybeAcceptListInvite'], 10, 3);
      add_action('jvb_cleanupOrphanedFavourites', [$this, 'cleanupOrphanedFavourites']);
   }
   protected function defineTables():void
   {
      $this->defineFavouriteTable();
@@ -126,6 +135,7 @@
            'list_id'      => 'bigint(20) unsigned NOT NULL',
            'user_id'      => "{$table->getUserIDType()} NOT NULL",
            'email'        => 'varchar(255) NOT NULL',
            'invite_token' => 'varchar(255) NOT NULL',
            'permission'   => "ENUM('view', 'edit') NOT NULL DEFAULT 'view'",
            'status'    => "ENUM('pending', 'accepted', 'rejected', 'revoked') NOT NULL DEFAULT 'pending'",
            'created_at'   => 'datetime NOT NULL DEFAULT CURRENT_TIMESTAMP',
@@ -372,6 +382,7 @@
         } elseif ($newUser) {
            $email = sanitize_email($newUser['email']);
            $name = sanitize_text_field($newUser['name']);
            $args['invite_token'] = wp_generate_password(32, false);
            $args['email'] = $email;
            //TODO: Magic Link setup
         }
@@ -570,6 +581,59 @@
               'shared_users' => $sharedWith
            ];
         }
   public function getFavouriteCounts(int $user_id): array
   {
      $results = $this->favourites->queryResults(
         "SELECT type, COUNT(*) as count FROM {table} WHERE user_id = %d GROUP BY type",
         [$user_id]
      );
      $counts = [];
      foreach ($results as $row) {
         $type = str_replace(BASE, '', $row->type);
         $counts[$type] = (int) $row->count;
      }
      $defaults = array_fill_keys(
         array_map(fn($t) => str_replace(BASE, '', $t), Registrar::withFeature('favouritable')),
         0
      );
      return array_merge($defaults, $counts);
   }
   public function cleanupOrphanedFavourites(): bool
   {
      global $wpdb;
      // Posts - no FK possible since target_id is generic
      $this->favourites->query(
         "DELETE f FROM {table} f
         LEFT JOIN {$wpdb->posts} p ON f.target_id = p.ID
         WHERE f.type IN (
             SELECT CONCAT('" . BASE . "', post_type)
             FROM {$wpdb->posts} GROUP BY post_type
         )
         AND p.ID IS NULL"
      );
      // Terms - same reason
      $this->favourites->query(
         "DELETE f FROM {table} f
         LEFT JOIN {$wpdb->term_taxonomy} tt ON f.target_id = tt.term_id
         AND f.type = CONCAT('" . BASE . "', tt.taxonomy)
         WHERE tt.term_id IS NULL
         AND f.type != CONCAT('" . BASE . "', 'user')"
      );
      $this->listItems->query(
         "DELETE li FROM {table} li
         LEFT JOIN {$wpdb->posts} p ON li.target_id = p.ID
         LEFT JOIN {$wpdb->term_taxonomy} tt ON li.target_id = tt.term_id
         WHERE p.ID IS NULL AND tt.term_id IS NULL"
      );
      return true;
   }
   /***************************************************************
    * UTILITY METHODS
    **************************************************************/
@@ -682,4 +746,50 @@
      unset($notes[$index]);
      return array_values($notes); //reindexed array
   }
   public function cleanupPostFavourites(int $post_id):void
   {
      try {
         $type = get_post_type($post_id);
         if (!$type) return;
         $this->favourites->where([
            'type'   => $type,
            'target_id' => $post_id
         ])->deleteResults();
         $this->listItems->where([
            'item_type' => $type,
            'item_id'   => $post_id
         ])->deleteResults();
      } catch (Exception $e) {
         JVB()->error()->log('cleanupPostFavourites', $e->getMessage(), [
            'post_id' => $post_id
         ]);
      }
   }
   public function cleanupTermFavourites(int $term_id, int $tt_id, string $taxonomy):void
   {
      try {
         $registrar = Registrar::getInstance($taxonomy);
         if (!$registrar || !$registrar->hasFeature('favouritable')) {
            return;
         }
         $this->favourites->where([
            'type'   => $taxonomy,
            'target_id' => $term_id,
         ])->deleteResults();
         $this->listItems->where([
            'item_type' => $taxonomy,
            'item_id'   => $term_id
         ])->deleteResults();
      } catch (Exception $e) {
         JVB()->error()->log('cleanupTermFavourites', $e->getMessage(), [
            'term_id' => $term_id,
            'taxonomy'=> $taxonomy
         ]);
      }
   }
}