Skip to content

Commit c54e6a0

Browse files
jakubkulhanclaude
andcommitted
Add comprehensive README.md with cargo-php installation and usage examples
🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
1 parent c2d84dc commit c54e6a0

1 file changed

Lines changed: 278 additions & 0 deletions

File tree

Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
# DataAccessKit Replication
2+
3+
> Real-time MySQL/MariaDB binary log replication stream for PHP
4+
5+
## Quick start
6+
7+
Start by creating a replication stream to capture database changes in real-time.
8+
9+
```php
10+
use DataAccessKit\Replication\Stream;
11+
12+
// Connect to MySQL replication stream
13+
$stream = new Stream('mysql://replication_user:password@localhost:3306?server_id=100');
14+
15+
// Process events as they occur
16+
foreach ($stream as $event) {
17+
match ($event->type) {
18+
'INSERT' => handleInsert($event),
19+
'UPDATE' => handleUpdate($event),
20+
'DELETE' => handleDelete($event),
21+
};
22+
}
23+
24+
function handleInsert($event) {
25+
echo "New record in {$event->schema}.{$event->table}\n";
26+
var_dump($event->after); // New row data
27+
}
28+
29+
function handleUpdate($event) {
30+
echo "Updated record in {$event->schema}.{$event->table}\n";
31+
var_dump($event->before); // Old row data
32+
var_dump($event->after); // New row data
33+
}
34+
35+
function handleDelete($event) {
36+
echo "Deleted record from {$event->schema}.{$event->table}\n";
37+
var_dump($event->before); // Deleted row data
38+
}
39+
```
40+
41+
## Installation
42+
43+
### Prerequisites
44+
45+
- **PHP 8.4** or higher
46+
- **Rust toolchain** (rustc, cargo)
47+
- **cargo-php** for building PHP extensions
48+
49+
Install cargo-php:
50+
51+
```bash
52+
cargo install cargo-php
53+
```
54+
55+
### Build and Install Extension
56+
57+
```bash
58+
# Clone the repository
59+
git clone https://github.com/jakubkulhan/data-access-kit-replication.git
60+
cd data-access-kit-replication
61+
62+
# Build the extension
63+
cargo build --release
64+
65+
# Install the extension using cargo-php
66+
cargo php install
67+
```
68+
69+
## Usage
70+
71+
### Stream
72+
73+
Initialize a stream to connect to the MySQL replication log:
74+
75+
```php
76+
use DataAccessKit\Replication\Stream;
77+
78+
// Create stream with connection URL
79+
$stream = new Stream('mysql://replication_user:password@localhost:3306?server_id=100');
80+
81+
// Start iterating over events
82+
foreach ($stream as $event) {
83+
// Process each replication event
84+
echo "Event: {$event->type} on {$event->schema}.{$event->table}\n";
85+
}
86+
```
87+
88+
Connection URL formats:
89+
90+
```php
91+
// MySQL (port 32016 when using docker-compose)
92+
$url = 'mysql://root@localhost:32016?server_id=100';
93+
94+
// MariaDB (port 35098 when using docker-compose)
95+
$url = 'mysql://root@localhost:35098?server_id=100';
96+
97+
// With authentication
98+
$url = 'mysql://user:password@localhost:3306?server_id=100';
99+
```
100+
101+
### Events
102+
103+
The extension provides three types of events for database changes:
104+
105+
#### InsertEvent
106+
107+
```php
108+
// Properties available on InsertEvent
109+
$event->type; // 'INSERT'
110+
$event->timestamp; // Unix timestamp
111+
$event->checkpoint; // Replication checkpoint
112+
$event->schema; // Database schema name
113+
$event->table; // Table name
114+
$event->after; // stdClass with new row data
115+
```
116+
117+
#### UpdateEvent
118+
119+
```php
120+
// Properties available on UpdateEvent
121+
$event->type; // 'UPDATE'
122+
$event->timestamp; // Unix timestamp
123+
$event->checkpoint; // Replication checkpoint
124+
$event->schema; // Database schema name
125+
$event->table; // Table name
126+
$event->before; // stdClass with old row data
127+
$event->after; // stdClass with new row data
128+
```
129+
130+
#### DeleteEvent
131+
132+
```php
133+
// Properties available on DeleteEvent
134+
$event->type; // 'DELETE'
135+
$event->timestamp; // Unix timestamp
136+
$event->checkpoint; // Replication checkpoint
137+
$event->schema; // Database schema name
138+
$event->table; // Table name
139+
$event->before; // stdClass with deleted row data
140+
```
141+
142+
### Filter
143+
144+
Filter events to only process specific tables or event types:
145+
146+
```php
147+
use DataAccessKit\Replication\{Stream, StreamFilterInterface};
148+
149+
class TableFilter implements StreamFilterInterface {
150+
public function __construct(private array $allowedTables) {}
151+
152+
public function accept(string $type, string $schema, string $table): bool {
153+
return in_array("$schema.$table", $this->allowedTables);
154+
}
155+
}
156+
157+
$stream = new Stream('mysql://root@localhost:32016?server_id=100');
158+
$stream->setFilter(new TableFilter(['myapp.users', 'myapp.orders']));
159+
160+
foreach ($stream as $event) {
161+
// Only receives events for users and orders tables
162+
var_dump($event);
163+
}
164+
```
165+
166+
You can also filter by event type:
167+
168+
```php
169+
class EventTypeFilter implements StreamFilterInterface {
170+
public function accept(string $type, string $schema, string $table): bool {
171+
// Only process INSERT and UPDATE events
172+
return in_array($type, ['INSERT', 'UPDATE']);
173+
}
174+
}
175+
```
176+
177+
### Checkpointer
178+
179+
Save and resume from specific positions in the binlog stream:
180+
181+
```php
182+
use DataAccessKit\Replication\{Stream, StreamCheckpointerInterface};
183+
184+
class FileCheckpointer implements StreamCheckpointerInterface {
185+
public function __construct(private string $filename) {}
186+
187+
public function loadLastCheckpoint(): ?string {
188+
return file_exists($this->filename) ? file_get_contents($this->filename) : null;
189+
}
190+
191+
public function saveCheckpoint(string $checkpoint): void {
192+
file_put_contents($this->filename, $checkpoint);
193+
}
194+
}
195+
196+
$stream = new Stream('mysql://root@localhost:32016?server_id=100');
197+
$stream->setCheckpointer(new FileCheckpointer('/tmp/replication.checkpoint'));
198+
199+
foreach ($stream as $event) {
200+
// Process event...
201+
// Checkpoint is automatically saved by the extension
202+
var_dump($event);
203+
}
204+
```
205+
206+
For production systems, use database-based checkpointing:
207+
208+
```php
209+
class DatabaseCheckpointer implements StreamCheckpointerInterface {
210+
public function __construct(private PDO $pdo, private string $streamId) {}
211+
212+
public function loadLastCheckpoint(): ?string {
213+
$stmt = $this->pdo->prepare('SELECT checkpoint FROM stream_positions WHERE stream_id = ?');
214+
$stmt->execute([$this->streamId]);
215+
return $stmt->fetchColumn() ?: null;
216+
}
217+
218+
public function saveCheckpoint(string $checkpoint): void {
219+
$stmt = $this->pdo->prepare(
220+
'INSERT INTO stream_positions (stream_id, checkpoint, updated_at) VALUES (?, ?, NOW()) ' .
221+
'ON DUPLICATE KEY UPDATE checkpoint = VALUES(checkpoint), updated_at = NOW()'
222+
);
223+
$stmt->execute([$this->streamId, $checkpoint]);
224+
}
225+
}
226+
```
227+
228+
The extension supports two checkpoint formats:
229+
230+
- **GTID format (MySQL only)**: `gtid:3E11FA47-71CA-11E1-9E33-C80AA9429562:23`
231+
- **File/position format**: `file:mysql-bin.000123:45678`
232+
233+
The extension automatically chooses the appropriate format based on server type and configuration.
234+
235+
## Contributing
236+
237+
This repository is part of the [DataAccessKit project](https://github.com/jakubkulhan/data-access-kit-src). Please open issues and pull requests in the main repository.
238+
239+
### Local Development Setup
240+
241+
For development, clone the source repository and install dependencies:
242+
243+
```bash
244+
composer install
245+
```
246+
247+
Start databases for testing:
248+
249+
```bash
250+
# Start MySQL and MariaDB for testing
251+
docker-compose up -d mysql mariadb
252+
```
253+
254+
Build and test the extension:
255+
256+
```bash
257+
# Build extension for development
258+
cargo build
259+
260+
# Run unit tests (fast, no database required)
261+
composer run test:unit
262+
263+
# Run database integration tests (requires running databases)
264+
composer run test:database:all
265+
266+
# Run tests against specific databases
267+
composer run test:database:mysql # MySQL on port 32016
268+
composer run test:database:mariadb # MariaDB on port 35098
269+
```
270+
271+
The test commands will:
272+
1. Build the Rust extension (`cargo build`)
273+
2. Load the extension via local PHP configuration
274+
3. Run the specified PHPUnit test groups
275+
276+
## License
277+
278+
Licensed under MIT license. See [LICENSE](LICENSE) for details.

0 commit comments

Comments
 (0)