PHPackages                             traindown/traindown-php - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. traindown/traindown-php

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

traindown/traindown-php
=======================

PHP Library for the Traindown Markup Language

01[1 issues](https://github.com/rbarden/traindown-php/issues)PHP

Since Mar 7Pushed 5y ago2 watchersCompare

[ Source](https://github.com/rbarden/traindown-php)[ Packagist](https://packagist.org/packages/traindown/traindown-php)[ RSS](/packages/traindown-traindown-php/feed)WikiDiscussions master Synced 1w ago

READMEChangelogDependenciesVersions (1)Used By (0)

traindown-php
=============

[](#traindown-php)

Traindown is a [Markdown](https://daringfireball.net/projects/markdown/) inspired language that helps athletes easily document their training.

See [the website](https://traindown.com/) for more information and how to use it from a user's perspective.

**Version**: this library currently aims to support v1.2.1 of the [specification.](https://github.com/traindown/spec)

Work In Progress
----------------

[](#work-in-progress)

Please understand that this library is still a work in progress and right now only implements the spec and some basic functions to access the resulting data. There aren't even tests for it yet.

There are most certainly still bugs to be worked out.

Future releases will contain more functionality to access the resulting data as well as transform it into other formats, such as JSON.

Installation
------------

[](#installation)

```
composer install traindown/traindown-php

```

Right now, the only requirements are PHP &gt; 8.0 and the Mbstring extension. **This is not set in stone.**

Use
---

[](#use)

Basic usage is fairly straight forward:

```
$file = '
@ 2021-01-01

* This is an example note!

# example metadata key: value

Bench Press:
  500
';

$parser = new Parser();
$document = $parser->parse($file);

foreach($document->getSessions() as $session) {
    // do something...
}
```

You can run `$parser->parse($file)` on multiple files without instantiating a new `Parser`. The internal state will reset on each call.

### Errors

[](#errors)

In the basic setup, unknown and unexpected tokens are silently ignored and the parser will continue with the rest of the document. These bad tokens are accessible on the `Parser` object itself:

```
$parser->hasBadTokens(); // bool
$parser->getBadTokens(); // array of the bad tokens
```

For example, when parsing the string `bw+25a`, two tokens are generated: a `T_LOAD` with a value of 'bw+25' and a `T_UNKNOWN` with a value of 'a'. This follows the spec for bodyweight loads, but does differ in behavior from the JS implementation which would accept the 'a' as part of the bodyweight value.

If you would rather an exception be thrown, pass `true` when instantiating the `Parser` and any bad token will immediately throw a `BadTokenException`.

```
$file = '
# Bad metadata
';

$parser = new Parser(true);

$document = $parser->parse($file); // Throws BadTokenException
```

The `BadTokenException` holds the token in question. If the token is `TokenType::T_UNKNOWN`, this it is an 'unknown' token, unrecognizable to the lexer. If the token is any other type, it is an 'unexpected' token, appearing in a place where it should not.

### The Traindown Objects

[](#the-traindown-objects)

This library parses the traindown string into a series of traindown objects from the `Traindown\Traindown` namespace.

Think of it like a tree where the `Document` is the root. This contains `Sessions` which contains `Movements` which contains `Performances`. All of those have metadata in the form of both `Notes` (single string comments) as well as `Data` (key-value pairs, referred to as "metadata" in the spec) and their respective getters and setters through the `HasMetadata` trait.

#### Document

[](#document)

The `Document` has these methods:

```
$document->getSessions(); // array of Session

$document->addSession(Session $session); // to add a single Session
```

#### Session

[](#session)

The `Session` has these methods:

```
$session->getDate(); // DateTime
$session->hasDefaultDate(); // bool, true if date failed to parse
$session->getMovements(); // array of Movement

$session->setDatetime(Token $token); // Takes a Token of TokenType::T_DATETIME
$session->addMovement(Movement $movement); // to add a single Movement
```

The value of the T\_DATETIME passed in (and thus what your users can enter in their documents) is simply parsed by `new DateTime($value)` and is therefore very forgiving. For a refresher on what formats are accepted, see [the manual.](https://www.php.net/manual/en/datetime.formats.php)If a value cannot be properly rendered, then a datetime of `now` is set and the `defaultDate` property is set to true.

#### Movement

[](#movement)

The `Movement` has these methods:

```
$movement->getName(); // string
$movement->isSuperset(); // bool
$movement->getSequence(); // int
$movement->getPerformances(); // array of Performance

$movement->addPerformance(Performance $performance); // to add a single Performance
```

The constructor for a `Movement` takes in a `TokenType::T_MOVEMENT` and a sequence number to determine its order in the document.

#### Performance

[](#performance)

The `Performance` has these methods:

```
$performance->getLoad(); // ?float, default is null because it must be set
$performance->getReps(); // float, defaults to 1 if not set
$performance->getSets(); // float, defaults to 1 if not set
$performance->getFails(); // float, defaults to 0 if not set
$performance->getRaw(string $prop); // ?float, returns the property without default value, good for checking if a prop was manually set or not.

$performance->isValid(); // bool, returns true if load has been set

$performance->setLoad(Token $token); // Takes a token of TokenType::T_LOAD
$performance->setReps(Token $token); // Takes a token of TokenType::T_REPS
$performance->setSets(Token $token); // Takes a token of TokenType::T_SETS
$performance->setFails(Token $token); // Takes a token of TokenType::T_FAILS
```

### Data

[](#data)

The `Data` (referred to as metadata in the spec) has these methods:

```
$data->getKey(); // string
$data->getValue(); // string
$data->getDataPair(); // [$key => $value]
```

The constructor for a `Data` takes in a token of `TokenType::T_METADATA`.

#### Note

[](#note)

The `Note` has these methods:

```
$note->getValue(); // string
```

The constructor for a `Note` takes in a token of `TokenType::T_NOTE`.

###  Health Score

16

—

LowBetter than 5% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity1

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity30

Early-stage or recently created project

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

### Community

Maintainers

![](https://www.gravatar.com/avatar/888999240fa89d1798f226f90369df4f98cddfd5cb178d61eaaf86b59a7e5dc0?d=identicon)[rbarden](/maintainers/rbarden)

---

Top Contributors

[![rbarden](https://avatars.githubusercontent.com/u/11159294?v=4)](https://github.com/rbarden "rbarden (2 commits)")

### Embed Badge

![Health badge](/badges/traindown-traindown-php/health.svg)

```
[![Health](https://phpackages.com/badges/traindown-traindown-php/health.svg)](https://phpackages.com/packages/traindown-traindown-php)
```

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
