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
![]() |
|||
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 |