Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
85.11% covered (warning)
85.11%
40 / 47
50.00% covered (danger)
50.00%
5 / 10
CRAP
0.00% covered (danger)
0.00%
0 / 1
TabManager
85.11% covered (warning)
85.11%
40 / 47
50.00% covered (danger)
50.00%
5 / 10
27.06
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
4 / 4
100.00% covered (success)
100.00%
1 / 1
1
 setContext
75.00% covered (warning)
75.00%
3 / 4
0.00% covered (danger)
0.00%
0 / 1
2.06
 initializeCurrentContext
87.50% covered (warning)
87.50%
7 / 8
0.00% covered (danger)
0.00%
0 / 1
2.01
 getConfigByClass
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
2
 getTabServiceNames
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getBackgroundTabNames
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 getExtraScripts
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 getDefaultTabForRecord
85.71% covered (warning)
85.71%
6 / 7
0.00% covered (danger)
0.00%
0 / 1
7.14
 getTabDetailsForRecord
100.00% covered (success)
100.00%
3 / 3
100.00% covered (success)
100.00%
1 / 1
1
 getTabsForRecord
76.92% covered (warning)
76.92%
10 / 13
0.00% covered (danger)
0.00%
0 / 1
7.60
1<?php
2
3/**
4 * Record tab manager
5 *
6 * PHP version 8
7 *
8 * Copyright (C) Villanova University 2019.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License version 2,
12 * as published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
22 *
23 * @category VuFind
24 * @package  RecordTabs
25 * @author   Demian Katz <demian.katz@villanova.edu>
26 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
27 * @link     https://vufind.org/wiki/development:plugins:record_tabs Wiki
28 */
29
30namespace VuFind\RecordTab;
31
32use VuFind\Config\PluginManager as ConfigManager;
33use VuFind\RecordDriver\AbstractBase as AbstractRecordDriver;
34
35use function in_array;
36
37/**
38 * Record tab manager
39 *
40 * @category VuFind
41 * @package  RecordTabs
42 * @author   Demian Katz <demian.katz@villanova.edu>
43 * @license  http://opensource.org/licenses/gpl-2.0.php GNU General Public License
44 * @link     https://vufind.org/wiki/development:plugins:record_tabs Wiki
45 */
46class TabManager
47{
48    /**
49     * Settings for different tab contexts.
50     *
51     * @var array
52     */
53    protected $contextSettings = [
54        'record' => [
55            'configFile' => 'RecordTabs',
56            'legacyConfigSection' => 'recorddriver_tabs',
57        ],
58        'collection' => [
59            'configFile' => 'CollectionTabs',
60            'legacyConfigSection' => 'recorddriver_collection_tabs',
61        ],
62    ];
63
64    /**
65     * Tab configurations
66     *
67     * @var array
68     */
69    protected $config = [];
70
71    /**
72     * Configuration plugin manager
73     *
74     * @var ConfigManager
75     */
76    protected $configManager;
77
78    /**
79     * RecordTab plugin manager
80     *
81     * @var PluginManager
82     */
83    protected $pluginManager;
84
85    /**
86     * Overall framework configuration (used for fetching configurations "the old
87     * way" -- can eventually be deprecated).
88     *
89     * @var array
90     */
91    protected $legacyConfig;
92
93    /**
94     * Current active context (defaults to 'record')
95     *
96     * @var string
97     */
98    protected $context = 'record';
99
100    /**
101     * Constructor
102     *
103     * @param PluginManager $pm           RecordTab plugin manager
104     * @param ConfigManager $cm           Configuration plugin manager
105     * @param array         $legacyConfig Overall framework configuration (only
106     * used for legacy config loading; optional)
107     */
108    public function __construct(
109        PluginManager $pm,
110        ConfigManager $cm,
111        $legacyConfig = []
112    ) {
113        $this->pluginManager = $pm;
114        $this->configManager = $cm;
115        $this->legacyConfig = $legacyConfig;
116
117        // Initialize default context.
118        $this->initializeCurrentContext();
119    }
120
121    /**
122     * Set and (if necessary) initialize the context.
123     *
124     * @param string $context Context to initialize
125     *
126     * @return void
127     * @throws \Exception
128     */
129    public function setContext($context)
130    {
131        if (!in_array($context, array_keys($this->contextSettings))) {
132            throw new \Exception("Unsupported context: $context");
133        }
134        $this->context = $context;
135        $this->initializeCurrentContext();
136    }
137
138    /**
139     * Initialize the current context (if not already initialized).
140     *
141     * @return void
142     */
143    protected function initializeCurrentContext()
144    {
145        if (!isset($this->config[$this->context])) {
146            $key = $this->contextSettings[$this->context]['legacyConfigSection']
147                ?? 'recorddriver_tabs';
148            $legacyConfig = $this->legacyConfig['vufind'][$key] ?? [];
149            $iniConfig = $this->configManager->get(
150                $this->contextSettings[$this->context]['configFile']
151            )->toArray();
152            $this->config[$this->context] = array_merge($legacyConfig, $iniConfig);
153        }
154    }
155
156    /**
157     * Load the specified key from the configuration array using the best
158     * available match to the class of the provided driver. Return the default
159     * value if no match is found.
160     *
161     * @param AbstractRecordDriver $driver  Record driver
162     * @param string               $setting Key to load from configuration
163     * @param string               $default Default to use if no setting found
164     *
165     * @return mixed
166     */
167    protected function getConfigByClass(
168        AbstractRecordDriver $driver,
169        $setting,
170        $default
171    ) {
172        // Get the current record driver's class name, then start a loop
173        // in case we need to use a parent class' name to find the appropriate
174        // setting.
175        $className = $driver::class;
176        do {
177            if (isset($this->config[$this->context][$className][$setting])) {
178                return $this->config[$this->context][$className][$setting];
179            }
180        } while ($className = get_parent_class($className));
181        // No setting found...
182        return $default;
183    }
184
185    /**
186     * Get an array of service names by looking up the provided record driver in
187     * the provided tab configuration array.
188     *
189     * @param AbstractRecordDriver $driver Record driver
190     *
191     * @return array
192     */
193    protected function getTabServiceNames(AbstractRecordDriver $driver)
194    {
195        return $this->getConfigByClass($driver, 'tabs', []);
196    }
197
198    /**
199     * Get an array of tabs names configured to load via AJAX in the background
200     *
201     * @param AbstractRecordDriver $driver Record driver
202     *
203     * @return array
204     */
205    public function getBackgroundTabNames(AbstractRecordDriver $driver)
206    {
207        return $this->getConfigByClass($driver, 'backgroundLoadedTabs', []);
208    }
209
210    /**
211     * Get an array of extra JS scripts by looking up the provided record driver in
212     * the provided tab configuration array.
213     *
214     * @return array
215     */
216    public function getExtraScripts()
217    {
218        return $this->config[$this->context]['TabScripts'] ?? [];
219    }
220
221    /**
222     * Get a default tab by looking up the provided record driver in the tab
223     * configuration array.
224     *
225     * @param AbstractRecordDriver $driver   Record driver
226     * @param array                $tabs     Details on available tabs (returned
227     * from getTabsForRecord()).
228     * @param string               $fallback Fallback to use if no tab specified
229     * or matched.
230     *
231     * @return string
232     */
233    public function getDefaultTabForRecord(
234        AbstractRecordDriver $driver,
235        array $tabs,
236        $fallback = null
237    ) {
238        // Load default from module configuration:
239        $default = $this->getConfigByClass($driver, 'defaultTab', null);
240
241        // Missing/invalid record driver configuration? Fall back to provided
242        // default:
243        if ((!$default || !isset($tabs[$default])) && isset($tabs[$fallback])) {
244            $default = $fallback;
245        }
246
247        // Is configured tab still invalid? If so, pick first existing tab:
248        if ((!$default || !isset($tabs[$default])) && !empty($tabs)) {
249            $keys = array_keys($tabs);
250            $default = $keys[0];
251        }
252
253        return $default;
254    }
255
256    /**
257     * Convenience method to load tab information, including default, in a
258     * single pass. Returns an associative array with 'tabs' and 'default' keys.
259     *
260     * @param AbstractRecordDriver  $driver   Record driver
261     * @param \Laminas\Http\Request $request  User request (optional)
262     * @param string                $fallback Fallback default tab to use if no
263     * tab specified or matched.
264     *
265     * @return array
266     */
267    public function getTabDetailsForRecord(
268        AbstractRecordDriver $driver,
269        $request = null,
270        $fallback = null
271    ) {
272        $tabs = $this->getTabsForRecord($driver, $request);
273        $default = $this->getDefaultTabForRecord($driver, $tabs, $fallback);
274        return compact('tabs', 'default');
275    }
276
277    /**
278     * Get an array of valid tabs for the provided record driver.
279     *
280     * @param AbstractRecordDriver  $driver  Record driver
281     * @param \Laminas\Http\Request $request User request (optional)
282     *
283     * @return array               service name => tab object
284     */
285    public function getTabsForRecord(
286        AbstractRecordDriver $driver,
287        $request = null
288    ) {
289        $tabs = [];
290        foreach ($this->getTabServiceNames($driver) as $tabKey => $svc) {
291            if (!$this->pluginManager->has($svc)) {
292                continue;
293            }
294            $newTab = $this->pluginManager->get($svc);
295            if (method_exists($newTab, 'setRecordDriver')) {
296                $newTab->setRecordDriver($driver);
297            }
298            if (
299                $request instanceof \Laminas\Http\Request
300                && method_exists($newTab, 'setRequest')
301            ) {
302                $newTab->setRequest($request);
303            }
304            if ($newTab->isActive()) {
305                $tabs[$tabKey] = $newTab;
306            }
307        }
308        return $tabs;
309    }
310}