Advanced Usage
This page demonstrates advanced examples and use cases for the Joomla Webservices API.
Batch Operations
Creating multiple articles simultaneously
<?php
/**
* Batch article import from CSV
*/
function batchImportArticles($csvFile) {
$results = [
'success' => 0,
'failed' => 0,
'errors' => []
];
if (($handle = fopen($csvFile, 'r')) !== false) {
// Skip header row
fgetcsv($handle);
while (($row = fgetcsv($handle)) !== false) {
list($title, $intro, $fulltext, $categoryId) = $row;
try {
createArticle($title, $intro, $fulltext, $categoryId);
$results['success']++;
} catch (Exception $e) {
$results['failed']++;
$results['errors'][] = [
'title' => $title,
'error' => $e->getMessage()
];
}
// Rate limiting - wacht 100ms tussen requests
usleep(100000);
}
fclose($handle);
}
return $results;
}
?>
Pagination and Large Datasets
<?php
/**
* Retrieve all articles with pagination
*/
function getAllArticles() {
global $baseUrl, $headers;
$allArticles = [];
$offset = 0;
$limit = 50;
$hasMore = true;
while ($hasMore) {
$url = $baseUrl . "/content/articles?page[offset]=$offset&page[limit]=$limit";
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);
if (isset($data['data']) && count($data['data']) > 0) {
$allArticles = array_merge($allArticles, $data['data']);
$offset += $limit;
// Check of er meer pagina's zijn
$totalPages = $data['meta']['total-pages'] ?? 1;
$currentPage = ($offset / $limit);
$hasMore = $currentPage < $totalPages;
} else {
$hasMore = false;
}
}
return $allArticles;
}
?>
Advanced Filtering
<?php
/**
* Search articles with multiple filters
*/
function searchArticles($filters) {
global $baseUrl, $headers;
$queryParams = [];
// Search term
if (isset($filters['search'])) {
$queryParams[] = 'filter[search]=' . urlencode($filters['search']);
}
// Category
if (isset($filters['category'])) {
$queryParams[] = 'filter[category]=' . $filters['category'];
}
// State
if (isset($filters['state'])) {
$queryParams[] = 'filter[state]=' . $filters['state'];
}
// Author
if (isset($filters['author'])) {
$queryParams[] = 'filter[author]=' . $filters['author'];
}
// Date range
if (isset($filters['created_from'])) {
$queryParams[] = 'filter[created_from]=' . $filters['created_from'];
}
if (isset($filters['created_to'])) {
$queryParams[] = 'filter[created_to]=' . $filters['created_to'];
}
$url = $baseUrl . '/content/articles?' . implode('&', $queryParams);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$response = curl_exec($ch);
curl_close($ch);
return json_decode($response, true);
}
// Usage
$results = searchArticles([
'search' => 'joomla',
'category' => 2,
'state' => 1,
'created_from' => '2024-01-01',
'created_to' => '2024-12-31'
]);
?>
Caching voor Betere Performance
<?php
/**
* Cache wrapper for API calls
*/
class JoomlaApiCache {
private $cacheDir;
private $cacheTTL;
public function __construct($cacheDir = '/tmp/joomla_cache', $ttl = 3600) {
$this->cacheDir = $cacheDir;
$this->cacheTTL = $ttl;
if (!is_dir($cacheDir)) {
mkdir($cacheDir, 0755, true);
}
}
private function getCacheKey($endpoint, $params = []) {
return md5($endpoint . json_encode($params));
}
private function getCacheFile($key) {
return $this->cacheDir . '/' . $key . '.json';
}
public function get($endpoint, $params = []) {
$key = $this->getCacheKey($endpoint, $params);
$file = $this->getCacheFile($key);
if (file_exists($file)) {
$age = time() - filemtime($file);
if ($age < $this->cacheTTL) {
return json_decode(file_get_contents($file), true);
}
}
return null;
}
public function set($endpoint, $params, $data) {
$key = $this->getCacheKey($endpoint, $params);
$file = $this->getCacheFile($key);
file_put_contents($file, json_encode($data));
}
public function clear($endpoint = null, $params = []) {
if ($endpoint === null) {
// Clear the cache
array_map('unlink', glob($this->cacheDir . '/*.json'));
} else {
// Clear specific cache
$key = $this->getCacheKey($endpoint, $params);
$file = $this->getCacheFile($key);
if (file_exists($file)) {
unlink($file);
}
}
}
}
// Usage
$cache = new JoomlaApiCache();
function getCachedArticles() {
global $cache;
$cached = $cache->get('/content/articles');
if ($cached !== null) {
return $cached;
}
// Get via API
$articles = makeApiRequest('GET', '/content/articles');
// Save to cache
$cache->set('/content/articles', [], $articles);
return $articles;
}
?>
Rate Limiting Handler
<?php
/**
* Rate limiter voor API requests
*/
class RateLimiter {
private $maxRequests;
private $timeWindow;
private $requests = [];
public function __construct($maxRequests = 100, $timeWindow = 60) {
$this->maxRequests = $maxRequests;
$this->timeWindow = $timeWindow;
}
public function checkLimit() {
$now = time();
$cutoff = $now - $this->timeWindow;
// Remove old requests
$this->requests = array_filter($this->requests, function($time) use ($cutoff) {
return $time > $cutoff;
});
if (count($this->requests) >= $this->maxRequests) {
$oldestRequest = min($this->requests);
$waitTime = $this->timeWindow - ($now - $oldestRequest);
throw new Exception("Rate limit bereikt. Wacht $waitTime seconden.");
}
$this->requests[] = $now;
}
}
// Usage
$rateLimiter = new RateLimiter(100, 60);
function makeRateLimitedRequest($method, $endpoint, $data = null) {
global $rateLimiter;
$rateLimiter->checkLimit();
return makeApiRequest($method, $endpoint, $data);
}
?>
Webhook Integration
Joomla sends webhooks for certain events. Here is an example handler:
<?php
/**
* Webhook handler for Joomla events
*/
// webhook-handler.php
$payload = file_get_contents('php://input');
$data = json_decode($payload, true);
// Verification (configure in Joomla)
$signature = $_SERVER['HTTP_X_JOOMLA_SIGNATURE'] ?? '';
$expectedSignature = hash_hmac('sha256', $payload, 'JOUW_WEBHOOK_SECRET');
if (!hash_equals($expectedSignature, $signature)) {
http_response_code(401);
die('Invalid signature');
}
// Process event
$event = $data['event'] ?? '';
$resource = $data['resource'] ?? [];
switch ($event) {
case 'article.created':
handleArticleCreated($resource);
break;
case 'article.updated':
handleArticleUpdated($resource);
break;
case 'user.created':
handleUserCreated($resource);
break;
default:
error_log("Unknown event: $event");
}
http_response_code(200);
echo json_encode(['status' => 'success']);
function handleArticleCreated($article) {
// Send notification, clear cache, etc.
error_log("New article created: " . $article['id']);
}
function handleArticleUpdated($article) {
// Cache update
global $cache;
$cache->clear('/content/articles/' . $article['id']);
}
function handleUserCreated($user) {
// Send welcome email, etc.
error_log("New user created: " . $user['id']);
}
?>
Async Processing with Queue
For large batch operations:
<?php
/**
* Queue system for async API calls
*/
class ApiQueue {
private $queueFile;
public function __construct($queueFile = 'api_queue.json') {
$this->queueFile = $queueFile;
}
public function add($method, $endpoint, $data = null) {
$queue = $this->getQueue();
$queue[] = [
'id' => uniqid(),
'method' => $method,
'endpoint' => $endpoint,
'data' => $data,
'status' => 'pending',
'created' => time()
];
$this->saveQueue($queue);
}
public function process($batchSize = 10) {
$queue = $this->getQueue();
$processed = 0;
foreach ($queue as &$item) {
if ($item['status'] === 'pending' && $processed < $batchSize) {
try {
makeApiRequest($item['method'], $item['endpoint'], $item['data']);
$item['status'] = 'completed';
$processed++;
} catch (Exception $e) {
$item['status'] = 'failed';
$item['error'] = $e->getMessage();
}
usleep(100000); // 100ms between requests
}
}
$this->saveQueue($queue);
return $processed;
}
private function getQueue() {
if (file_exists($this->queueFile)) {
return json_decode(file_get_contents($this->queueFile), true);
}
return [];
}
private function saveQueue($queue) {
file_put_contents($this->queueFile, json_encode($queue, JSON_PRETTY_PRINT));
}
}
// Usage
$queue = new ApiQueue();
// Add tasks
for ($i = 1; $i <= 100; $i++) {
$queue->add('POST', '/content/articles', [
'title' => "Artikel $i",
'introtext' => "Intro $i",
'fulltext' => "Tekst $i",
'catid' => 2,
'state' => 1
]);
}
// Process queue (run this via cron every minute)
$processed = $queue->process(10);
echo "Processed $processed items\n";
?>