Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Youtrack Php Sdk Laravel Package

cybercog/youtrack-php-sdk

PHP SDK for the JetBrains YouTrack REST API. Provides typed models, resource clients, and authentication helpers so you can query issues, projects, users, and workflows from any PHP or Laravel app without hand-writing HTTP calls or parsing raw JSON.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and pin deliberately. composer require cybercog/youtrack-php-sdk — note this is a framework-agnostic SDK, not a Laravel package: there is no service provider, no publishable config, no facade. Everything below is wiring you own.

Where to look first on 5.0.0. The release notes for 5.0.0 are only a Full Changelog link to 4.0.2...5.0.0, so the diff is the documentation. Before adopting it:

  1. composer why-not cybercog/youtrack-php-sdk 5.0.0 — confirms nothing (PHP version, PSR-18/PSR-17 constraints, Guzzle adapter) is blocking you.
  2. Diff src/Connection.php (constructor signature, token/auth handling) and src/Exception/ (renamed or removed exception classes) — those two are what a Laravel app actually touches.
  3. Grep your own codebase for every SDK symbol you call. Major bumps in this SDK have historically dropped deprecated aliases and raised the minimum PHP/PSR versions, so the "breaking" part is usually method removal, not new API surface.

Keep ^4 in composer.json until that grep is clean; there is no upgrade guide to lean on.

Configure it like any other credential.

// config/services.php
'youtrack' => [
    'url'   => env('YOUTRACK_URL'),   // https://example.youtrack.cloud
    'token' => env('YOUTRACK_TOKEN'), // permanent token, not a password
],
// AppServiceProvider::register()
$this->app->scoped(Connection::class, fn () => new Connection(
    config('services.youtrack.url'),
    config('services.youtrack.token'),
));

Prefer scoped() over singleton() — see Gotchas for Octane.

First real use case: turn exceptions into tracked issues. This is the highest-value, lowest-risk entry point and exercises auth, write, and error handling in one go:

// bootstrap/app.php -> withExceptions()
->report(function (Throwable $e) {
    if ($this->app->runningInConsole() && ! $this->app->runningUnitTests()) {
        App\Jobs\ReportExceptionToYouTrack::dispatch($e::class, $e->getMessage(), $e->getTraceAsString());
    }
})

Queue it, dedupe it, and you have a working integration before you touch any read path.

Implementation Patterns

Wrap, don't sprinkle. Do not inject Connection into controllers. Put a thin adapter between your app and the SDK:

interface IssueTracker { public function open(string $project, string $summary, string $body): string; }

final class YouTrackIssueTracker implements IssueTracker { /* holds Connection */ }

You get three things: the 5.0.0 → 6.0.0 upgrade becomes a one-file change, tests bind a fake against your interface, and you can enforce policy (redaction, project allow-list, rate budget) in one place.

Multi-instance / multi-tenant. If you talk to more than one YouTrack (per-customer instance, or a staging and prod pair), a single global singleton is wrong. Use a factory keyed by tenant and a scoped binding so the right token is resolved per request/job:

$this->app->scoped(Connection::class, fn () => $this->app->make(YouTrackFactory::class)
    ->for(config('services.youtrack.url'), config('services.youtrack.token')));

Writes belong on the queue. YouTrack round-trips are tens-to-hundreds of milliseconds and the API will 5xx occasionally. Pattern: listener/job with $tries = 3, backoff([5, 30, 120]), and ShouldBeUnique keyed on a hash of the payload so a retried webhook doesn't create duplicate issues. Carry a dedupe string into the issue description/tag rather than relying on the API for idempotency.

Reads belong in the cache. Project metadata, custom-field schemas, saved queries, and user lists change on the scale of weeks:

$fields = Cache::remember("youtrack:project:{$id}:fields", now()->addHour(), fn () => $client->projectFields($id));

Cache the transformed array, not the SDK's response objects — the object graph is not necessarily serializable across versions.

Inbound webhooks. YouTrack workflow JS can POST to a Laravel route on state change. There's no native signature, so put a shared secret in a header, compare with hash_equals(), and keep the route outside web middleware (no CSRF). Acknowledge with 200 before dispatching work.

Testing. The SDK speaks PSR-18, so swap the HTTP client for a mock rather than faking at the Laravel Http layer (your code never goes through Http). Easiest sustainable approach: assert against your IssueTracker interface; exercise the real adapter in a single integration test against a throwaway YouTrack project, tagged @group integration and skipped in CI without credentials.

Gotchas and Tips

No default timeout. Left unset, a stalled YouTrack will block a queue worker indefinitely. Pass a preconfigured Guzzle client (or any PSR-18 client with timeout/connect_timeout) and set it lower than your job's retry_after.

The fields parameter is the #1 source of "my data is empty". YouTrack returns only a minimal representation unless you explicitly ask for fields; custom fields in particular come back absent, not null. Budget time for building field-query strings, and centralise them in one class so they don't drift across call sites.

Status codes lie slightly. 403 almost always means the token's user lacks a Hub permission for that project (e.g. "Update Issue"), not that the token is invalid — that's 401. 404 is also returned when you can read the instance but cannot see the project. Log the response body; YouTrack puts the useful part there.

IDs and custom fields are not scalars. PROJ-123 (readable id) and the internal numeric id are different fields; custom-field values are objects with a $type discriminator and a value/name/id inside. Write one CustomFieldValue::scalar() helper early rather than sprinkling $v['value']['name'] ?? null.

Never put the Connection on a queued job or in a service that outlives the request. It carries a bearer token. With Octane, a singleton will leak one tenant's token into another tenant's request — use scoped, and never resolve it inside a config:cache-time closure.

Don't log request dumps. The SDK's underlying client will happily log the Authorization header if you attach a generic logging middleware; scrub it or log at info with the header list filtered.

Escape user content in descriptions. YouTrack renders Markdown and auto-links PROJ-123; unescaped user input becomes broken formatting or accidental issue cross-references.

Extension points, ranked by usefulness: (1) the PSR-18 client — retries, timeouts, logging; (2) a wrapper class — policy and mapping; (3) extending Connection — last resort, it makes the 5.x→6.x diff land in your subclass instead of your adapter.

On the 5.0.0 upgrade itself: treat it as an unverified major. Branch, bump, run PHPStan at your existing level (renamed/removed methods are exactly what static analysis catches for free), run the integration suite against a sandbox project, then merge. If anything is unclear, the 4.0.2...5.0.0 compare view is the only authoritative record — there is no release narrative to fall back on.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
socialdept/atp-orm
cboxdk/laravel-assistant-client
socialdept/atp-resolver
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin