Skip to content

Commit 3bd029f

Browse files
committed
feat: add adapter
BREAKING CHANGE: PHPWatcher mandatory construct arguments
1 parent 724fc3a commit 3bd029f

File tree

9 files changed

+164
-89
lines changed

9 files changed

+164
-89
lines changed

README.md

Lines changed: 32 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
A simple directory and file watcher that was made using PHP.
44

5+
## Requirements
6+
7+
* PHP >= 8.1
8+
59
## Installation
610

711
```shell
@@ -17,7 +21,10 @@ To use this package you just need to initialize the watcher and call the tick fu
1721

1822
require_once './vendor/autoload.php';
1923

24+
use \Cydrickn\PHPWatcher\Adapters\SwooleTimerAdapter;
25+
2026
$watcher = new \Cydrickn\PHPWatcher\Watcher(
27+
new SwooleTimerAdapter(),
2128
[__DIR__],
2229
[__DIR__ . '/vendor/'],
2330
function (array $changes) {
@@ -28,79 +35,42 @@ $watcher = new \Cydrickn\PHPWatcher\Watcher(
2835
$watcher->tick();
2936
```
3037

31-
## \Cydrickn\PHPWatcher\Watcher::__construct
32-
33-
\Cydrickn\PHPWatcher\Watcher::__construct - Creates the instance representing the watcher
34-
35-
### Description
36-
37-
```php
38-
public \Cydrickn\PHPWatcher\Watcher::__construct(
39-
array $watchFor,
40-
array $excludes,
41-
callable $handler,
42-
int $interval = 1000
43-
)
44-
```
45-
46-
### Parameters
47-
48-
**watchFor**
49-
50-
List of files and folder that will watch by the watcher.
38+
## Adapters
5139

52-
For folders this will include its sub-folders.
40+
Currently, we have 3 premade adapters:
5341

54-
**excludes**
42+
### \Cydrickn\PHPWatcher\Adapters\SwooleTimerAdapter
5543

56-
List of files and folder that will be excluded in watching.
44+
If you are using Swoole/Openswoole then best choice to use this adapter
5745

58-
For folders this will include its sub-folders.
46+
### \Cydrickn\PHPWatcher\Adapters\NativeAdapter
5947

60-
**handler**
48+
If not using Swoole/Openswoole then you can go for this one, it uses PHP's do-while and sleep
6149

62-
A function that will be called once their are changes
50+
### \Cydrickn\PHPWatcher\Adapters\HybridAdapter
6351

64-
**interval**
52+
This is same as the version 1 where it will automatically use the SwooleTimerAdapter, if available or fallback to NativeAdapter.
53+
This might be useful in a mixed environment.
6554

66-
This is delay for how long it will wait before it will do checking of the files / folders. Default to 1000 milliseconds.
55+
## Custom Adapter
6756

68-
## \Cydrickn\PHPWatcher\Watcher::checkChanges
69-
70-
\Cydrickn\PHPWatcher\Watcher::checkChanges - Check the changes
71-
72-
### Description
57+
If you don't want to use any pre-made adapter you can create your own adapter.
58+
Example:
7359

7460
```php
75-
public \Cydrickn\PHPWatcher\Watcher::checkChanges(): void
76-
```
77-
78-
## \Cydrickn\PHPWatcher\Watcher::tick
79-
80-
\Cydrickn\PHPWatcher\Watcher::tick - Start the watching of files
81-
82-
### Description
83-
84-
```php
85-
public \Cydrickn\PHPWatcher\Watcher::tick(
86-
?callable $handler = null
87-
): void
88-
```
89-
90-
### Parameters
91-
92-
**handler**
93-
94-
A callable use for watching the file, this is default to null.
95-
96-
Once the handler is null, it will use the default handler.
97-
98-
There are two default handler.
61+
<?php
9962

100-
- Swoole\Timer - Will be only use when swoole is enabled in your server
101-
- The do while - If the swoole is not enabled
63+
namespace Your\Namespace;
10264

