Skip to content

Commit 2dab931

Browse files
committed
[UPD] [REF] v3.0.0 release preparation
1 parent 2d9550d commit 2dab931

61 files changed

Lines changed: 4573 additions & 2583 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.github/workflows/tests.yml

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ jobs:
1212
strategy:
1313
fail-fast: false
1414
matrix:
15-
php-version: [ '8.2', '8.3', '8.4' ]
15+
php-version: [ '8.2', '8.3', '8.4', '8.5' ]
1616

1717
name: Unit — PHP ${{ matrix.php-version }}
1818

@@ -24,20 +24,29 @@ jobs:
2424
with:
2525
php-version: ${{ matrix.php-version }}
2626
extensions: openssl, sockets, pcntl
27-
coverage: none
27+
coverage: ${{ matrix.php-version == '8.5' && 'xdebug' || 'none' }}
2828

2929
- name: Install Composer dependencies
3030
run: composer install --no-interaction --prefer-dist
3131

3232
- name: Run unit tests
33-
run: vendor/bin/pest tests/Unit
33+
run: vendor/bin/pest tests/Unit ${{ matrix.php-version == '8.5' && '--coverage-clover=coverage/unit-clover.xml' || '' }}
34+
35+
- name: Upload unit coverage to Codecov
36+
if: matrix.php-version == '8.5'
37+
uses: codecov/codecov-action@v5
38+
with:
39+
files: coverage/unit-clover.xml
40+
token: ${{ secrets.CODECOV_TOKEN }}
41+
flags: unit
42+
fail_ci_if_error: false
3443

3544
integration:
3645
runs-on: ubuntu-latest
3746
strategy:
3847
fail-fast: false
3948
matrix:
40-
php-version: [ '8.2', '8.3', '8.4' ]
49+
php-version: [ '8.2', '8.3', '8.4', '8.5' ]
4150

4251
name: Integration — PHP ${{ matrix.php-version }}
4352

@@ -49,7 +58,7 @@ jobs:
4958
with:
5059
php-version: ${{ matrix.php-version }}
5160
extensions: openssl, sockets, pcntl
52-
coverage: none
61+
coverage: ${{ matrix.php-version == '8.5' && 'xdebug' || 'none' }}
5362

5463
- name: Install Composer dependencies
5564
run: composer install --no-interaction --prefer-dist
@@ -58,10 +67,27 @@ jobs:
5867
id: opcua
5968
uses: GianfriAur/opcua-test-server-suite@v1.1.4
6069

61-
- name: Run integration tests
70+
- name: Run all tests
6271
env:
6372
OPCUA_CERTS_DIR: ${{ steps.opcua.outputs.certs-dir }}
64-
run: vendor/bin/pest tests/Integration --group=integration
73+
run: vendor/bin/pest --log-junit=results/junit.xml ${{ matrix.php-version == '8.5' && '--coverage-clover=coverage/clover.xml' || '' }}
74+
75+
- name: Upload coverage to Codecov
76+
if: matrix.php-version == '8.5'
77+
uses: codecov/codecov-action@v5
78+
with:
79+
files: coverage/clover.xml
80+
token: ${{ secrets.CODECOV_TOKEN }}
81+
fail_ci_if_error: false
82+
83+
- name: Upload test results to Codecov
84+
if: ${{ !cancelled() }}
85+
uses: codecov/codecov-action@v5
86+
with:
87+
files: results/junit.xml
88+
token: ${{ secrets.CODECOV_TOKEN }}
89+
flags: test-results
90+
disable_search: true
6591

6692
- name: Server logs (on failure)
6793
if: failure()

CHANGELOG.md

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

