Skip to content

Commit 5933a49

Browse files
Implement ApplicationBuilder and CanUpload trait
This commit implements ApplicationBuilder class and CanUpload trait. It also refactors AbstractApplication, Route, Config, Listener and other classes to adapt the CanUpload trait. The ApplicationBuilder class includes the creation logic of different application types. The CanUpload trait provides generic methods for the data upload and removal to Nginx Unit.
1 parent deb1d1b commit 5933a49

32 files changed

+608
-397
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
# CHANGELOG
22

3+
## v0.8.0 - [2024/04/26]
4+
5+
- Updated application classes
6+
- Removed doc folder
7+
- Updated tests
8+
39
## v0.7.0 - [2024/04/07]
410

511
- Now SDK support connection via only address.

composer.json

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "pavlusha/unit-php-sdk",
3-
"version": "0.7.0",
3+
"version": "0.8.0",
44
"type": "sdk",
55
"description": "This project allows developers to interact with the Nginx Unit web server through PHP classes",
66
"license": "Apache-2.0",
@@ -29,13 +29,14 @@
2929
},
3030
"require": {
3131
"php": "^8.3",
32-
"friendsofphp/php-cs-fixer": "^3.46",
32+
"friendsofphp/php-cs-fixer": "^3.54",
3333
"guzzlehttp/guzzle": "^7.8.1",
34-
"ext-curl": "*",
35-
"nesbot/carbon": "^2.72"
34+
"nesbot/carbon": "^2.72",
35+
"doctrine/inflector": "^2.0",
36+
"ext-curl": "*"
3637
},
3738
"require-dev": {
38-
"pestphp/pest": "^2.26",
39+
"pestphp/pest": "^2.34",
3940
"phpstan/phpstan": "^1.10",
4041
"mockery/mockery": "^1.6"
4142
},
@@ -57,6 +58,6 @@
5758
"pestphp/pest-plugin": true
5859
}
5960
},
60-
"minimum-stability": "beta",
61+
"minimum-stability": "stable",
6162
"prefer-stable": true
6263
}

src/Abstract/AbstractApplication.php

Lines changed: 27 additions & 83 deletions
Original file line numberDiff line numberDiff line change
@@ -6,22 +6,21 @@
66
ProcessManagement\ProcessIsolation,
77
ProcessManagement\RequestLimit
88
};
9+
use UnitPhpSdk\Builders\EndpointBuilder;
910
use UnitPhpSdk\Exceptions\UnitException;
10-
use UnitPhpSdk\Http\UnitRequest;
11-
use UnitPhpSdk\Contracts\{ApplicationControlInterface, ApplicationInterface, Arrayable, Uploadable};
11+
use UnitPhpSdk\Contracts\{ApplicationInterface, Arrayable, Uploadable};
12+
use UnitPhpSdk\Traits\CanUpload;
1213
use UnitPhpSdk\Traits\HasListeners;
1314

1415
/**
15-
* @implements ApplicationInterface, ApplicationControlInterface, Arrayable
16+
* @implements ApplicationInterface
17+
* @implements Arrayable
18+
* @implements Uploadable
1619
*/
17-
abstract class AbstractApplication implements ApplicationInterface, ApplicationControlInterface, Arrayable, Uploadable
20+
abstract class AbstractApplication implements ApplicationInterface, Arrayable, Uploadable
1821
{
1922
use HasListeners;
20-
21-
/**
22-
* @var UnitRequest
23-
*/
24-
private UnitRequest $unitRequest;
23+
use CanUpload;
2524

2625
/**
2726
* Environment variables to be passed to the app
@@ -89,24 +88,18 @@ abstract class AbstractApplication implements ApplicationInterface, ApplicationC
8988
private ?ProcessIsolation $isolation = null;
9089

9190
/**
92-
* @throws UnitException
91+
* @param string $name
92+
* @param array|null $data
9393
*/
94-
public function __construct($data = null)
94+
public function __construct(string $name, ?array $data = [])
9595
{
96+
$this->setName($name);
97+
9698
if (!empty($data)) {
9799
$this->parseFromArray($data);
98100
}
99-
}
100-
101-
/**
102-
* @param UnitRequest $unitRequest
103-
* @return AbstractApplication
104-
*/
105-
public function setUnitRequest(UnitRequest $unitRequest): self
106-
{
107-
$this->unitRequest = $unitRequest;
108101

109-
return $this;
102+
$this->setApiEndpoint(EndpointBuilder::create("config/applications/")->get() . $this->getName());
110103
}
111104

112105
/**
@@ -348,61 +341,33 @@ public function setName(string $name): self
348341
*
349342
* @param array $data
350343
* @return void
351-
* @throws UnitException
352344
*/
353345
public function parseFromArray(array $data): void
354346
{
355347
$data = array_filter($data, fn ($item) => !empty($item), ARRAY_FILTER_USE_BOTH);
356348

357-
if (array_key_exists('working_directory', $data)) {
358-
$this->setWorkingDirectory($data['working_directory']);
359-
}
360-
361-
if (array_key_exists('user', $data)) {
362-
$this->setUser($data['user']);
363-
}
364-
365-
if (array_key_exists('group', $data)) {
366-
$this->setGroup($data['group']);
367-
}
368-
369-
if (array_key_exists('environment', $data)) {
370-
$this->setEnvironment($data['environment']);
371-
}
372-
373-
if (array_key_exists('stderr', $data)) {
374-
$this->setStdErr($data['stderr']);
375-
}
376-
377-
if (array_key_exists('stdout', $data)) {
378-
$this->setStdOut($data['stdout']);
379-
}
349+
$attributes = ['working_directory', 'user', 'group', 'environment', 'stderr', 'stdout', 'isolation', 'processes', 'limits',];
380350

381-
if (array_key_exists('isolation', $data)) {
382-
$this->setIsolation($data['isolation']);
383-
}
384-
385-
if (array_key_exists('processes', $data)) {
386-
$this->setProcesses($data['processes']);
387-
}
351+
foreach ($attributes as $attribute) {
352+
$camelCase = str_replace(' ', '', ucwords(str_replace('_', ' ', $attribute)));
353+
$method = "set" . $camelCase;
388354

389-
if (array_key_exists('limits', $data)) {
390-
$this->setLimits($data['limits']);
355+
$this->setDataAttributeIfExists($data, $attribute, $method);
391356
}
392357
}
393358

394359
/**
395-
* @inheritDoc
360+
* If the given key exists in the data array, call the corresponding setter method.
361+
*
362+
* @param array $data
363+
* @param string $key
364+
* @param string $method
396365
*/
397-
public function restartApplication(): bool
366+
protected function setDataAttributeIfExists(array $data, string $key, string $method): void
398367
{
399-
try {
400-
$this->unitRequest->send("/control/applications/{$this->getName()}/restart");
401-
} catch (UnitException) {
402-
return false;
368+
if (array_key_exists($key, $data)) {
369+
$this->$method($data[$key]);
403370
}
404-
405-
return true;
406371
}
407372

408373
/**
@@ -430,25 +395,4 @@ public function toJson(): string|false
430395
{
431396
return json_encode(array_filter(static::toArray(), fn ($item) => !empty($item)), JSON_UNESCAPED_SLASHES);
432397
}
433-
434-
/**
435-
* @param UnitRequest $request
436-
* @return void
437-
* @throws UnitException
438-
*/
439-
#[\Override] public function upload(UnitRequest $request): void
440-
{
441-
$request->setMethod('PUT')
442-
->send($this->getApiEndpoint(), true, ['json' => array_filter($this->toArray(), fn ($item) => !empty($item))]);
443-
}
444-
445-
#[\Override] public function remove(UnitRequest $request): void
446-
{
447-
$request->setMethod('DELETE')->send($this->getApiEndpoint());
448-
}
449-
450-
public function getApiEndpoint(): string
451-
{
452-
return "/config/applications/{$this->getName()}";
453-
}
454398
}

src/Builders/ApplicationBuilder.php

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
<?php
2+
3+
namespace UnitPhpSdk\Builders;
4+
5+
use UnitPhpSdk\Config\Application\{GoExternalApplication,
6+
JavaApplication,
7+
NodeJsExternalApplication,
8+
PerlApplication,
9+
PhpApplication,
10+
PythonApplication,
11+
RubyApplication,
12+
WebAssemblyApplication,
13+
WebAssemblyComponentApplication
14+
};
15+
use UnitPhpSdk\Exceptions\UnitException;
16+
17+
class ApplicationBuilder
18+
{
19+
/**
20+
* @throws UnitException
21+
*
22+
* TODO: add ApplicationTypeEnum as possible type
23+
*/
24+
public static function create($appName, $appData, string $type = '')
25+
{
26+
$application = match ($type) {
27+
'php' => new PhpApplication($appName, $appData),
28+
'java' => new JavaApplication($appName, $appData),
29+
'perl' => new PerlApplication($appName, $appData),
30+
'python' => new PythonApplication($appName, $appData),
31+
'wasm' => new WebAssemblyApplication($appName, $appData),
32+
'ruby' => new RubyApplication($appName, $appData),
33+
'wasm-wasi-component' => new WebAssemblyComponentApplication($appName, $appData),
34+
'external' => self::isNodeJsApplication($appData) ?
35+
new NodeJsExternalApplication($appName, $appData) :
36+
new GoExternalApplication($appName, $appData),
37+
};
38+
39+
return $application;
40+
}
41+
42+
/**
43+
* Detect if NodeJsExternalApplication
44+
*
45+
* @param $appData
46+
* @return bool
47+
*/
48+
private static function isNodeJsApplication($appData): bool
49+
{
50+
if (str_contains($appData['executable'], '.js')) {
51+
return true;
52+
}
53+
54+
if (array_key_exists('arguments', $appData)) {
55+
return str_contains(implode(';', $appData['arguments']), '.js');
56+
}
57+
58+
return false;
59+
}
60+
}

src/Builders/EndpointBuilder.php

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
<?php
2+
3+
namespace UnitPhpSdk\Builders;
4+
5+
use UnitPhpSdk\Contracts\Uploadable;
6+
use UnitPhpSdk\Support\Pluralizer;
7+
8+
/**
9+
* Class EndpointBuilder
10+
*
11+
* A class to build the endpoint for a given object.
12+
*
13+
* TODO: review
14+
*/
15+
class EndpointBuilder
16+
{
17+
protected string $endpoint = '';
18+
19+
public function __construct(
20+
// TODO: change with http extension
21+
array|string $url = null
22+
) {
23+
$this->endpoint = '/' . (is_array($url) ? implode('/', $url) : $url);
24+
}
25+
26+
/**
27+
* @param object $object
28+
* @return array
29+
*/
30+
private static function convertNamespace(object $object): array
31+
{
32+
$fullClassName = get_class($object);
33+
$namespaceParts = array_map('strtolower', explode('\\', $fullClassName));
34+
array_shift($namespaceParts);
35+
36+
return $namespaceParts;
37+
}
38+
39+
/**
40+
* @param mixed|null $value
41+
* @return EndpointBuilder
42+
*/
43+
public static function create(mixed $value = null): EndpointBuilder
44+
{
45+
$result = $value;
46+
47+
if (is_a($value, Uploadable::class)) {
48+
$result = self::convertNamespace($value);
49+
$entity = Pluralizer::plural(end($result));
50+
array_pop($result);
51+
$result[] = $entity;
52+
}
53+
54+
return new EndpointBuilder($result);
55+
}
56+
57+
/**
58+
* Gets the endpoint value.
59+
*
60+
* @return string The endpoint value.
61+
*/
62+
public function get(): string
63+
{
64+
return $this->endpoint;
65+
}
66+
}

0 commit comments

Comments
 (0)