1<?php
2/*
3 * vim:set softtabstop=4 shiftwidth=4 expandtab:
4 *
5 * LICENSE: GNU Affero General Public License, version 3 (AGPL-3.0-or-later)
6 * Copyright 2001 - 2020 Ampache.org
7 *
8 * This program is free software: you can redistribute it and/or modify
9 * it under the terms of the GNU Affero General Public License as published by
10 * the Free Software Foundation, either version 3 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 * GNU Affero General Public License for more details.
17 *
18 * You should have received a copy of the GNU Affero General Public License
19 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
20 *
21 */
22
23declare(strict_types=0);
24
25namespace Ampache\Repository\Model;
26
27use Ampache\Config\AmpConfig;
28use Ampache\Module\System\Dba;
29
30/**
31 * This is a general object that is extended by all of the basic
32 * database based objects in ampache. It attempts to do some standard
33 * caching for all of the objects to cut down on the database calls
34 */
35abstract class database_object
36{
37    protected const DB_TABLENAME = null;
38
39    private static $object_cache = array();
40
41    // Statistics for debugging
42    public static $cache_hit       = 0;
43    private static ?bool $_enabled = null;
44
45    /**
46     * get_info
47     * retrieves the info from the database and puts it in the cache
48     * @param integer $object_id
49     * @param string $table_name
50     * @return array
51     */
52    public function get_info($object_id, $table_name = '')
53    {
54        $table     = $this->getTableName($table_name);
55        $object_id = (int)$object_id;
56
57        // Make sure we've got a real id
58        if ($object_id < 1) {
59            return array();
60        }
61
62        if (self::is_cached($table, $object_id)) {
63            return self::get_from_cache($table, $object_id);
64        }
65
66        $params     = array($object_id);
67        $sql        = "SELECT * FROM `$table` WHERE `id`= ?";
68        $db_results = Dba::read($sql, $params);
69
70        if (!$db_results) {
71            return array();
72        }
73
74        $row = Dba::fetch_assoc($db_results);
75
76        self::add_to_cache($table, $object_id, $row);
77
78        return $row;
79    } // get_info
80
81    /**
82     * getTableName
83     * @param $table_name
84     * @return string
85     */
86    private function getTableName($table_name): string
87    {
88        if (!$table_name) {
89            $table_name = static::DB_TABLENAME;
90
91            if ($table_name === null) {
92                $table_name = Dba::escape(strtolower(get_class($this)));
93            }
94        }
95
96        return Dba::escape($table_name);
97    }
98
99    /**
100     * clear_cache
101     */
102    public static function clear_cache()
103    {
104        self::$object_cache = array();
105    }
106
107    /**
108     * is_cached
109     * this checks the cache to see if the specified object is there
110     * @param string $index
111     * @param string $object_id
112     * @return boolean
113     */
114    public static function is_cached($index, $object_id)
115    {
116        // Make sure we've got some parents here before we dive below
117        if (!isset(self::$object_cache[$index])) {
118            return false;
119        }
120
121        return isset(self::$object_cache[$index][$object_id]);
122    } // is_cached
123
124    /**
125     * get_from_cache
126     * This attempts to retrieve the specified object from the cache we've got here
127     * @param string $index
128     * @param integer|string $object_id
129     * @return array
130     */
131    public static function get_from_cache($index, $object_id)
132    {
133        // Check if the object is set
134        if (isset(self::$object_cache[$index]) && isset(self::$object_cache[$index][$object_id])) {
135            self::$cache_hit++;
136
137            return self::$object_cache[$index][$object_id];
138        }
139
140        return array();
141    } // get_from_cache
142
143    /**
144     * add_to_cache
145     * This adds the specified object to the specified index in the cache
146     * @param string $index
147     * @param integer|string $object_id
148     * @param array $data
149     * @return boolean
150     */
151    public static function add_to_cache($index, $object_id, $data)
152    {
153        /**
154         * Lazy load the cache setting to avoid some magic auto_init logic
155         */
156        if (self::$_enabled === null) {
157            self::$_enabled = AmpConfig::get('memory_cache');
158        }
159        if (!self::$_enabled) {
160            return false;
161        }
162
163        $value = false;
164        if (!empty($data)) {
165            $value = $data;
166        }
167
168        self::$object_cache[$index][$object_id] = $value;
169
170        return true;
171    } // add_to_cache
172
173    /**
174     * remove_from_cache
175     * This function clears something from the cache, there are a few places we need to do this
176     * in order to have things display correctly
177     * @param string $index
178     * @param integer $object_id
179     */
180    public static function remove_from_cache($index, $object_id)
181    {
182        if (isset(self::$object_cache[$index]) && isset(self::$object_cache[$index][$object_id])) {
183            unset(self::$object_cache[$index][$object_id]);
184        }
185    } // remove_from_cache
186}
187