Site   A
last analyzed

Complexity

Total Complexity 32

Size/Duplication

Total Lines 317
Duplicated Lines 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 32
eloc 64
dl 0
loc 317
ccs 80
cts 80
cp 1
rs 9.84
c 0
b 0
f 0

23 Methods

Rating   Name   Duplication   Size   Complexity  
A getNginxConfPathAttribute() 0 3 1
A getNginxConfTemplateAttribute() 0 5 2
A buildFiles() 0 3 1
A getPorter() 0 3 1
A resolveFromPathOrCurrentWorkingDirectory() 0 9 3
A destroyFiles() 0 3 1
A remove() 0 11 1
A getSchemeAttribute() 0 3 2
A getCertificateBuilder() 0 3 1
A firstOrCreateForName() 0 9 2
A getSiteConfigBuilder() 0 3 1
A resolveFromPathOrCurrentWorkingDirectoryOrFail() 0 9 2
A setNginxType() 0 7 1
A getUrlAttribute() 0 3 1
A buildCertificate() 0 3 1
A destroyCertificate() 0 3 1
A nameFromPath() 0 15 3
A setPhpVersion() 0 10 2
A php_version() 0 3 1
A secure() 0 11 1
A unsecure() 0 11 1
A getPorterLibrary() 0 3 1
A createForName() 0 7 1
1
<?php
2
3
namespace App\Models;
4
5
use App\Events\SiteRemoved;
6
use App\Events\SiteSecured;
7
use App\Events\SiteUnsecured;
8
use App\Porter;
9
use App\PorterLibrary;
10
use App\Support\Contracts\Cli;
11
use App\Support\Nginx\SiteConfBuilder;
12
use App\Support\Ssl\CertificateBuilder;
13
use Illuminate\Database\Eloquent\Factories\HasFactory;
14
use Illuminate\Database\Eloquent\Model;
15
use Illuminate\Support\Str;
16
17
class Site extends Model
18
{
19
    use HasFactory;
20
21
    protected $guarded = [];
22
    protected $casts = ['secure' => 'boolean'];
23
24
    /**
25
     * PHP Version.
26
     *
27
     * @return \Illuminate\Database\Eloquent\Relations\BelongsTo
28
     */
29 4
    public function php_version()
30
    {
31 4
        return $this->belongsTo(PhpVersion::class);
32
    }
33
34
    /**
35
     * Resolve the site from the current working directory.
36
     *
37
     * @param string|null $path
38
     *
39
     * @return Site|null
40
     */
41 13
    public static function resolveFromPathOrCurrentWorkingDirectory($path = null)
42
    {
43 13
        $name = static::nameFromPath($path ?: app(Cli::class)->currentWorkingDirectory());
44
45 13
        if (!$name) {
46 2
            return;
47
        }
48
49 11
        return static::where('name', $name)->first();
50
    }
51
52
    /**
53
     * Resolve the site from the current working directory
54
     * Fail if not found.
55
     *
56
     * @param string|null $path
57
     *
58
     * @throws \Exception
59
     *
60
     * @return Site|null
61
     */
62 3
    public static function resolveFromPathOrCurrentWorkingDirectoryOrFail($path = null)
63
    {
64 3
        $site = static::resolveFromPathOrCurrentWorkingDirectory($path);
65
66 3
        if (!$site) {
67 1
            throw new \Exception('Site not found.');
68
        }
69
70 3
        return $site;
71
    }
72
73
    /**
74
     * Get the url for this site.
75
     *
76
     * @return string
77
     */
78 10
    public function getUrlAttribute()
79
    {
80 10
        return $this->name.'.'.setting('domain');
81
    }
82
83
    /**
84
     * Get the scheme for this site.
85
     *
86
     * @return string
87
     */
88 1
    public function getSchemeAttribute()
89
    {
90 1
        return ($this->secure ? 'https' : 'http').'://';
91
    }
92
93
    /**
94
     * Return the path for the NGiNX config file.
95
     *
96
     * @return string
97
     */
98 3
    public function getNginxConfPathAttribute()
99
    {
100 3
        return $this->getPorterLibrary()->configPath()."/nginx/conf.d/{$this->name}.conf";
101
    }
102
103
    /**
104
     * Return the full NGiNX template to use.
105
     *
106
     * @return string
107
     */
108 3
    public function getNginxConfTemplateAttribute()
109
    {
110 3
        $type = $this->nginx_conf ?? 'default';
111
112 3
        return "nginx.{$type}.domain".(($this->secure ?? false) ? '_secure' : '');
113
    }
114
115
    /**
116
     * Build the files for this site (e.g. nginx conf).
117
     *
118
     * @throws \Throwable
119
     */
120 9
    public function buildFiles()
121
    {
122 9
        $this->getSiteConfigBuilder()->build($this);
123
    }
124
125
    /**
126
     * Destroy the files for this site (e.g. NGiNX conf).
127
     */
128 1
    public function destroyFiles()
129
    {
130 1
        $this->getSiteConfigBuilder()->destroy($this);
131
    }
132
133
    /**
134
     * Secure the site. Build certs.
135
     */
136 2
    public function secure()
137
    {
138 2
        $this->buildCertificate();
139
140 2
        $this->update(['secure' => true]);
141
142 2
        $this->buildFiles();
143
144 2
        event(new SiteSecured($this));
145
146 2
        $this->getPorter()->restartServing();
147
    }
148
149
    /**
150
     * Unsecure this site.
151
     */
152 2
    public function unsecure()
153
    {
154 2
        $this->destroyCertificate();
155
156 2
        $this->update(['secure' => false]);
157
158 2
        $this->buildFiles();
159
160 2
        event(new SiteUnsecured($this));
161
162 2
        $this->getPorter()->restartServing();
163
    }
164
165
    /**
166
     * Remove this site and associated files.
167
     *
168
     * @throws \Exception
169
     * @throws \Throwable
170
     */
171 1
    public function remove()
172
    {
173 1
        $this->destroyCertificate();
174
175 1
        $this->getSiteConfigBuilder()->destroy($this);
176
177 1
        $this->delete();
178
179 1
        event(new SiteRemoved($this));
180
181 1
        $this->getPorter()->restartServing();
182
    }
183
184
    /**
185
     * Set the PHP version for the site.
186
     *
187
     * @param int|null $phpVersionId
188
     *
189
     * @throws \Throwable
190
     */
191 2
    public function setPhpVersion($phpVersionId = null)
192
    {
193 2
        $this->update(['php_version_id' => $phpVersionId ?: PhpVersion::defaultVersion()->id]);
194
195
        // The php_version relation needs to be refreshed, so get a whole new representation of this
196 2
        $this->refresh();
197
198 2
        $this->buildFiles();
199
200 2
        $this->getPorter()->restartServing();
201
    }
202
203
    /**
204
     * Set the nginx type for the site (we have different template configs we can use).
205
     *
206
     * @param $type
207
     *
208
     * @throws \Throwable
209
     */
210 1
    public function setNginxType($type)
211
    {
212 1
        $this->update(['nginx_conf' => $type ?? 'default']);
213
214 1
        $this->buildFiles();
215
216 1
        $this->getPorter()->restartServing();
217
    }
218
219
    /**
220
     * Get the first site based on name, or create a new record.
221
     *
222
     *
223
     * @param $name
224
     *
225
     * @return mixed
226
     */
227 1
    public static function firstOrCreateForName($name)
228
    {
229 1
        $result = static::where('name', $name)->first();
230
231 1
        if ($result) {
232 1
            return $result;
233
        }
234
235 1
        return static::createForName($name);
236
    }
237
238
    /**
239
     * Create an new site based on the name.
240
     *
241
     * @param $name
242
     *
243
     * @return mixed
244
     */
245 2
    public static function createForName($name)
246
    {
247 2
        return static::create([
248
            'name'           => $name,
249
            'nginx_conf'     => 'default',
250 2
            'php_version_id' => PhpVersion::defaultVersion()->id,
251
            'secure'         => false,
252
        ]);
253
    }
254
255
    /**
256
     * Get Certificate builder.
257
     *
258
     * @return CertificateBuilder
259
     */
260 7
    protected function getCertificateBuilder()
261
    {
262 7
        return app(CertificateBuilder::class);
263
    }
264
265
    /**
266
     * Get Site Config Builder.
267
     *
268
     * @return \App\Support\Nginx\SiteConfBuilder
269
     */
270 11
    protected function getSiteConfigBuilder()
271
    {
272 11
        return app(SiteConfBuilder::class);
273
    }
274
275
    /**
276
     * Get Porter.
277
     *
278
     * @return Porter
279
     */
280 7
    protected function getPorter()
281
    {
282 7
        return app(Porter::class);
283
    }
284
285
    /**
286
     * Get PorterLibrary.
287
     *
288
     * @return PorterLibrary
289
     */
290 3
    protected function getPorterLibrary()
291
    {
292 3
        return app(PorterLibrary::class);
293
    }
294
295
    /**
296
     * Build Certificate for site.
297
     */
298 4
    public function buildCertificate()
299
    {
300 4
        $this->getCertificateBuilder()->build($this->url);
301
    }
302
303
    /**
304
     * Destroy Certificate for site.
305
     */
306 4
    public function destroyCertificate()
307
    {
308 4
        $this->getCertificateBuilder()->destroy($this->url);
309
    }
310
311
    /**
312
     * Return a site directory name from a path, after checking it is within the
313
     * home directory.
314
     *
315
     * @param $path
316
     *
317
     * @return null|string
318
     */
319 17
    public static function nameFromPath($path)
320
    {
321 17
        $home = setting('home');
322
323 17
        if (strpos($path, DIRECTORY_SEPARATOR) === false) {
324 7
            return $path;
325
        }
326
327 10
        if (strpos($path, $home) !== 0) {
0 ignored issues
show
Bug introduced by
It seems like $home can also be of type null; however, parameter $needle of strpos() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

327
        if (strpos($path, /** @scrutinizer ignore-type */ $home) !== 0) {
Loading history...
328 3
            return;
329
        }
330
331 7
        $path = trim(Str::after($path, $home), DIRECTORY_SEPARATOR);
332
333 7
        return Str::before($path, DIRECTORY_SEPARATOR);
334
    }
335
}
336