Files
Additional/app/Services/TrelloService.php
T
twotalesanimation ca7d16da16 feat: Add Trello configuration fallback and test command
- Add fallback env parsing directly from .env file in config/trello.php
- Fixes issue where cached config prevents env() from reading .env values
- Add artisan trello:test command to diagnose Trello configuration
- Test command checks API credentials, board/list IDs, and connectivity
- Test successfully creates and moves a test Trello card
2026-01-02 15:36:27 +02:00

223 lines
6.2 KiB
PHP

<?php
namespace App\Services;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
class TrelloService
{
protected string $apiKey;
protected string $apiToken;
protected string $boardId;
protected string $baseUrl = 'https://api.trello.com/1';
public function __construct()
{
$this->apiKey = config('trello.api_key');
$this->apiToken = config('trello.api_token');
$this->boardId = config('trello.board_id');
}
/**
* Create a new card on the board
*/
public function createCard(string $orderId, string $orderNumber, string $orderType = 'standard', ?string $startingListId = null): ?string
{
if (! $this->isConfigured()) {
Log::warning('Trello not configured, skipping card creation', [
'order_id' => $orderId,
'api_key' => $this->apiKey ? 'set' : 'empty',
'api_token' => $this->apiToken ? 'set' : 'empty',
'board_id' => $this->boardId ? 'set' : 'empty',
]);
return null;
}
try {
$listId = $startingListId ?? $this->getStartingListId($orderType);
$response = Http::post("{$this->baseUrl}/cards", [
'name' => "Order #{$orderNumber}",
'desc' => "Order ID: {$orderId}\nType: {$orderType}",
'idList' => $listId,
'key' => $this->apiKey,
'token' => $this->apiToken,
]);
if ($response->successful()) {
$data = $response->json();
return $data['id'] ?? null;
}
Log::error('Failed to create Trello card', ['response' => $response->body()]);
return null;
} catch (\Exception $e) {
Log::error('Exception creating Trello card', ['error' => $e->getMessage()]);
return null;
}
}
/**
* Move a card to a different list
*/
public function moveCard(string $cardId, string $listName): bool
{
if (! $this->isConfigured()) {
return false;
}
try {
$listId = $this->getListIdByName($listName);
if (! $listId) {
Log::warning('Trello list not found', ['list_name' => $listName]);
return false;
}
$response = Http::put("{$this->baseUrl}/cards/{$cardId}", [
'idList' => $listId,
'key' => $this->apiKey,
'token' => $this->apiToken,
]);
return $response->successful();
} catch (\Exception $e) {
Log::error('Exception moving Trello card', [
'card_id' => $cardId,
'error' => $e->getMessage(),
]);
return false;
}
}
/**
* Attach a file or URL to a card
*/
public function attachFile(string $cardId, string $fileName, string $fileUrl): bool
{
if (! $this->isConfigured()) {
return false;
}
try {
$response = Http::post("{$this->baseUrl}/cards/{$cardId}/attachments", [
'name' => $fileName,
'url' => $fileUrl,
'key' => $this->apiKey,
'token' => $this->apiToken,
]);
return $response->successful();
} catch (\Exception $e) {
Log::error('Exception attaching file to Trello card', [
'card_id' => $cardId,
'error' => $e->getMessage(),
]);
return false;
}
}
/**
* Check/tick a checklist item on a card
*/
public function checkItem(string $cardId, string $checklistName, string $itemName): bool
{
if (! $this->isConfigured()) {
return false;
}
try {
// Fetch card to find checklist
$cardResponse = Http::get("{$this->baseUrl}/cards/{$cardId}", [
'key' => $this->apiKey,
'token' => $this->apiToken,
'checklists' => 'open',
]);
if (! $cardResponse->successful()) {
return false;
}
$checklists = $cardResponse->json('checklists') ?? [];
$checklist = collect($checklists)->firstWhere('name', $checklistName);
if (! $checklist) {
Log::warning('Trello checklist not found', ['checklist_name' => $checklistName]);
return false;
}
$checklistId = $checklist['id'];
$item = collect($checklist['checkItems'])->firstWhere('name', $itemName);
if (! $item) {
Log::warning('Trello checklist item not found', ['item_name' => $itemName]);
return false;
}
$response = Http::put("{$this->baseUrl}/checklists/{$checklistId}/checkItems/{$item['id']}", [
'state' => 'complete',
'key' => $this->apiKey,
'token' => $this->apiToken,
]);
return $response->successful();
} catch (\Exception $e) {
Log::error('Exception checking Trello item', [
'card_id' => $cardId,
'error' => $e->getMessage(),
]);
return false;
}
}
/**
* Get starting list ID for order type
*/
protected function getStartingListId(string $orderType): string
{
if ($orderType === 'custom') {
return config('trello.lists.custom.new_custom_order');
}
return config('trello.lists.standard.new_order');
}
/**
* Get list ID by name (from config)
*/
protected function getListIdByName(string $listName): ?string
{
$lists = array_merge(
config('trello.lists.standard', []),
config('trello.lists.custom', [])
);
foreach ($lists as $key => $id) {
if (str_replace('_', ' ', ucfirst($key)) === $listName) {
return $id;
}
}
return null;
}
/**
* Check if Trello is configured
*/
protected function isConfigured(): bool
{
return ! empty($this->apiKey) && ! empty($this->apiToken) && ! empty($this->boardId);
}
}