Download the PHP package chemaclass/edifact-parser without Composer
On this page you can find all versions of the php package chemaclass/edifact-parser. It is possible to download/install these versions without Composer. Possible dependencies are resolved automatically.
Download chemaclass/edifact-parser
More information about chemaclass/edifact-parser
Files in chemaclass/edifact-parser
Package edifact-parser
Short Description An EDIFACT file parser to extract the values from any defined segment
License MIT
Informations about the package edifact-parser
π¦ EDIFACT Parser
A complete PHP toolkit for UN/EDIFACT β read, write, validate, and stream EDI interchanges with a typed, object-oriented API.
EDIFACT β Electronic Data Interchange For Administration, Commerce, and Transport β is the international standard for structured business documents (orders, invoices, despatch advices, transport instructions). π New to it? Start here.
Why this library
- π₯ Parse any interchange β unknown tags degrade gracefully to raw values, so no message type is unsupported.
- π€ Write it back β serialize segments to a valid
.edistring, or assemble a fullUNBβ¦UNZinterchange with auto-computed control counts. - β Validate β pluggable rule sets for required segments, cardinality, and order.
- π Stream β parse multi-gigabyte files in bounded memory (one message at a time).
- π§± Model the full envelope β interchange β functional groups (
UNG/UNE) β messages, with duplicate-preserving access and typed metadata on every envelope segment. - π·οΈ 32 typed segments out of the box with domain accessors, plus qualifier constants β or 134 with the directory bundle, and trivially extensible with your own.
- π Directory-aware β validate elements, lengths, representations and code lists against
the real UN/EDIFACT directories, and group messages into their actual nested segment
groups (
SG1β¦SGn) rather than a heuristic. - π₯οΈ CLI included β
edifact parse|inspect|validate|segments, JSON on stdout, documented exit codes. - π©Ί Structured diagnostics β stable codes and positions across parsing and validation, so failures are matched on, not string-searched.
- π Fluent query API and a statistics analyzer for extracting data. Results,
messages, line items and queries are all
Countableanditerable, and any of them dumps to plain arrays or JSON. - π Charset-aware (
UNOAβ¦UNOY), strictly typed (PHP 8.0+, PSR-4), and fully covered by PHPUnit, PHPStan, Psalm, Rector and PHP-CS-Fixer.
Table of Contents
- Upgrading from 6.x
- Command line
- Quick Start
- Streaming large files
- Built-in segments
- Writing EDIFACT
- Validation
- Extending
- Debugging
- Development
- Contributing
For AI coding agents: docs/llms/. Every snippet there
is backed by a runnable file under example/ that CI executes.
πΎ Installation
Requires PHP 8.0+ with ext-json and ext-mbstring.
π Quick Start
The parser never throws on unknown segments β they become UnknownSegments you can still
read via rawValues(), so you can process any interchange and add typed segments later.
π₯ Parsing
EdifactParser::parse() / parseFile() return a ParserResult:
A message starts at UNH and ends at UNT; an interchange wraps messages between
UNB and UNZ, optionally grouped by UNG/UNE. Invalid input throws
InvalidFile.
Choosing a tokenizer
Turning raw text into segments is pluggable. NativeTokenizer is the default β a
regex-free single-pass scanner, ~1.8Γ faster at tokenizing (~1.3Γ on parse() overall),
and it never rewrites the bytes it reads:
SabasTokenizer delegates to sabas/edifact, which was the default up to 6.x. It is still
available, but be aware it strips every byte in \x80-\xFF β NAD+BY+++MΓΌller comes
back as Mller:
Reach for it when you need bug-for-bug compatibility with 6.x, or want the restricted
UNOB repertoire enforced. Otherwise the default is both faster and lossless.
For ASCII input the two tokenize identically β verified segment-for-segment across the test fixtures and a generated corpus.
Streaming large files
Stream messages one at a time in bounded memory β ideal for large interchanges. A
leading UNA service-string advice (custom separators/release char) is honoured
automatically:
π₯οΈ Command line
composer require installs an edifact binary. It answers "what is in this file?" without
writing a script β and it is built for automation as much as for people:
Contract, so output can be consumed without guessing:
- data on stdout, diagnostics on stderr β never interleaved, so
| jqalways works - exit codes:
0success/valid,1invalid input,2usage error - JSON by default;
--prettyis purely cosmetic
No console framework is pulled in β a parsing library should not put one in your vendor/.
π Reading data
Typed accessors
Typed segments expose their fields as methods β self-documenting and IDE-friendly:
Every segment also exposes the raw structure when you need it:
Accessing segments
Dumping a message
toArray() / toJson() render a whole message β or a single segment β as plain data,
with context children nested. Useful for logs, snapshot tests and diffing interchanges:
Fluent query API
Chain filters and transformations over every segment (order preserved, duplicates included):
query()and$message->segments()return every segment in original order, duplicates included. The keyed lookups (segmentByTagAndSubId(),allSegments()) index by tag + subId and keep the last occurrence β use the query API when duplicates matter.
Line items
Line items group each LIN with its related detail segments (QTY, PRI, PIA, β¦) β
ideal for orders and invoices:
Hierarchical context segments
Context segments preserve parent β child relationships (e.g. NAD β CTA β COM):
Keyed lookups always hand back the typed segment, so you can go the other way too β read a segment normally, then ask the message what was grouped under it:
Interchange & envelope metadata
Every envelope segment exposes typed metadata:
Functional groups (UNG/UNE)
When an interchange wraps messages in UNGβ¦UNE groups, read them directly. Interchanges
without groups return an empty list β messages stay available flat via
transactionMessages():
Statistics & analysis
MessageAnalyzer extracts counts and aggregates:
Qualifier constants
Avoid magic strings with typed qualifier catalogs (IDE autocomplete, usable in match):
| Class | Covers |
|---|---|
NADQualifier |
Party roles β BY, SU, CN, CZ, DP, IV, PR, CA, FW, MF, UC, WH |
QTYQualifier |
Quantity types β 1, 3, 11, 12, 21, 33, 46, 47, 48, 192 |
PRIQualifier |
Price types β AAA, AAB, AAE, AAF, AAG, CAL, CT, DIS, LIS, MIN, RRP |
DTMQualifier |
Date/time types β 137, 2, 3, 4, 10, 11, 13, β¦ |
RFFQualifier |
Reference types β ON, IV, DQ, CU, SRN, CT, POR, β¦ |
Character sets
The parser reads raw bytes. Decode non-ASCII values to UTF-8 from the interchange's syntax identifier:
UNOA/UNOB β ASCII, UNOCβUNOK β ISO-8859-*, UNOY β UTF-8.
Built-in segments
32 segments are typed and registered by default (134 with
SegmentFactory::withDirectorySegments()):
- Envelope / service:
UNB,UNG,UNH,UNS,UNT,UNE,UNZ - Header:
BGM,DTM,RFF,NAD,CUX,TDT,LOC,FTX - Party / terms:
CTA,COM,PAT,PCD,TAX,TOD - Detail / summary:
LIN,PIA,IMD,QTY,PRI,MEA,PAC,GID,MOA,PCI,CNT
Any other tag parses as an UnknownSegment (readable via rawValues()); add your own typed
class in a few lines β see Extending.
π€ Writing EDIFACT
Build individual segments
Fluent, type-safe builders produce segment objects:
NADNameAddress, QTYQuantity and PRIPrice provide ::builder().
Serialize segments to a string
EdifactSerializer is the inverse of parsing β it round-trips a parsed interchange
byte-for-byte and escapes separators/release chars for you:
Assemble a full interchange
InterchangeBuilder writes a complete UNBβ¦UNZ interchange and fills in the UNT segment
counts and the UNZ control count automatically:
β Validation
Check a message against a pluggable rule set β required segments, cardinality, and relative order. The validator never throws; an empty result means the message conforms:
Ready-made rule sets for common message types are provided as starting points:
π§ Extending
Custom segments
Extend AbstractSegment and register your class. The shared accessor helpers
(element(), component(), firstComponent()) safely read simple and composite elements:
withAdditionalSegments()keeps every default and merges your tags on top β registering a custom class under a default tag overrides that default. UsewithSegments()instead when you want an explicit, closed set of segments.
Introspection
Ask the factory what it knows, instead of reading the source:
Descriptors are derived by reflection, so they cannot drift from the code.
registeredTags() and classForTag() read the map only β no class is loaded.
The shape of toArray()/toJson() is published as a JSON Schema at
schema/message.schema.json, and a test asserts the schema
still matches what a parsed message actually produces.
Composable segment bundles
The defaults are exposed as two composable bundles so you can build a lean factory
that only types the tags you care about β everything else still parses as a readable
UnknownSegment:
SegmentFactory::ENVELOPE_SEGMENTSβ the UN* service/control segments (7).SegmentFactory::BUSINESS_SEGMENTSβ header, party/terms, detail and summary (25).SegmentFactory::DEFAULT_SEGMENTSβ the union of both (32).
Custom grouping rules
Context hierarchies and line-item boundaries are driven by GroupingRules. Pass a
customized instance to change which tags open a context, attach as children, or close a
line-item section:
GroupingRules also reads back what it is configured with β contextTags(),
childTags(), breakLineItemTags() β and the defaults are exposed as
GroupingRules::DEFAULT_CONTEXT_TAGS, DEFAULT_CHILD_TAGS and
DEFAULT_BREAK_LINE_ITEM_TAGS.
More examples in extracting data, query filtering, printing segments, context segments.
π Debugging
Error handling
Structured diagnostics
Matching on English prose is fragile, so parse failures and validation failures share one type with stable codes and, where known, a position:
Codes are public API β see DiagnosticCode for the catalogue. Messages are not: they may
be reworded at any time.
π οΈ Development
CI runs the benchmarks on every pull request, measuring the base branch and the head
branch on the same runner and failing when a metric regresses beyond 1.5Γ. Absolute
timings on shared hardware mean little; ratios measured back to back do. Never change
tools/benchmark.php in a commit that also reports a performance delta β the numbers
stop being comparable.
- PHP 8.0+, strict types, PSR-4. Type hints and tests required for new functionality.
- All code must pass PHP-CS-Fixer, Psalm, PHPStan and Rector (CI is authoritative).
Local toolchain note: the pinned Psalm (
vimeo/psalm ^4.30) runs on PHP β€ 8.3 β run it under 8.3 if your CLI is newer. On PHP > 8.3, PHP-CS-Fixer needsPHP_CS_FIXER_IGNORE_ENV=1.
π€ Contributing
Contributions of all kinds are welcome β bug fixes, ideas, and improvements.
- π Report an issue
- π§ Open a pull request
π See the contributing guide to get started.
All versions of edifact-parser with dependencies
ext-mbstring Version *
php Version >=8.0
sabas/edifact Version ^1.3
webmozart/assert Version ^1.12