3+
## [3.0.0] - 2026-03-22
4+
5+
### Changed
6+
7+
- **Breaking**: Updated dependency `gianfriaur/opcua-php-client` from `^2.0` to `^3.0`.
8+
- **Breaking**: `nodeClassMask` parameter replaced with `nodeClasses` array. Browse methods (`browse()`, `browseWithContinuation()`, `browseAll()`, `browseRecursive()`) now accept `NodeClass[] $nodeClasses = []` instead of `int $nodeClassMask = 0`. Pass an array of `NodeClass` enum values (e.g. `[NodeClass::Object, NodeClass::Variable]`) instead of a raw bitmask integer. Empty array means all classes (same as the old `0`).
9+
- **Breaking**: Strict return types for all service responses. The following methods now return typed DTOs instead of associative arrays:
10+
- `createSubscription()``SubscriptionResult` (`->subscriptionId`, `->revisedPublishingInterval`, `->revisedLifetimeCount`, `->revisedMaxKeepAliveCount`)
11+
- `createMonitoredItems()``MonitoredItemResult[]` (`->statusCode`, `->monitoredItemId`, `->revisedSamplingInterval`, `->revisedQueueSize`)
12+
- `createEventMonitoredItem()``MonitoredItemResult`
13+
- `call()``CallResult` (`->statusCode`, `->inputArgumentResults`, `->outputArguments`)
14+
- `browseWithContinuation()` / `browseNext()``BrowseResultSet` (`->references`, `->continuationPoint`)
15+
- `publish()``PublishResult` (`->subscriptionId`, `->sequenceNumber`, `->moreNotifications`, `->notifications`, `->availableSequenceNumbers`)
16+
- `translateBrowsePaths()``BrowsePathResult[]` (`->statusCode`, `->targets`) with `BrowsePathTarget` (`->targetId`, `->remainingPathIndex`)
17+
- **Breaking**: Ambiguous `$items` parameters renamed for named parameter clarity: `readMulti($readItems)`, `writeMulti($writeItems)`, `createMonitoredItems($subscriptionId, $monitoredItems)`. Only affects code using named parameters.
18+
- All `TypeSerializer` getters updated to use `public readonly` properties from `opcua-php-client` v3.0.0 (`$ref->nodeId` instead of `$ref->getNodeId()`, etc.).
19+
- `TypeSerializer` now preserves `Variant` multi-dimensional array dimensions through serialization/deserialization roundtrips.
20+
- Method whitelist expanded from 32 to 37 methods to support all new v3.0.0 operations.
21+
22+
### Added
23+
24+
- **All methods accepting `NodeId` now also accept `string`.** Pass OPC UA string format directly (e.g. `'i=2259'`, `'ns=2;s=MyNode'`). Applies to: `read`, `write`, `browse`, `browseAll`, `browseWithContinuation`, `browseRecursive`, `call` (both params), `historyReadRaw`, `historyReadProcessed`, `historyReadAtTime`, `createEventMonitoredItem`, `resolveNodeId` (`$startingNodeId`), `invalidateCache`. Also works inside arrays for `readMulti`, `writeMulti`, `createMonitoredItems`, `translateBrowsePaths`.
25+
- **Fluent/Builder API** for multi-node operations. `readMulti()`, `writeMulti()`, `createMonitoredItems()`, and `translateBrowsePaths()` now return a fluent builder when called without arguments: `$client->readMulti()->node('i=2259')->value()->node('i=1001')->displayName()->execute()`. The array-based API still works when passing arguments directly.
26+
- **PSR-3 Logging.** `setLogger(LoggerInterface)` / `getLogger()` on `ManagedClient`. Uses `NullLogger` by default.
27+
- **PSR-16 Cache management.** `setCache(?CacheInterface)` / `getCache()` on `ManagedClient`. `invalidateCache(NodeId|string)` and `flushCache()` are forwarded to the daemon's underlying `Client` via IPC.
28+
- **`useCache` parameter** added to `browse()`, `browseAll()`, `getEndpoints()`, and `resolveNodeId()`. Forwarded to the daemon to control cache behaviour per-call.
29+
- **`getExtensionObjectRepository()`** returns a local `ExtensionObjectRepository` instance on `ManagedClient`.
30+
- **`discoverDataTypes(?int $namespaceIndex, bool $useCache)`** — forwarded to the daemon's `Client` to discover and register dynamic codecs for server-defined structured types.
31+
- **`transferSubscriptions(int[] $subscriptionIds, bool $sendInitialValues)`** — transfer existing subscriptions to a new session after reconnection without data loss. Returns `TransferResult[]`.
32+
- **`republish(int $subscriptionId, int $retransmitSequenceNumber)`** — re-request notifications that were sent but not yet acknowledged.
33+
- `psr/log` ^3.0 and `psr/simple-cache` ^3.0 added as dependencies.
34+
- `TypeSerializer` now serializes/deserializes all new v3.0.0 DTO types: `SubscriptionResult`, `MonitoredItemResult`, `CallResult`, `BrowseResultSet`, `PublishResult`, `BrowsePathResult`, `BrowsePathTarget`, `TransferResult`.
35+
- Unit tests for all new DTO serialization roundtrips (SubscriptionResult, MonitoredItemResult, CallResult, BrowseResultSet, PublishResult, BrowsePathResult, TransferResult).
36+
- Unit tests for Variant multi-dimensional dimensions preservation.
37+
- Unit tests for `ManagedClient` Logger, Cache, and ExtensionObjectRepository configuration.
38+
- Unit tests for new setter rejection (`setLogger`, `setCache` blocked via method whitelist).
39+
- **Daemon-side PSR-3 logging.** The daemon now uses a `StreamLogger` (PSR-3 compliant) instead of `echo`. Configure via `--log-file` (default: stderr) and `--log-level` (default: info). The same logger is injected into each OPC UA `Client` created by the daemon, so client-level events (connections, retries, errors) are captured in the daemon's log output.
40+
- **Daemon-side cache configuration.** The daemon's `Client` instances now accept a configurable PSR-16 cache driver. Configure via `--cache-driver` (`memory`, `file`, `none`), `--cache-path` (required for file driver), and `--cache-ttl` (default: 300s). Browse, resolve, endpoint discovery, and type discovery results are cached inside the daemon.
41+
- `StreamLogger` class (`src/Logging/StreamLogger.php`) — minimal PSR-3 logger that writes to a file or stream with configurable minimum log level and `{placeholder}` interpolation.
42+
- **Automatic session recovery with subscription transfer.** When a `query` operation fails with `ConnectionException`, the daemon automatically attempts to reconnect, transfer active subscriptions to the new session via `transferSubscriptions()`, and republish unacknowledged notifications. If recovery succeeds, the original operation is retried transparently. Subscriptions that fail to transfer are removed from tracking. All recovery events are logged.
43+
- `Session` now tracks active subscription IDs. `addSubscription()`, `removeSubscription()`, `getSubscriptionIds()`, `hasSubscriptions()` methods added. Subscriptions are automatically tracked on `createSubscription` and untracked on successful `deleteSubscription`.
44+
- Fixed `getEndpoints()` returning raw arrays instead of `EndpointDescription[]` objects.
45+
- Fixed `republish()` returning `publishTime` as ISO 8601 string instead of `?DateTimeImmutable`.
46+
- Fixed `serializeEndpointDescription()` not including the `serverCertificate` field.
47+
48+
### Breaking Changes
49+
50+
- All service response methods listed above now return typed objects instead of arrays. Code using `$result['key']` must change to `$result->key`.
51+
- Browse methods no longer accept `int $nodeClassMask`. Use `array $nodeClasses` with `NodeClass` enum values instead. Replace `nodeClassMask: 3` with `nodeClasses: [NodeClass::Object, NodeClass::Variable]`.
52+
- `readMulti($items)` renamed to `readMulti($readItems)`, `writeMulti($items)` to `writeMulti($writeItems)`, `createMonitoredItems(..., $items)` to `createMonitoredItems(..., $monitoredItems)`. Only affects code using named parameters.
53+
354
## [2.0.0] - 2026-03-20
455

