deter-consulting/lexoffice-bundle
Laravel bundle for integrating with the lexoffice API. Provides a structured foundation to connect your app to lexoffice services, helping you authenticate, make API requests, and build features around invoices, contacts, and accounting data.
Installation
composer require deter-consulting/lexoffice-bundle
Register the bundle in config/bundles.php:
return [
DeterConsulting\LexOfficeBundle\LexOfficeBundle::class => ['all' => true],
];
Publish Configuration
php artisan vendor:publish --provider="DeterConsulting\LexOfficeBundle\LexOfficeBundle" --tag="config"
Update config/lexoffice.php with your LexOffice API credentials:
return [
'client_id' => env('LEXOFFICE_CLIENT_ID'),
'client_secret' => env('LEXOFFICE_CLIENT_SECRET'),
'account_id' => env('LEXOFFICE_ACCOUNT_ID'),
'base_uri' => env('LEXOFFICE_BASE_URI', 'https://api.lexoffice.com'),
];
First Use Case: Fetch a Customer
Inject the LexOfficeClient service into a controller or service:
use DeterConsulting\LexOfficeBundle\Client\LexOfficeClient;
public function __construct(private LexOfficeClient $lexOffice)
{
}
public function showCustomer($id)
{
$customer = $this->lexOffice->customers()->find($id);
return response()->json($customer);
}
Resource Management Use the fluent API for common operations:
// Create a customer
$customer = $this->lexOffice->customers()->create([
'name' => 'John Doe',
'email' => 'john@example.com',
'address' => '123 Main St',
]);
// Fetch all invoices for a customer
$invoices = $this->lexOffice->invoices()
->where('customer_id', $customer->id)
->all();
// Update an invoice status
$invoice = $this->lexOffice->invoices()->find($invoiceId);
$invoice->update(['status' => 'sent']);
Event-Driven Integrations
Listen to LexOffice webhook events using Laravel's Messenger:
// config/lexoffice.php
'webhooks' => [
'invoice_created' => 'https://your-app.com/lexoffice/webhooks/invoice',
'payment_received' => 'https://your-app.com/lexoffice/webhooks/payment',
],
// routes/web.php
Route::post('/lexoffice/webhooks/invoice', [LexOfficeWebhookController::class, 'handleInvoice']);
Data Synchronization Sync local models with LexOffice resources:
public function syncCustomers()
{
$lexOfficeCustomers = $this->lexOffice->customers()->all();
foreach ($lexOfficeCustomers as $customer) {
Customer::updateOrCreate(
['lexoffice_id' => $customer->id],
$customer->toArray()
);
}
}
Batch Operations Process large datasets efficiently:
$this->lexOffice->invoices()->paginate(100)->each(function ($invoice) {
// Process each invoice (e.g., update local records)
});
Service Provider Extensions
Override or extend bundle services in your AppServiceProvider:
public function register()
{
$this->app->extend('lexoffice.client', function ($client) {
$client->setCustomHeader('X-Custom-Header', 'value');
return $client;
});
}
Command Integration Create custom Artisan commands for LexOffice operations:
use Illuminate\Console\Command;
use DeterConsulting\LexOfficeBundle\Client\LexOfficeClient;
class SyncInvoicesCommand extends Command
{
protected $signature = 'lexoffice:sync-invoices';
protected $description = 'Sync invoices from LexOffice';
public function handle(LexOfficeClient $lexOffice)
{
$invoices = $lexOffice->invoices()->all();
// Process invoices...
}
}
API Resource Transformation Transform LexOffice API responses into Eloquent resources:
use Illuminate\Http\Resources\Json\JsonResource;
class LexOfficeInvoiceResource extends JsonResource
{
public function toArray($request)
{
return [
'id' => $this->id,
'number' => $this->number,
'amount' => $this->amount,
'due_date' => $this->due_date,
'customer' => new LexOfficeCustomerResource($this->customer),
];
}
}
Authentication Issues
$client = $this->app->make(LexOfficeClient::class);
if (!$client->isAuthenticated()) {
$client->refreshToken();
}
Rate Limiting
Invoice::all()->each(function ($invoice) {
SyncInvoiceJob::dispatch($invoice);
});
Data Mismatches
$lexOfficeData = $this->lexOffice->invoices()->find($id);
$localData = (new InvoiceMapper())->toLocal($lexOfficeData);
Webhook Delays
Laravel Horizon:
public function handleWebhook(Request $request)
{
try {
// Process webhook
} catch (\Exception $e) {
WebhookFailedJob::dispatch($request->all());
}
}
Enable API Logging
Configure the LexOfficeClient to log requests/responses:
$client = $this->app->make(LexOfficeClient::class);
$client->setDebug(true); // Enable logging
Inspect Raw Responses
Use Laravel's tap to debug API responses:
$invoice = $this->lexOffice->invoices()->find($id)->tap(function ($invoice) {
\Log::debug('Raw response:', $invoice->rawResponse);
});
Handle Undocumented Fields LexOffice API may return unexpected fields. Use a flexible approach:
$data = $this->lexOffice->invoices()->find($id)->toArray();
$localData = array_intersect_key($data, array_flip(['id', 'number', 'amount']));
Base URI Overrides Override the default LexOffice API URI in config:
'base_uri' => env('LEXOFFICE_BASE_URI', 'https://api.lexoffice.com'),
Custom Headers Add custom headers to all requests:
$client = $this->app->make(LexOfficeClient::class);
$client->setDefaultHeaders([
'X-Custom-Header' => 'value',
'Authorization' => 'Bearer ' . $this->getToken(),
]);
Timeout Settings Adjust request timeouts:
$client = $this->app->make(LexOfficeClient::class);
$client->setTimeout(30); // 30 seconds
Custom Resources Extend the bundle's resource classes:
namespace App\LexOffice;
use DeterConsulting\LexOfficeBundle\Resources\Invoice;
class CustomInvoice extends Invoice
{
public function getCustomField()
{
return $this->custom_field ?? null;
}
}
Event Listeners Listen to LexOffice events:
use DeterConsulting\LexOfficeBundle\Events\InvoiceCreated;
event(new InvoiceCreated($invoice));
API Client Extensions
Extend the LexOfficeClient for custom endpoints:
$client->extend('custom', function () {
return new CustomLexOfficeClient($this->httpClient);
});
Caching Responses Cache frequent API calls:
$customer = Cache::remember("lexoffice.customer.{$id}", now()->addHours(1), function () use ($id) {
return $this->lexOffice->customers()->find($id);
});
Batch Processing Use chunking for large datasets:
$this->lexOffice
How can I help you explore Laravel packages today?