5 use Drupal\Core\Config\ConfigFactoryInterface;
14 use Contracts\FactoryInterface;
15 use GuzzleHttp\Client as GuzzleClient;
36 private $storageFactory;
41 public function __construct(ConfigFactoryInterface $configService, FactoryInterface $storageFactory) {
42 $this->setConfigService($configService);
43 $this->storageFactory = $storageFactory;
57 if (!is_object($data)) {
58 throw new \Exception(
"data must be an object.");
61 foreach ($this->getPropertyList() as $property_id) {
62 if (isset($data->{$property_id})) {
63 $data->{$property_id} = $this->referenceProperty($property_id, $data->{$property_id});
80 private function referenceProperty(
string $property_id, $data) {
81 if (is_array($data)) {
82 return $this->referenceMultiple($property_id, $data);
86 return $this->referenceSingle($property_id, $data);
101 private function referenceMultiple(
string $property_id, array $values) : array {
103 foreach ($values as $value) {
104 $data = $this->referenceSingle($property_id, $value);
105 if (NULL !== $data) {
123 private function referenceSingle(
string $property_id, $value) {
125 if ($property_id ==
'distribution') {
126 $value = $this->distributionHandling($value);
129 $uuid = $this->checkExistingReference($property_id, $value);
131 $uuid = $this->createPropertyReference($property_id, $value);
139 'Neither found an existing nor could create a new reference for property_id: @property_id with value: @value',
141 '@property_id' => $property_id,
142 '@value' => var_export($value, TRUE),
161 private function distributionHandling($distribution): object {
164 if (is_object($distribution) && isset($distribution->downloadURL)) {
168 $distribution->downloadURL = $this->registerWithResourceMapper(
169 $this->hostify($distribution->downloadURL), $this->getMimeType($distribution));
172 return $distribution;
186 private function registerWithResourceMapper(
string $downloadUrl,
string $mimeType): string {
189 $resource =
new Resource($downloadUrl, $mimeType);
192 if ($this->getFileMapper()->
register($resource)) {
195 $downloadUrl = $resource->getUniqueIdentifier();
198 catch (AlreadyRegistered $e) {
199 $info = json_decode($e->getMessage());
204 if (isset($info[0]->identifier)) {
206 $stored = $this->getFileMapper()->get($info[0]->identifier, Resource::DEFAULT_SOURCE_PERSPECTIVE);
207 $downloadUrl = $this->handleExistingResource($info, $stored, $mimeType);
217 private function handleExistingResource($info, $stored, $mimeType) {
218 if ($info[0]->perspective == Resource::DEFAULT_SOURCE_PERSPECTIVE &&
219 (ResourceMapper::newRevision() == 1 || $stored->getMimeType() != $mimeType)) {
220 $new = $stored->createNewVersion();
222 $new->changeMimeType($mimeType);
224 $this->getFileMapper()->registerNewVersion($new);
225 $downloadUrl = $new->getUniqueIdentifier();
228 $downloadUrl = $stored->getUniqueIdentifier();
236 private function getFileMapper(): ResourceMapper {
237 return \Drupal::service(
'dkan.metastore.resource_mapper');
249 public static function hostify(
string $resourceUrl): string {
251 $serverPublicFilesUrl = UrlHostTokenResolver::getServerPublicFilesUrl();
252 $serverPublicFilesUrl = isset($serverPublicFilesUrl) ? parse_url($serverPublicFilesUrl) : NULL;
253 $serverHost = $serverPublicFilesUrl[
'host'] ?? \Drupal::request()->getHost();
255 $resourceParsedUrl = parse_url($resourceUrl);
256 if (isset($resourceParsedUrl[
'host']) && $resourceParsedUrl[
'host'] == $serverHost) {
258 $resourceParsedUrl[
'host'] = UrlHostTokenResolver::TOKEN;
259 $resourceUrl = self::unparseUrl($resourceParsedUrl);
267 private static function unparseUrl($parsedUrl) {
280 foreach ($urlParts as $part) {
281 if (!isset($parsedUrl[$part])) {
284 $url .= ($part ==
"port") ?
':' :
'';
285 $url .= ($part ==
"query") ?
'?' :
'';
286 $url .= ($part ==
"fragment") ?
'#' :
'';
287 $url .= $parsedUrl[$part];
288 $url .= ($part ==
"scheme") ?
'://' :
'';
303 private function getLocalMimeType(
string $downloadUrl): ?string {
307 $filename = \Drupal::service(
'file_system')->basename($downloadUrl);
308 $filename = urldecode($filename);
311 $files = \Drupal::entityTypeManager()
313 ->loadByProperties([
'filename' => $filename]);
314 $file = reset($files);
318 if ($file !== FALSE) {
319 $mime_type = $file->getMimeType();
323 $this->log(
'value_referencer',
'Unable to determine mime type of file with name "@name", because no file was found with that name.', [
324 '@name' => $filename,
340 private function getRemoteMimeType(
string $downloadUrl): ?string {
345 $client =
new GuzzleClient();
346 $response = $client->head($downloadUrl);
348 $content_type = $response->getHeader(
'Content-Type');
350 if (isset($content_type[0])) {
351 $mime_type = $content_type[0];
368 private function getMimeType($distribution): string {
369 $mimeType =
"text/plain";
372 if (isset($distribution->mediaType)) {
373 $mimeType = $distribution->mediaType;
376 elseif (isset($distribution->format) && $distribution->format ==
'csv') {
377 $mimeType =
'text/csv';
379 elseif (isset($distribution->format) && $distribution->format ==
'tsv') {
380 $mimeType =
'text/tab-separated-values';
384 elseif (isset($distribution->downloadURL)) {
387 $is_local = $distribution->downloadURL !== $this->hostify($distribution->downloadURL);
388 $mimeType = $is_local ?
389 $this->getLocalMimeType($distribution->downloadURL) :
390 $this->getRemoteMimeType($distribution->downloadURL);
393 return $mimeType ?? self::DEFAULT_MIME_TYPE;
410 private function checkExistingReference(
string $property_id, $data) {
411 $storage = $this->storageFactory->getInstance($property_id);
412 $nodes = $storage->getEntityStorage()->loadByProperties([
413 'field_data_type' => $property_id,
414 'title' => Service::metadataHash($data),
417 if ($node = reset($nodes)) {
421 $node->set(
'moderation_state',
'published');
423 return $node->uuid();
443 private function createPropertyReference(
string $property_id, $value) {
445 $data = new \stdClass();
446 $data->identifier = $this->getUuidService()->generate($property_id, $value);
447 $data->data = $value;
448 $json = json_encode($data);
451 $storage = $this->storageFactory->getInstance($property_id);
452 $entity_uuid = $storage->store($json, $data->identifier);