556
### Changed

CODE_OF_CONDUCT.md

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
# Contributor Covenant Code of Conduct
2+
3+
## Our Pledge
4+
5+
In the interest of fostering an open and welcoming environment, we as
6+
contributors and maintainers pledge to making participation in our project and
7+
our community a harassment-free experience for everyone, regardless of age, body
8+
size, disability, ethnicity, gender identity and expression, level of experience,
9+
education, socio-economic status, nationality, personal appearance, race,
10+
religion, or sexual identity and orientation.
11+
12+
## Our Standards
13+
14+
Examples of behavior that contributes to creating a positive environment
15+
include:
16+
17+
* Using welcoming and inclusive language
18+
* Being respectful of differing viewpoints and experiences
19+
* Gracefully accepting constructive criticism
20+
* Focusing on what is best for the community
21+
* Showing empathy towards other community members
22+
23+
Examples of unacceptable behavior by participants include:
24+
25+
* The use of sexualized language or imagery and unwelcome sexual attention or
26+
advances
27+
* Trolling, insulting/derogatory comments, and personal or political attacks
28+
* Public or private harassment
29+
* Publishing others' private information, such as a physical or electronic
30+
address, without explicit permission
31+
* Other conduct which could reasonably be considered inappropriate in a
32+
professional setting
33+
34+
## Our Responsibilities
35+
36+
Project maintainers are responsible for clarifying the standards of acceptable
37+
behavior and are expected to take appropriate and fair corrective action in
38+
response to any instances of unacceptable behavior.
39+
40+
Project maintainers have the right and responsibility to remove, edit, or
41+
reject comments, commits, code, wiki edits, issues, and other contributions
42+
that are not aligned to this Code of Conduct, or to ban temporarily or
43+
permanently any contributor for other behaviors that they deem inappropriate,
44+
threatening, offensive, or harmful.
45+
46+
## Scope
47+
48+
This Code of Conduct applies both within project spaces and in public spaces
49+
when an individual is representing the project or its community. Examples of
50+
representing a project or community include using an official project e-mail
51+
address, posting via an official social media account, or acting as an appointed
52+
representative at an online or offline event. Representation of a project may be
53+
further defined and clarified by project maintainers.
54+
55+
## Enforcement
56+
57+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
58+
reported by contacting the project team at [gianfri.aur@gmail.com](mailto:gianfri.aur@gmail.com). All
59+
complaints will be reviewed and investigated and will result in a response that
60+
is deemed necessary and appropriate to the circumstances. The project team is
61+
obligated to maintain confidentiality with regard to the reporter of an incident.
62+
Further details of specific enforcement policies may be posted separately.
63+
64+
Project maintainers who do not follow or enforce the Code of Conduct in good
65+
faith may face temporary or permanent repercussions as determined by other
66+
members of the project's leadership.
67+
68+
## Attribution
69+
70+
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71+
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
72+
73+
[homepage]: https://www.contributor-covenant.org

0 commit comments

Comments
 (0)