From ad7167b979342bdb5d8be64c4f86f83c42ef508d Mon Sep 17 00:00:00 2001
From: Demian Katz <demian.katz@villanova.edu>
Date: Tue, 17 Jul 2012 14:59:02 -0400
Subject: [PATCH] Added tag filtering to favorites.

---
 module/VuFind/src/VuFind/Db/Table/Gateway.php |  13 +-
 .../VuFind/src/VuFind/Db/Table/Resource.php   |  23 +-
 .../src/VuFind/Db/Table/ResourceTags.php      | 247 ++++++++++++++++++
 3 files changed, 265 insertions(+), 18 deletions(-)
 create mode 100644 module/VuFind/src/VuFind/Db/Table/ResourceTags.php

diff --git a/module/VuFind/src/VuFind/Db/Table/Gateway.php b/module/VuFind/src/VuFind/Db/Table/Gateway.php
index 57797f482de..6625cbe199b 100644
--- a/module/VuFind/src/VuFind/Db/Table/Gateway.php
+++ b/module/VuFind/src/VuFind/Db/Table/Gateway.php
@@ -45,16 +45,19 @@ class Gateway extends AbstractTableGateway
      * Constructor
      *
      * @param string $table    Name of database table to interface with
-     * @param string $rowClass Name of class used to represent rows
+     * @param string $rowClass Name of class used to represent rows (null for
+     * default)
      */
-    public function __construct($table, $rowClass)
+    public function __construct($table, $rowClass = null)
     {
         $this->table = $table;
         $this->featureSet = new FeatureSet();
         $this->featureSet->addFeature(new GlobalAdapterFeature());
         $this->initialize();
-        $resultSetPrototype = $this->getResultSetPrototype();
-        $resultSetPrototype
-            ->setArrayObjectPrototype(new $rowClass($this->getAdapter()));
+        if (!is_null($rowClass)) {
+            $resultSetPrototype = $this->getResultSetPrototype();
+            $resultSetPrototype
+                ->setArrayObjectPrototype(new $rowClass($this->getAdapter()));
+        }
     }
 }
diff --git a/module/VuFind/src/VuFind/Db/Table/Resource.php b/module/VuFind/src/VuFind/Db/Table/Resource.php
index f525025388f..02ba8d6a898 100644
--- a/module/VuFind/src/VuFind/Db/Table/Resource.php
+++ b/module/VuFind/src/VuFind/Db/Table/Resource.php
@@ -167,21 +167,18 @@ class Resource extends Gateway
 
             // Adjust for tags if necessary:
             if (!empty($tags)) {
-                /* TODO:
+                $linkingTable = new ResourceTags();
                 foreach ($tags as $tag) {
-                    $subSelect = $this->select();
-                    $subSelect->setIntegrityCheck(false)
-                        ->distinct()
-                        ->from(array('rt' => 'resource_tags'), 'rt.resource_id')
-                        ->join(array('t' => 'tags'), 'rt.tag_id = t.id', array())
-                        ->where('t.tag = ?', $tag)
-                        ->where('rt.user_id = ?', $userId);
-                    if (!is_null($listId)) {
-                        $subSelect->where('rt.list_id = ?', $listId);
-                    }
-                    $select->where('r.id in ?', $subSelect);
+                    $matches
+                        = $linkingTable->getResourcesForTag($tag, $userId, $listId);
+                    $select->where->in(
+                        'resource.id',
+                        array_map(
+                            function ($i) { return $i['resource_id']; },
+                            $matches->toArray()
+                        )
+                    );
                 }
-                 */
             }
 
             // Apply sorting, if necessary:
