Passed
Push — stage ( e57dee...a7e110 )
by Jon
07:08
created

GenerateRdf::getProjectPath()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
eloc 1
nc 1
nop 1
1
<?php
2
3
namespace App\Jobs;
4
5
use App\Models\Elementset;
6
use App\Models\Release;
7
use App\Models\VocabsModel;
8
use App\Models\Vocabulary;
9
use App\Services\Publish\Git;
10
use apps\frontend\lib\services\jsonldElementsetService;
11
use apps\frontend\lib\services\jsonldVocabularyService;
0 ignored issues
show
Bug introduced by
The type apps\frontend\lib\services\jsonldVocabularyService was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
12
use GuzzleHttp\Client;
13
use Illuminate\Bus\Queueable;
14
use Illuminate\Contracts\Queue\ShouldQueue;
15
use Illuminate\Foundation\Bus\Dispatchable;
16
use Illuminate\Queue\InteractsWithQueue;
17
use Illuminate\Queue\SerializesModels;
18
use Illuminate\Support\Facades\Storage;
19
use Symfony\Component\Process\Exception\ProcessFailedException;
20
use Symfony\Component\Process\Process;
21
22
class GenerateRdf implements ShouldQueue
23
{
24
    use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
25
    public const  VOCABULARY   = Vocabulary::class;
26
    public const  ELEMENTSET   = Elementset::class;
27
    public const  REPO_ROOT    = 'repos';
28
    public const  PROJECT_ROOT = 'projects';
29
    private const URLARRAY     = [self::VOCABULARY => 'vocabularies/', self::ELEMENTSET => 'elementsets/'];
30
    /** @var int $projectId */
31
    private $projectId;
32
    /** @var string $class */
33
    private $class;
34
    /** @var int $id */
35
    private $id;
36
    /** @var string $filePath */
37
    private $filePath;
38
    /** @var string $fileName */
39
    private $fileName;
40
    private $disk;
41
    /**
42
     * @var VocabsModel
43
     */
44
    private $model;
45
    /**
46
     * @var Release
47
     */
48
    private $release;
49
50
    /**
51
     * Create a new job instance.
52
     *
53
     * @param VocabsModel $model
54
     * @param Release     $release
55
     * @param string      $disk
56
     *
57
     * @throws \GitWrapper\GitException
58
     */
59
    public function __construct(VocabsModel $model, Release $release, $disk = self::REPO_ROOT)
60
    {
61
        $this->id        = $model->id;
62
        $this->model     = $model;
63
        $this->class     = \get_class($model);
64
        $this->projectId = $model->project_id;
0 ignored issues
show
Bug introduced by
The property project_id does not seem to exist on App\Models\VocabsModel. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
65
        $basePath        = parse_url($model->base_domain)['path'];
0 ignored issues
show
Bug introduced by
The property base_domain does not seem to exist on App\Models\VocabsModel. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
66
        $this->filePath  = rtrim(parse_url($model->uri)['path'], '/');
0 ignored issues
show
Bug introduced by
The property uri does not seem to exist on App\Models\VocabsModel. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
67
        $this->fileName  = str_replace_first($basePath, '', parse_url($model->uri)['path']);
68
        $this->disk      = $disk;
69
        Git::initDir($model->project, $this->disk);
0 ignored issues
show
Bug introduced by
The property project does not seem to exist on App\Models\VocabsModel. Are you sure there is no database migration missing?

Checks if undeclared accessed properties appear in database migrations and if the creating migration is correct.

Loading history...
70
        $this->release = $release;
71
    }
72
73
    /**
74
     * Execute the job.
75
     *
76
     * @return void
77
     * @throws \InvalidArgumentException
78
     */
79
    public function handle(): void
80
    {
81
        //make sure we have a repo and create one if we don't
82
        //get the rdf/xml and store it in the repo
83
        $this->saveXml();
84
        //get the jsonld and store it in the repo
85
        $this->saveJsonLd();
86
        //TODO: make the translators that are run user-selectable as part of the project attributes
87
        //run the translators to generate the other flavours and store in the repo
88
        $this->saveTtl();
89
        $this->saveNt();
90
        //these are the wonky remote translators
91
        $this->saveN3();
92
        $this->saveRdfJson();
93
        $this->saveMicrodata();
94
        $this->saveRdfa();
95
96
        //update the entry in the releaseables table
97
        $this->updateRelease($this->model);
98
    }
99
100
    /**
101
     * @param $mimeType
102
     *
103
     * @return string
104
     */
105
    public function getStoragePath($mimeType): string
106
    {
107
        return Git::getProjectPath($this->projectId) . "{$mimeType}{$this->filePath}.$mimeType";
108
    }
109
110
    public function saveXml()
111
    {
112
        $storagePath = $this->getStoragePath('xml');
113
        $client      = new Client();
114
        $res         = $client->get(url(self::URLARRAY[$this->class] . $this->id . '.rdf'));
115
        Storage::disk($this->disk)->put($storagePath, $res->getBody());
116
    }
117
118
    public function saveJsonLd()
119
    {
120
        $storagePath = $this->getStoragePath('jsonld');
121
        $release     = $this->makeReleaseArray();
122
        initSymfonyDb();
123
        if ($this->class === self::VOCABULARY) {
124
            $vocabulary    = \VocabularyPeer::retrieveByPK($this->id);
0 ignored issues
show
Bug introduced by
The type VocabularyPeer was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
125
            $jsonLdService = new jsonldVocabularyService($vocabulary, $release);
126
        }
127
        if ($this->class === self::ELEMENTSET) {
128
            $elementset    = \SchemaPeer::retrieveByPK($this->id);
0 ignored issues
show
Bug introduced by
The type SchemaPeer was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
129
            $jsonLdService = new jsonldElementsetService($elementset, $release);
130
        }
131
        Storage::disk($this->disk)->put($storagePath, $jsonLdService->getJsonLd());
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $jsonLdService does not seem to be defined for all execution paths leading up to this point.
Loading history...
132
    }
133
134
    public function saveTtl()
135
    {
136
        $this->runRapper('ttl', 'turtle');
137
    }
138
139
    public function saveNt()
140
    {
141
        $this->runRapper('nt', 'ntriples');
142
    }
143
144
    public function saveN3()
145
    {
146
        $this->runCurl('n3');
147
    }
148
149
    public function saveRdfJson()
150
    {
151
        $this->runCurl('rdf-json');
152
    }
153
154
    public function saveMicrodata()
155
    {
156
        $this->runCurl('microdata');
157
    }
158
159
    public function saveRdfa()
160
    {
161
        $this->runCurl('rdfa');
162
    }
163
164
    /**
165
     * @return array
166
     */
167
    private function makeReleaseArray(): array
168
    {
169
        return ['tag_name' => $this->release->tag_name, 'published_at' => $this->release->published_at->format('F j, Y')];
170
    }
171
172
    /**
173
     * @throws \Symfony\Component\Process\Exception\RuntimeException
174
     * @throws \Symfony\Component\Process\Exception\ProcessFailedException
175
     * @throws \Symfony\Component\Process\Exception\LogicException
176
     */
177
    private function runRapper($mimeType, $rapperType)
178
    {
179
        $outputPath = $this->getStoragePath($mimeType);
180
        //just to make sure the path exists
181
        Storage::disk($this->disk)->put($outputPath, ' ');
182
        //make sure rapper has the full paths
183
        $sourcePath = Storage::disk($this->disk)->path($this->getStoragePath('xml'));
184
        $outputPath = Storage::disk($this->disk)->path($this->getStoragePath($mimeType));
185
        $process    = new Process("rapper -o {$rapperType} {$sourcePath} > {$outputPath}");
186
        $process->run();
187
188
        // executes after the command finishes
189
        if (! $process->isSuccessful()) {
190
            throw new ProcessFailedException($process);
191
        }
192
    }
193
194
    /**
195
     * @param $mimeType
196
     *
197
     * @throws \Symfony\Component\Process\Exception\ProcessFailedException
198
     * @throws \Symfony\Component\Process\Exception\RuntimeException
199
     * @throws \Symfony\Component\Process\Exception\LogicException
200
     */
201
    public function runCurl($mimeType)
202
    {
203
        $outputPath = $this->getStoragePath($mimeType);
204
        //just to make sure the path exists
205
        Storage::disk($this->disk)->put($outputPath, ' ');
206
        //make sure we have the full paths
207
        $sourcePath = Storage::disk($this->disk)->path($this->getStoragePath('xml'));
208
        $outputPath = Storage::disk($this->disk)->path($this->getStoragePath($mimeType));
209
        $process    = new Process("curl --data-urlencode content@{$sourcePath} http://rdf-translator.appspot.com/convert/xml/{$mimeType}/content > {$outputPath}");
210
        $process->run();
211
212
        // executes after the command finishes
213
        if (! $process->isSuccessful()) {
214
            throw new ProcessFailedException($process);
215
        }
216
    }
217
218
    /**
219
     * @param $vocab
220
     *
221
     * @throws \InvalidArgumentException
222
     */
223
    private function updateRelease(VocabsModel $vocab): void
224
    {
225
        $vocab->releases()->updateExistingPivot($this->release->id, ['published_at' => $this->release->published_at]);
226
    }
227
}
228