phpugl/dime-timetracker-bundle
Symfony bundle that integrates Dime time tracking into PHP applications, providing configuration and services for recording work hours, managing projects and tasks, and adding timetracking features to Symfony projects.
Before anything else, correct the framing: phpugl/dime-timetracker-bundle is a Symfony 2 bundle, not a Laravel package. It expects AppKernel registration, a services.yml file, FOSRestBundle annotation routing, and Doctrine ORM entities. There is no service provider, no facade, no config publishing, and no migrations/ directory. Running
composer require phpugl/dime-timetracker-bundle
inside a Laravel project will fail immediately on php and symfony/* constraints (Symfony 2.3–2.8, PHP 5.3–5.6). Do not spend more than five minutes on this path.
Where to look first if you are evaluating it:
composer.json — record the exact php, symfony/*, friendsofsymphony/rest-bundle, and jms/serializer constraints. This is your compatibility answer.Entity/ — the actual value: the domain model (User, Project, Activity, Timeslip). Read this before any code.Controller/ and Resources/config/routing/ — the REST surface. Count endpoints. If it's under ~15, rewriting is cheaper than integrating.Resources/config/services.yml — how the domain services are wired, useful as a checklist when you build your own.The realistic first use case is not "install it." It is a 2–4 day spike where you clone the repo and map its resource taxonomy onto Laravel migrations + Eloquent models. The thing you actually ship is your own TimeslipController, not this bundle.
The only pattern that works in a Laravel codebase is HTTP integration over a running Dime instance behind a repository interface — the bundle itself is a controller/serializer layer you can rewrite in a sprint.
Repository + DTO pattern (recommended):
interface TimeslipRepository {
public function forProject(int $projectId, CarbonImmutable $from, CarbonImmutable $to): Collection;
}
class HttpTimeslipRepository implements TimeslipRepository {
public function forProject(...) {
return Http::baseUrl(config('dime.base_url'))
->withBasicAuth(config('dime.user'), config('dime.pass'))
->get('/api/timeslips', ['project' => $projectId, ...])
->throw()
->collect('timeslips')
->map(fn ($row) => TimeslipDTO::fromDime($row));
}
}
Bind it in AppServiceProvider. Controllers and reporting jobs depend on the interface, never on Dime's payload shape. This is the Laravel equivalent of the bundle's "wiring services into the container" — except you control it.
Domain modeling pattern. Mirror the bundle's entity graph if you are building your own schema:
users — the tracker (may be external/Dime-owned)projects — belongs to a client, has many activitiesactivities — the billable categorytimeslips — belongs to user + project + activity, has duration (minutes) and dateUse integer minutes for duration and a date (not datetime) for timeslip.date; this matches Dime's semantics and avoids most timezone drift.
Service provider translation. The bundle's services.yml is effectively a list of $this->app->bind() calls. If you're forking any logic, translate one-to-one: Dime\TimeslipService → App\Services\TimeslipService, registered in AppServiceProvider. Don't try to reuse the Symfony DI config verbatim — you'll be fighting autowiring.
Sidecar pattern (only if you must run the legacy code). Deploy it in its own Symfony 2 container behind a reverse proxy, expose only the endpoints you need, and treat it as an anti-corruption layer. Your Laravel app talks to your contract via the repository above; the sidecar is swappable.
Testing. Use Http::fake() with fixtures captured from your spike against a live Dime. Record request shapes and response payloads as JSON files under tests/Fixtures/dime/. These become your contract tests — you want them to fail loudly if upstream drifts.
boot(), no register(), no artisan. There's no shim. Don't argue with the composer.json; argue with the framework choice.date columns, and write a reconciliation test that compares your aggregates against the source on a schedule. An off-by-one-hour error in a timeslip is a billing dispute, not a bug ticket.jms/serializer breaks at runtime with no contract to catch it. Consumer-driven contract tests are your only defense; add response validation in the adapter.dd()/ray() won't help. You're reading source and var_dump-ing inside a container.services.yml (wiring) — those are the two files to read carefully before any rewrite.LICENSE is unclear or absent, stop evaluation immediately; a fork without clean licensing is a legal problem, not an engineering one.Bottom line for a Laravel developer: git clone it, spend a week reading the entities and route conventions, then build the equivalent with Eloquent, Http, and a repository interface. Do not add it to composer.json — the framework mismatch alone makes that a non-starter, and the maintenance burden makes it a bad idea even if it weren't.
How can I help you explore Laravel packages today?