amateescu / prov
PHP implementation of the W3C Provenance Data Model (PROV-DM)
Requires
- php: ^8.4
- ext-json: *
Requires (Dev)
- carthage-software/mago: ^1.24.0
- infection/infection: ^0.32.6
- openprov/testcases: 1.0.0
- phpunit/phpunit: ^12.0
Suggests
- ext-dom: Required for XmlSerializer (PROV-XML serialization and deserialization)
README
PHP implementation of the W3C Provenance Data Model (PROV-DM).
PROV-DM describes where things come from: entities (things you care about), activities (things that happen), and agents (who's responsible). Relations like wasGeneratedBy and wasAttributedTo connect them to form a provenance graph.
This library provides a fluent builder for assembling that graph, round-trip serializers for PROV-JSON, PROV-N, and PROV-XML (plus serialize-only PROV-JSON-LD), document operations (merge, flatten, semantic equality), and a partial PROV-CONSTRAINTS validator.
Requirements
- PHP 8.4+
ext-dom(only if you useXmlSerializer)
Installation
composer require amateescu/prov
Quick start
use Prov\Format; use Prov\Prov; $builder = Prov::documentBuilder(); $builder->namespace('ex', 'http://example.org/'); $builder->entity('ex:article'); $builder->activity('ex:writing', startTime: new DateTimeImmutable('2024-01-15')); $builder->agent('ex:alice'); $builder->wasGeneratedBy(entity: 'ex:article', activity: 'ex:writing'); $builder->wasAssociatedWith(activity: 'ex:writing', agent: 'ex:alice'); $doc = $builder->build(); $json = Prov::serialize($doc, Format::Json); echo $json; // Other formats: Format::ProvN, Format::Xml, Format::JsonLd. $parsed = Prov::deserialize($json, Format::Json);
Always pass relation arguments by name. PROV-DM fixes a per-relation positional order that does not follow subject-before-object.
wasGeneratedBytakes(entity, activity)butusedtakes(activity, entity): the two sit in opposite orders even though they connect the same two records. Positional calls silently invert the relation:// These two lines describe DIFFERENT facts, even though both identifiers are the same: $builder->wasGeneratedBy('ex:article', 'ex:writing'); // article wasGeneratedBy writing ✓ $builder->used('ex:article', 'ex:writing'); // article used writing ✗ (reversed) // Always use named arguments: $builder->wasGeneratedBy(entity: 'ex:article', activity: 'ex:writing'); $builder->used(activity: 'ex:writing', entity: 'ex:article');
Format support
| Format | Serialize | Deserialize |
|---|---|---|
| PROV-JSON | yes | yes |
| PROV-N | yes | yes |
| PROV-XML | yes | yes |
| PROV-JSON-LD | yes | no (would require an RDF-aware parser) |
Document operations
use Prov\Operation\DocumentOperations; use Prov\Operation\DocumentComparator; $merged = DocumentOperations::merge($docA, $docB); $flat = DocumentOperations::flatten($docWithBundles); // throws if Mentions present $flat = DocumentOperations::flattenDroppingMentions($docWithBundles); DocumentComparator::equals($a, $b); // structural (semantic) equality
Validation
$result = Prov::validate($document); if (!$result->isValid()) { foreach ($result->getViolations() as $violation) { echo "[C{$violation->constraintId}] {$violation->message}\n"; } } // Or throw if the document has any violations: Prov::validate($document)->throwIfInvalid(); // raises ConstraintViolationException
Coverage is partial: rules that need transitive graph reasoning over derivation chains aren't implemented, so isValid() === true only means no checked rule was violated. Use ConstraintValidator::implementedConstraints() or ::unsupportedConstraints() to see the exact set.
Builder tips
Blank nodes (anonymous records):
$e = $builder->blank(); // _:b1 $builder->entity($e); $builder->wasGeneratedBy(entity: $e, activity: 'ex:writing');
Bundles:
$builder ->entity('ex:e1') ->withBundle('ex:b1', fn ($b) => $b ->entity('ex:e2') ->wasGeneratedBy(entity: 'ex:e2', activity: 'ex:a1')) ->build();
DocumentBuilder::build() and BundleBuilder::build() are single-use; a second call throws LogicException.
Learn more
Every public class carries an inline docblock explaining what it's for. The most useful starting points:
Prov\Prov: the facade used in the examples aboveProv\Builder\DocumentBuilder: the full set of record and relation methodsProv\Format: supported serialization formatsProv\Constraint\ConstraintValidator: what each PROV-CONSTRAINTS rule checks
Development
Before submitting a PR, run composer check (format, lint, analyze, tests).
License
This library is made available under the MIT License. Please see LICENSE for more information.