diff --git a/module/VuFind/src/VuFind/Db/Table/ResourceTags.php b/module/VuFind/src/VuFind/Db/Table/ResourceTags.php
new file mode 100644
index 00000000000..c61897b65ad
--- /dev/null
+++ b/module/VuFind/src/VuFind/Db/Table/ResourceTags.php
@@ -0,0 +1,247 @@
+<?php
+/**
+ * Table Definition for resource_tags
+ *
+ * PHP version 5
+ *
+ * Copyright (C) Villanova University 2010.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2,
+ * as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ * @category VuFind2
+ * @package  DB_Models
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org   Main Site
+ */
+namespace VuFind\Db\Table;
+use Zend\Db\Sql\Expression;
+
+/**
+ * Table Definition for resource_tags
+ *
+ * @category VuFind2
+ * @package  DB_Models
+ * @author   Demian Katz <demian.katz@villanova.edu>
+ * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
+ * @link     http://vufind.org   Main Site
+ */
+class ResourceTags extends Gateway
+{
+    /**
+     * Constructor
+     */
+    public function __construct()
+    {
+        parent::__construct('resource_tags', 'VuFind\Db\Row\Resource');
+    }
+
+    /**
+     * Look up a row for the specified resource.
+     *
+     * @param string $resource_id ID of resource to link up
+     * @param string $tag_id      ID of tag to link up
+     * @param string $user_id     ID of user creating link (optional but recommended)
+     * @param string $list_id     ID of list to link up (optional)
+     *
+     * @return void
+     */
+    public function createLink($resource_id, $tag_id, $user_id = null,
+        $list_id = null
+    ) {
+        /* TODO
+        $select = $this->select();
+        $select->where('resource_id = ?', $resource_id)
+            ->where('tag_id = ?', $tag_id);
+        if (!is_null($list_id)) {
+            $select->where('list_id = ?', $list_id);
+        } else {
+            $select->where('list_id is null');
+        }
+        if (!is_null($user_id)) {
+            $select->where('user_id = ?', $user_id);
+        } else {
+            $select->where('user_id is null');
+        }
+        $result = $this->fetchRow($select);
+
+        // Only create row if it does not already exist:
+        if (is_null($result)) {
+            $result = $this->createRow();
+            $result->resource_id = $resource_id;
+            $result->tag_id = $tag_id;
+            if (!is_null($list_id)) {
+                $result->list_id = $list_id;
+            }
+            if (!is_null($user_id)) {
+                $result->user_id = $user_id;
+            }
+            $result->save();
+        }
+         */
+    }
+
+    /**
+     * Check whether or not the specified tags are present in the table.
+     *
+     * @param array $ids IDs to check.
+     *
+     * @return array     Associative array with two keys: present and missing
+     */
+    public function checkForTags($ids)
+    {
+        /* TODO
+        // Set up return arrays:
+        $retVal = array('present' => array(), 'missing' => array());
+
+        // Look up IDs in the table:
+        $select = $this->select()->distinct()->from($this->_name, 'tag_id');
+        foreach ($ids as $current) {
+            $select->orWhere('tag_id = ?', $current);
+        }
+        $results = $this->fetchAll($select);
+
+        // Record all IDs that are present:
+        foreach ($results as $current) {
+            $retVal['present'][] = $current->tag_id;
+        }
+
+        // Detect missing IDs:
+        foreach ($ids as $current) {
+            if (!in_array($current, $retVal['present'])) {
+                $retVal['missing'][] = $current;
+            }
+        }
+
+        // Send back the results:
+        return $retVal;
+         */
+    }
+
+    /**
+     * Get resources associated with a particular tag.
+     *
+     * @param string $tag    Tag to match
+     * @param string $userId ID of user owning favorite list
+     * @param string $listId ID of list to retrieve (null for all favorites)
+     *
+     * @return Zend_Db_Table_Rowset
+     */
+    public function getResourcesForTag($tag, $userId, $listId = null)
+    {
+        $callback = function ($select) use ($tag, $userId, $listId) {
+            $select->columns(
+                array(
+                    'resource_id' => new Expression(
+                        'DISTINCT(?)', array('resource_tags.resource_id'),
+                        array(Expression::TYPE_IDENTIFIER)
+                    )
+                )
+            );
+            $select->join(
+                array('t' => 'tags'), 'resource_tags.tag_id = t.id', array()
+            );
+            $select->where->equalTo('t.tag', $tag)
+                ->where->equalTo('resource_tags.user_id', $userId);
+            if (!is_null($listId)) {
+                $select->where->equalTo('resource_tags.list_id', $listId);
+            }
+        };
+
+        return $this->select($callback);
+    }
+
+    /**
+     * Unlink rows for the specified resource.
+     *
+     * @param string|array $resource_id ID (or array of IDs) of resource(s) to
+     *                                  unlink (null for ALL matching resources)
+     * @param string       $user_id     ID of user removing links
+     * @param string       $list_id     ID of list to unlink (null for ALL matching
+     *                                  lists, 'none' for tags not in a list)
+     * @param string       $tag_id      ID of tag to unlink (null for ALL matching
+     *                                  tags)
+     *
+     * @return void
+     */
+    public function destroyLinks($resource_id, $user_id, $list_id = null,
+        $tag_id = null
+    ) {
+        /* TODO
+        $db = $this->getAdapter();
+
+        $where = $db->quoteInto('user_id = ?', $user_id);
+
+        if (!is_null($resource_id)) {
+            if (is_array($resource_id)) {
+                $resourceSQL = array();
+                foreach ($resource_id as $current) {
+                    $resourceSQL[] = $db->quoteInto('resource_id = ?', $current);
+                }
+                $where .= ' AND (' . implode(' OR ', $resourceSQL) . ')';
+            } else {
+                $where .= $db->quoteInto(' AND resource_id = ?', $resource_id);
+            }
+        }
+        if (!is_null($list_id)) {
+            if ($list_id != 'none') {
+                $where .= $db->quoteInto(' AND list_id = ?', $list_id);
+            } else {
+                // special case -- if $list_id is set to the string "none", we
+                // want to delete tags that are not associated with lists.
+                $where .= ' AND list_id is null';
+            }
+        }
+        if (!is_null($tag_id)) {
+            $where .= $db->quoteInto(' AND tag_id = ?', $tag_id);
+        }
+
+        // Get a list of all tag IDs being deleted; we'll use these for
+        // orphan-checking:
+        $select = $this->select()->distinct()->from($this->_name, 'tag_id')
+            ->where($where);
+        $potentialOrphans = $this->fetchAll($select);
+
+        // Now delete the unwanted rows:
+        $this->delete($where);
+
+        // Check for orphans:
+        if (count($potentialOrphans) > 0) {
+            $ids = array();
+            foreach ($potentialOrphans as $current) {
+                $ids[] = $current->tag_id;
+            }
+            $checkResults = $this->checkForTags($ids);
+            if (count($checkResults['missing']) > 0) {
+                $tagTable = new VuFind_Model_Db_Tags();
+                $tagTable->deleteByIdArray($checkResults['missing']);
+            }
+        }
+         */
+    }
+
+    /**
+     * Assign anonymous tags to the specified user ID.
+     *
+     * @param int $id User ID to own anonymous tags.
+     *
+     * @return void
+     */
+    public function assignAnonymousTags($id)
+    {
+        /* TODO
+        $this->update(array('user_id' => $id), 'user_id IS NULL');
+         */
+    }
+}
-- 
GitLab