103-
Once you pass your own handler, this will pass two argument
65+
use Cydrickn\PHPWatcher\Adapters\AdapterInterface;
10466

105-
- The first argument would be the checkChanges function
106-
- The second is the interval
67+
class YourAdapter implements AdapterInterface
68+
{
69+
public function tick(callable $handler, int $interval = 1000)
70+
{
71+
// Implement your own logic
72+
// Also make sure to call the handler to trigger the checking of changed files
73+
// e.g. call_user_func($handler);
74+
}
75+
}
76+
```

UPGRADE.md

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
# Upgrade Notes
2+
3+
When upgrading to a newer version, some configuration structures must be updated before applying the modifications.
4+
5+
## 2.0
6+
7+
- Upgrade your PHP version to 8.1 or higher
8+
9+
### Breaking changes
10+
11+
It's expecting the when upgrading from version 1.x to 2.0 that it will break,
12+
this is due to the new version is now using Adapter, where you need to pass the Adapter instead of automatically
13+
detecting the Swoole Timer and use that.
14+
15+
From this code (v1)
16+
```php
17+
<?php
18+
19+
require_once './vendor/autoload.php';
20+
21+
$watcher = new \Cydrickn\PHPWatcher\Watcher(
22+
[__DIR__],
23+
[__DIR__ . '/vendor/'],
24+
function (array $changes) {
25+
echo json_encode($changes) . PHP_EOL;
26+
}
27+
);
28+
29+
$watcher->tick();
30+
```
31+
32+
To this code (v2)
33+
```php
34+
<?php
35+
36+
require_once './vendor/autoload.php';
37+
38+
use \Cydrickn\PHPWatcher\Adapters\SwooleTimerAdapter;
39+
40+
$watcher = new \Cydrickn\PHPWatcher\Watcher(
41+
new SwooleTimerAdapter(),
42+
[__DIR__],
43+
[__DIR__ . '/vendor/'],
44+
function (array $changes) {
45+
echo json_encode($changes) . PHP_EOL;
46+
}
47+
);
48+
49+
$watcher->tick();
50+
```
51+
52+
Take note that `tick()` method now don't accept any parameter unlike from version 1.

composer.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,5 +14,7 @@
1414
"email": "cydrick.dev@gmail.com"
1515
}
1616
],
17-
"require": {}
17+
"require": {
18+
"php": ">=8.1"
19+
}
1820
}

src/Adapters/AdapterInterface.php

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Cydrickn\PHPWatcher\Adapters;
6+
7+
interface AdapterInterface
8+
{
9+
public function tick(callable $handler, int $interval = 1000): void;
10+
}

src/Adapters/HybridAdapter.php

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Cydrickn\PHPWatcher\Adapters;
6+
7+
class HybridAdapter implements AdapterInterface
8+
{
9+
private NativeAdapter $nativeAdapter;
10+
private SwooleTimerAdapter $swooleTimer;
11+
12+
public function __construct()
13+
{
14+
$this->nativeAdapter = new NativeAdapter();
15+
$this->swooleTimer = new SwooleTimerAdapter();
16+
}
17+
18+
public function tick(callable $handler, int $interval = 1000): void
19+
{
20+
if (extension_loaded('swoole') || extension_loaded('openswoole')) {
21+
$this->swooleTimer->tick($handler, $interval);
22+
} else {
23+
$this->nativeAdapter->tick($handler, $interval);
24+
}
25+
}
26+
}

src/Adapters/NativeAdapter.php

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Cydrickn\PHPWatcher\Adapters;
6+
7+
class NativeAdapter implements AdapterInterface
8+
{
9+
public function tick(callable $handler, int $interval = 1000): void
10+
{
11+
do {
12+
call_user_func($handler);
13+
sleep($interval / 1000);
14+
} while (true);
15+
}
16+
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Cydrickn\PHPWatcher\Adapters;
6+
7+
use Swoole\Timer;
8+
9+
class SwooleTimerAdapter implements AdapterInterface
10+
{
11+
public function tick(callable $handler, int $interval = 1000): void
12+
{
13+
Timer::tick($interval, function () use ($handler) {
14+
call_user_func($handler);
15+
});
16+
}
17+
}

src/Enum/ChangeType.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
<?php
22

3+
declare(strict_types=1);
4+
35
namespace Cydrickn\PHPWatcher\Enum;
46

57
enum ChangeType: int

src/Watcher.php

Lines changed: 6 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
<?php
2+
declare(strict_types=1);
23

34
namespace Cydrickn\PHPWatcher;
45

6+
use Cydrickn\PHPWatcher\Adapters\AdapterInterface;
57
use Cydrickn\PHPWatcher\Enum\ChangeType;
68
use RecursiveDirectoryIterator;
79
use RecursiveTreeIterator;
@@ -13,12 +15,11 @@ class Watcher
1315
private array $changes = [];
1416
private bool $initialized = false;
1517
private bool $checking = false;
16-
1718
private array $excludeFiles = [];
1819
private array $excludeDirs = [];
1920
private mixed $handler;
2021

21-
public function __construct(private array $watchFor, array $excludes, callable $handler, private int $interval = 1000)
22+
public function __construct(private readonly AdapterInterface $adapter, private readonly array $watchFor, array $excludes, callable $handler, private readonly int $interval = 1000)
2223
{
2324
foreach ($excludes as $exclude) {
2425
if (is_dir($exclude)) {
@@ -30,7 +31,6 @@ public function __construct(private array $watchFor, array $excludes, callable $
3031
$this->handler = $handler;
3132
}
3233

33-
3434
protected function addChange(string $filename, ChangeType $type): void
3535
{
3636
$this->changes[] = [
@@ -63,7 +63,7 @@ protected function checkFile(string $file, bool $checkForDelete = false): void
6363
$data = $this->files[$file];
6464
$checkData = filemtime($file);
6565

66-
if ($checkData != $data) {
66+
if ($checkData !== $data) {
6767
$this->addChange($file, ChangeType::UPDATED);
6868
}
6969
}
@@ -81,7 +81,6 @@ protected function commit(): void
8181
unset($this->files[$change['name']]);
8282
continue;
8383
}
84-
8584
$this->files[$change['name']] = $change['data'];
8685
}
8786

@@ -106,11 +105,9 @@ public function checkChanges(): void
106105
foreach ($allFiles as $file) {
107106
$filename = trim(str_replace(['|', ' ', '~', '\\'], '', $file), '-');
108107
$filename = is_dir($filename) ? $filename . '/' : $filename;
109-
110108
if ((is_file($filename) && in_array($filename, $this->excludeFiles)) || (is_dir($filename) && in_array($filename, $this->excludeDirs))) {
111109
continue;
112110
}
113-
114111
foreach ($this->excludeDirs as $dir) {
115112
if (str_starts_with($filename, $dir)) {
116113
continue 2;
@@ -123,7 +120,6 @@ public function checkChanges(): void
123120
$this->checkFile($watchFor);
124121
}
125122

126-
127123
// Checks the deleted files
128124
foreach ($this->files as $key => $file) {
129125
$this->checkFile($key, true);
@@ -138,24 +134,8 @@ public function checkChanges(): void
138134
$this->checking = false;
139135
}
140136

141-
public function tick(?callable $handler = null): void
137+
public function tick(): void
142138
{
143-
if ($handler !== null) {
144-
call_user_func($handler, [$this, 'checkChanges'], $this->interval);
145-
return;
146-
}
147-
148-
if (class_exists(Timer::class)) {
149-
Timer::tick($this->interval, function () {
150-
$this->checkChanges();
151-
});
152-
} else {
153-
$this->tick(function ($checkChanges, $interval) {
154-
do {
155-
call_user_func($checkChanges);
156-
sleep($interval / 1000);
157-
} while (true);
158-
});
159-
}
139+
$this->adapter->tick([$this, 'checkChanges'], $this->interval);
160140
}
161141
}

0 commit comments

Comments
 (0)