Code Coverage |
||||||||||
Lines |
Functions and Methods |
Classes and Traits |
||||||||
Total | |
0.00% |
0 / 57 |
|
0.00% |
0 / 4 |
CRAP | |
0.00% |
0 / 1 |
Importer | |
0.00% |
0 / 57 |
|
0.00% |
0 / 4 |
506 | |
0.00% |
0 / 1 |
__construct | |
0.00% |
0 / 1 |
|
0.00% |
0 / 1 |
2 | |||
save | |
0.00% |
0 / 5 |
|
0.00% |
0 / 1 |
6 | |||
generateXML | |
0.00% |
0 / 22 |
|
0.00% |
0 / 1 |
42 | |||
initProcessor | |
0.00% |
0 / 29 |
|
0.00% |
0 / 1 |
182 |
1 | <?php |
2 | |
3 | /** |
4 | * VuFind XSLT importer |
5 | * |
6 | * PHP version 8 |
7 | * |
8 | * Copyright (C) Villanova University 2010. |
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 XSLT |
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/ Wiki |
28 | */ |
29 | |
30 | namespace VuFind\XSLT; |
31 | |
32 | use DOMDocument; |
33 | use Laminas\ServiceManager\ServiceLocatorInterface; |
34 | use VuFindSearch\Backend\Solr\Document\RawXMLDocument; |
35 | use XSLTProcessor; |
36 | |
37 | use function is_array; |
38 | |
39 | /** |
40 | * VuFind XSLT importer |
41 | * |
42 | * @category VuFind |
43 | * @package XSLT |
44 | * @author Demian Katz <demian.katz@villanova.edu> |
45 | * @license http://opensource.org/licenses/gpl-2.0.php GNU General Public License |
46 | * @link https://vufind.org/wiki/ Wiki |
47 | */ |
48 | class Importer |
49 | { |
50 | /** |
51 | * Service locator |
52 | * |
53 | * @var ServiceLocatorInterface |
54 | */ |
55 | protected $serviceLocator; |
56 | |
57 | /** |
58 | * Constructor |
59 | * |
60 | * @param ServiceLocatorInterface $sm Service manager |
61 | */ |
62 | public function __construct(ServiceLocatorInterface $sm) |
63 | { |
64 | $this->serviceLocator = $sm; |
65 | } |
66 | |
67 | /** |
68 | * Save an XML file to the Solr index using the specified configuration. |
69 | * |
70 | * @param string $xmlFile XML file to transform. |
71 | * @param string $properties Properties file. |
72 | * @param string $index Solr index to use. |
73 | * @param bool $testMode Are we in test-only mode? |
74 | * |
75 | * @throws \Exception |
76 | * @return string Transformed XML |
77 | */ |
78 | public function save( |
79 | $xmlFile, |
80 | $properties, |
81 | $index = 'Solr', |
82 | $testMode = false |
83 | ) { |
84 | // Process the file: |
85 | $xml = $this->generateXML($xmlFile, $properties); |
86 | |
87 | // Save the results (or just display them, if in test mode): |
88 | if (!$testMode) { |
89 | $solr = $this->serviceLocator->get(\VuFind\Solr\Writer::class); |
90 | $solr->save($index, new RawXMLDocument($xml)); |
91 | } |
92 | return $xml; |
93 | } |
94 | |
95 | /** |
96 | * Transform $xmlFile using the provided $properties configuration. |
97 | * |
98 | * @param string $xmlFile XML file to transform. |
99 | * @param string $properties Properties file. |
100 | * |
101 | * @throws \Exception |
102 | * @return mixed Transformed XML. |
103 | */ |
104 | protected function generateXML($xmlFile, $properties) |
105 | { |
106 | // Load properties file: |
107 | $resolver = $this->serviceLocator->get(\VuFind\Config\PathResolver::class); |
108 | $properties = $resolver->getConfigPath($properties, 'import'); |
109 | if (!file_exists($properties)) { |
110 | throw new \Exception("Cannot load properties file: {$properties}."); |
111 | } |
112 | $options = parse_ini_file($properties, true); |
113 | |
114 | // Make sure required parameter is set: |
115 | if (!($filename = $options['General']['xslt'] ?? '')) { |
116 | throw new \Exception( |
117 | "Properties file ({$properties}) is missing General/xslt setting." |
118 | ); |
119 | } |
120 | $xslFile = $resolver->getConfigPath($filename, 'import/xsl'); |
121 | |
122 | // Initialize the XSL processor: |
123 | $xsl = $this->initProcessor($options); |
124 | |
125 | // Load up the style sheet |
126 | $style = new DOMDocument(); |
127 | if (!$style->load($xslFile)) { |
128 | throw new \Exception("Problem loading XSL file: {$xslFile}."); |
129 | } |
130 | $xsl->importStyleSheet($style); |
131 | |
132 | // Load up the XML document |
133 | $xml = new DOMDocument(); |
134 | if (!$xml->load($xmlFile)) { |
135 | throw new \Exception("Problem loading XML file: {$xmlFile}."); |
136 | } |
137 | |
138 | // Process and return the XML through the style sheet |
139 | $result = $xsl->transformToXML($xml); |
140 | if (!$result) { |
141 | throw new \Exception('Problem transforming XML.'); |
142 | } |
143 | return $result; |
144 | } |
145 | |
146 | /** |
147 | * Initialize an XSLT processor using settings from the user-specified properties |
148 | * file. |
149 | * |
150 | * @param array $options Parsed contents of properties file. |
151 | * |
152 | * @throws \Exception |
153 | * @return object XSLT processor. |
154 | */ |
155 | protected function initProcessor($options) |
156 | { |
157 | // Prepare an XSLT processor and pass it some variables |
158 | $xsl = new XSLTProcessor(); |
159 | |
160 | // Register PHP functions, if specified: |
161 | if (isset($options['General']['php_function'])) { |
162 | $functions = is_array($options['General']['php_function']) |
163 | ? $options['General']['php_function'] |
164 | : [$options['General']['php_function']]; |
165 | foreach ($functions as $function) { |
166 | $xsl->registerPHPFunctions($function); |
167 | } |
168 | } |
169 | |
170 | // Register custom classes, if specified: |
171 | if (isset($options['General']['custom_class'])) { |
172 | $classes = is_array($options['General']['custom_class']) |
173 | ? $options['General']['custom_class'] |
174 | : [$options['General']['custom_class']]; |
175 | $truncate = $options['General']['truncate_custom_class'] ?? true; |
176 | foreach ($classes as $class) { |
177 | // Add a default namespace if none was provided: |
178 | if (!str_contains($class, '\\')) { |
179 | $class = 'VuFind\XSLT\Import\\' . $class; |
180 | } |
181 | // If necessary, dynamically generate the truncated version of the |
182 | // requested class: |
183 | if ($truncate) { |
184 | $parts = explode('\\', $class); |
185 | $class = preg_replace('/[^A-Za-z0-9_]/', '', array_pop($parts)); |
186 | $ns = implode('\\', $parts); |
187 | if (!class_exists($class)) { |
188 | class_alias("$ns\\$class", $class); |
189 | } |
190 | } |
191 | $methods = get_class_methods($class); |
192 | if (method_exists($class, 'setServiceLocator')) { |
193 | $class::setServiceLocator($this->serviceLocator); |
194 | } |
195 | foreach ($methods as $method) { |
196 | $xsl->registerPHPFunctions($class . '::' . $method); |
197 | } |
198 | } |
199 | } |
200 | |
201 | // Load parameters, if provided: |
202 | if (isset($options['Parameters'])) { |
203 | $xsl->setParameter('', $options['Parameters']); |
204 | } |
205 | |
206 | return $xsl; |
207 | } |
208 | } |