amsom-habitat / oracle-function-calling
Bibliothèque PHP pour faciliter l'appel de fonctions et procédures stockées Oracle via Doctrine. Supporte les paramètres CLOB volumineux et la gestion de fichiers base64.
Package info
gitlab.com/amsom-package/oraclefunctioncalling
pkg:composer/amsom-habitat/oracle-function-calling
Requires
- php: >=8.0
- doctrine/orm: ^2.13 || ^3.0
- symfony/http-foundation: ^5.4 || ^6.0 || ^7.0
- symfony/http-kernel: ^5.4 || ^6.0 || ^7.0
README
Bibliothèque PHP pour simplifier les appels aux fonctions et procédures Oracle via Doctrine, avec support avancé des CLOB, BLOB et compression automatique des PDFs.
🚀 Fonctionnalités
- ✅ Appels simples : Fonctions Oracle en une ligne
- ✅ CLOB volumineux : Découpage automatique jusqu'à 50 MB
- ✅ Fichiers base64 : Conversion automatique vers BLOB Oracle
- ✅ Compression PDF : Réduction automatique vers une taille cible (nouveau !)
- ✅ Gestion des erreurs : Rollback automatique et exceptions structurées
- ✅ Réponses HTTP : Génération automatique de Response Symfony
📦 Installation
composer require amsom-habitat/oracle-function-calling
Configuration rapide
Symfony
services:
AmsomUtilities\OracleFunctionCalling: ~
# ou avec options
AmsomUtilities\OracleFunctionCalling:
arguments:
$managerRegistry: '@doctrine'
$fileMaxSize: 10485760 # 10MB par défaut
Variable d'environnement
FILE_MAX_SIZE=10485760
Exemples d'utilisation
📦 Installation
composer require amsom-habitat/oracle-function-calling
⚙️ Configuration
Configuration Symfony (services.yaml)
Configuration de base :
services:
AmsomUtilities\OracleFunctionCalling:
arguments:
$managerRegistry: '@doctrine'
Configuration complète (recommandé) :
services:
AmsomUtilities\OracleFunctionCalling:
arguments:
$managerRegistry: '@doctrine'
$fileMaxSize: '%env(int:FILE_MAX_SIZE)%'
$apiDocumentUrl: '%env(API_DOCUMENT_URL)%'
Variables d'environnement
# Taille maximale des fichiers (10 MB par défaut)
FILE_MAX_SIZE=10485760
# URL de l'API Document pour la compression PDF (optionnel)
API_DOCUMENT_URL=http://api_document
Configuration programmatique
$oracleCaller = new OracleFunctionCalling(
$managerRegistry,
20971520, // 20 MB max
'https://api-document.example.com'
);
// Ou avec chaînage
$oracleCaller
->setFileMaxSize(10 * 1024 * 1024)
->setApiDocumentUrl('https://api-document.example.com');
🎯 Utilisation
1. Appel simple
Pour les fonctions Oracle standard retournant une chaîne :
// Appel basique
$result = $oracleCaller->call(
'MY_PACKAGE.MY_FUNCTION',
"'param1', 123, 'param2'"
);
// Résultat
echo $result; // {"data": {"id": 123, "status": "success"}}
Avec rollback automatique en cas d'erreur :
$result = $oracleCaller->call(
'MY_PACKAGE.CREATE_USER',
"'john.doe', 'john@example.com'",
rollbackIfFail: true // Rollback si exception
);
2. Appel avec CLOB volumineux
Pour passer de grandes chaînes (JSON, XML, textes > 32 000 caractères) :
$largeData = json_encode($bigArray); // Peut faire plusieurs MB
$result = $oracleCaller->largeCall(
'MY_PACKAGE.PROCESS_DATA',
"'user123', 'action'", // Paramètres AVANT le CLOB
$largeData, // Le CLOB volumineux
"'additionalParam'" // Paramètres APRÈS (optionnel)
);
Note : Les virgules de séparation sont gérées automatiquement.
3. Appel avec fichier (BLOB)
Pour envoyer des fichiers encodés en base64 :
$base64File = base64_encode(file_get_contents('document.pdf'));
$result = $oracleCaller->fileCall(
'MY_PACKAGE.SAVE_DOCUMENT',
"'DOC123', 'john.doe', 'document.pdf'",
$base64File
);
// Vérifier les erreurs de taille
$decoded = json_decode($result);
if (isset($decoded->error)) {
// Le fichier dépasse la limite autorisée
}
4. Génération de réponse HTTP
Convertit automatiquement le résultat Oracle en Response Symfony :
public function createAction(Request $request): Response
{
$result = $this->oracleCaller->call(
'MY_PACKAGE.CREATE_ITEM',
"'param1', 'param2'"
);
// Retourne HTTP 201 si succès, 400 si erreur
return $this->oracleCaller->handleResult($result, Response::HTTP_CREATED);
}
Convention Oracle obligatoire :
✅ Succès : JSON avec propriété data
{"data": {"id": 123, "message": "Créé avec succès"}}
❌ Erreur : JSON sans data
{"error": "Message d'erreur", "code": "ERR_001"}
🗜️ Compression automatique des PDFs
La fonctionnalité de compression PDF permet de réduire automatiquement la taille des fichiers PDF avant leur envoi à Oracle.
Configuration
# URL de l'API Document
API_DOCUMENT_URL=http://api_document
Utilisation par défaut
Détection et compression automatiques :
// Le PDF sera automatiquement détecté et compressé vers 1 MB
$result = $oracleCaller->fileCall(
'SAVE_DOCUMENT',
"'DOC123', 'contract.pdf'",
$pdfBase64
);
Options de compression
$options = [
'mimeType' => 'application/pdf', // Force la détection PDF
'compressPdf' => true, // Active/désactive (défaut: true)
'targetSize' => 500000 // Taille cible en octets (défaut: 1 Mo)
];
$result = $oracleCaller->fileCall(
'SAVE_DOCUMENT',
"'DOC123', 'contract.pdf'",
$pdfBase64,
"", // params after
$options
);
Exemples pratiques
Documents d'archive (compression maximale) :
$result = $oracleCaller->fileCall(
'ARCHIVE_DOCUMENT',
"'DOC_OLD', 'archive.pdf'",
$pdfBase64,
"",
['targetSize' => 300000] // Compresse vers 300 KB
);
Documents légaux (haute qualité) :
$result = $oracleCaller->fileCall(
'SAVE_LEGAL_DOC',
"'DOC_LEGAL', 'contract.pdf'",
$pdfBase64,
"",
['targetSize' => 2000000] // Compresse vers 2 MB (qualité préservée)
);
Désactiver la compression :
$result = $oracleCaller->fileCall(
'SAVE_DOCUMENT',
"'DOC123', 'signature.pdf'",
$pdfBase64,
"",
['compressPdf' => false] // Pas de compression
);
Détection automatique des PDFs
La compression s'active uniquement pour les PDFs, détectés par :
- ✅
mimeTypeexplicite :'application/pdf' - ✅ Préfixe data URI :
data:application/pdf;base64,... - ✅ Signature du fichier : Header
%PDF
Les autres fichiers (images, Excel, Word) ne sont jamais compressés.
Comportement intelligent
- ✅ Compression non bénéfique : Le fichier original est conservé si la compression ne réduit pas la taille
- ✅ API indisponible : Le fichier original est utilisé avec un log d'avertissement
- ✅ Logs détaillés : Toutes les opérations sont loguées pour le débogage
[OracleFunctionCalling] PDF compressé avec succès - Réduction: 45.32%
[OracleFunctionCalling] Compression non bénéfique, utilisation du fichier original
[OracleFunctionCalling] API_DOCUMENT_URL non configurée, compression désactivée
Tailles cibles recommandées
| Cas d'usage | Taille cible | Description |
|---|---|---|
| Archives | 200-500 KB | Compression maximale, qualité acceptable |
| Documents courants | 500 KB-1 MB | Bon équilibre qualité/taille (défaut) |
| Documents importants | 1-2 MB | Haute qualité, bonne compression |
| Documents légaux | 2-3 MB | Qualité maximale, compression légère |
📚 Exemples complets
Contrôleur Symfony - Upload de document
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use AmsomUtilities\OracleFunctionCalling;
class DocumentController extends AbstractController
{
#[Route('/api/documents', methods: ['POST'])]
public function uploadDocument(
Request $request,
OracleFunctionCalling $oracleCaller
): Response {
$data = json_decode($request->getContent(), true);
$options = [
'mimeType' => $data['mimeType'],
'targetSize' => 1000000 // 1 MB
];
$result = $oracleCaller->fileCall(
'DOC_PACKAGE.SAVE_DOCUMENT',
"'{$data['title']}', '{$data['userId']}'",
$data['fileBase64'],
"",
$options
);
return $oracleCaller->handleResult($result, Response::HTTP_CREATED);
}
}
Upload multiple avec compression différenciée
#[Route('/api/documents/bulk', methods: ['POST'])]
public function uploadMultiple(
Request $request,
OracleFunctionCalling $oracleCaller
): Response {
$data = json_decode($request->getContent(), true);
$results = [];
foreach ($data['files'] as $file) {
// Taille cible selon le type de document
$targetSize = match($file['category']) {
'archive' => 300000, // 300 KB
'legal' => 2000000, // 2 MB
default => 1000000 // 1 MB
};
$result = $oracleCaller->fileCall(
'DOC_PACKAGE.SAVE_DOCUMENT',
"'{$file['title']}', '{$file['category']}'",
$file['base64'],
"",
[
'mimeType' => $file['mimeType'],
'targetSize' => $targetSize
]
);
$results[] = json_decode($result);
}
return $this->json(['data' => $results]);
}
Traitement de données volumineuses
public function processBulkData(array $items): Response
{
$largeJson = json_encode($items);
$result = $this->oracleCaller->largeCall(
'BULK_PACKAGE.PROCESS_ITEMS',
"'user123', 'batch_001'",
$largeJson
);
return $this->oracleCaller->handleResult($result, Response::HTTP_OK);
}
Gestion avancée des erreurs
use Symfony\Component\HttpKernel\Exception\HttpException;
public function createUser(Request $request): Response
{
try {
$data = json_decode($request->getContent(), true);
$params = sprintf(
"'%s', '%s', %d",
addslashes($data['name']),
addslashes($data['email']),
$data['age']
);
$result = $this->oracleCaller->call(
'USER_PACKAGE.CREATE_USER',
$params,
rollbackIfFail: true
);
return $this->oracleCaller->handleResult($result, Response::HTTP_CREATED);
} catch (HttpException $e) {
return $this->json([
'error' => $e->getMessage(),
'code' => $e->getStatusCode()
], $e->getStatusCode());
}
}
🗄️ Exemples de fonctions Oracle
Fonction simple (retour JSON)
CREATE OR REPLACE FUNCTION MY_PACKAGE.CREATE_USER(
p_name VARCHAR2,
p_email VARCHAR2,
p_age NUMBER
) RETURN VARCHAR2 IS
v_id NUMBER;
BEGIN
INSERT INTO users (name, email, age)
VALUES (p_name, p_email, p_age)
RETURNING id INTO v_id;
COMMIT;
RETURN '{"data": {"id": ' || v_id || ', "message": "User created"}}';
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
RETURN '{"error": "' || SQLERRM || '"}';
END;
Fonction avec CLOB
CREATE OR REPLACE FUNCTION MY_PACKAGE.PROCESS_BULK_DATA(
p_user_id VARCHAR2,
p_batch_id VARCHAR2,
p_json_data CLOB
) RETURN VARCHAR2 IS
v_count NUMBER := 0;
BEGIN
-- Traiter le CLOB (parsing JSON, insertion multiple, etc.)
-- ... votre logique ici ...
COMMIT;
RETURN '{"data": {"processed": ' || v_count || ', "batch": "' || p_batch_id || '"}}';
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
RETURN '{"error": "' || SQLERRM || '", "code": "BULK_ERROR"}';
END;
Fonction avec fichier (BLOB)
CREATE OR REPLACE FUNCTION DOC_PACKAGE.SAVE_DOCUMENT(
p_title VARCHAR2,
p_user_id VARCHAR2,
p_file_size NUMBER,
p_file_blob BLOB
) RETURN VARCHAR2 IS
v_doc_id VARCHAR2(50);
BEGIN
v_doc_id := SYS_GUID();
INSERT INTO documents (id, title, user_id, file_data, file_size, created_at)
VALUES (v_doc_id, p_title, p_user_id, p_file_blob, p_file_size, SYSDATE);
COMMIT;
RETURN '{"data": {"documentId": "' || v_doc_id || '", "size": ' || p_file_size || '}}';
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
RETURN '{"error": "' || SQLERRM || '"}';
END;
🔧 Configuration avancée
Constantes disponibles
OracleFunctionCalling::CLOB_CHUNK_SIZE // 32000 caractères (32 KB)
OracleFunctionCalling::RESPONSE_SIZE // 4000 caractères (4 KB)
OracleFunctionCalling::DEFAULT_FILE_MAX_SIZE // 10485760 octets (10 MB)
Limites et performance
| Type | Limite par défaut | Configurable | Consommation mémoire |
|---|---|---|---|
| Réponse Oracle | 4 KB | ❌ Constante | Faible |
| Fichiers (base64) | 10 MB | ✅ Oui | ~40-50 MB / 10 MB fichier |
| CLOB | Illimitée | ✅ Optionnel | Variable selon taille |
Recommandations PHP :
# php.ini
memory_limit = 256M # Minimum recommandé
max_execution_time = 60 # Pour gros fichiers
post_max_size = 20M
upload_max_filesize = 20M
Méthodes utilitaires
// Récupérer les configurations
$maxSize = $oracleCaller->getFileMaxSize(); // int
$apiUrl = $oracleCaller->getApiDocumentUrl(); // string|null
// Modifier dynamiquement
$oracleCaller
->setFileMaxSize(20 * 1024 * 1024) // 20 MB
->setApiDocumentUrl('https://api.example.com');
⚠️ Gestion des erreurs
Toutes les méthodes peuvent lever une HttpException :
use Symfony\Component\HttpKernel\Exception\HttpException;
try {
$result = $oracleCaller->call('MY_FUNCTION', "'param'");
} catch (HttpException $e) {
// $e->getStatusCode() => 500
// $e->getMessage() => Message d'erreur Oracle
logger->error('Oracle call failed', [
'function' => 'MY_FUNCTION',
'error' => $e->getMessage()
]);
}
Codes HTTP retournés :
500: Erreur Oracle (syntaxe SQL, contrainte, exception PL/SQL)400: Erreur métier (retournée parhandleResult()si JSON sansdata)413: Fichier trop volumineux (dépasseFILE_MAX_SIZE)
🧪 Tests & Débogage
Vérifier la configuration
// Dans un contrôleur ou commande Symfony
public function debug(OracleFunctionCalling $oracleCaller): void
{
dump([
'fileMaxSize' => $oracleCaller->getFileMaxSize(),
'apiDocumentUrl' => $oracleCaller->getApiDocumentUrl(),
]);
}
Logs de compression PDF
# Rechercher les logs de compression
tail -f var/log/prod.log | grep "OracleFunctionCalling"
# Exemples de logs
[OracleFunctionCalling] PDF compressé avec succès - Réduction: 45.32%
[OracleFunctionCalling] Compression non bénéfique, utilisation du fichier original
[OracleFunctionCalling] API_DOCUMENT_URL non configurée, compression désactivée
[OracleFunctionCalling] Erreur API compression PDF (HTTP 500): ...
Tester la compression manuellement
curl -X POST http://api_document/compress_pdf_target_base64 \
-H "Content-Type: application/json" \
-d '{
"pdfContent": "JVBERi0xLjQKJ...",
"targetSize": 1000000,
"maxQuality": 70,
"minQuality": 20
}'
📖 Documentation complémentaire
- COMPRESSION_PDF.md : Guide complet de la compression PDF
- MIGRATION.md : Guide de migration depuis les versions précédentes
🤝 Support
Pour toute question ou problème :
- Consulter les logs de l'application
- Vérifier la configuration Symfony et les variables d'environnement
- Tester les fonctions Oracle directement via SQL Developer
- Contacter l'équipe de développement
📄 Licence
Propriétaire - AMSOM Habitat
🔄 Changelog
v2.0.0 (2026-03-30)
- ✨ Ajout de la compression automatique des PDFs par taille cible
- ✨ Support du paramètre
optionsdansfileCall - ✨ Détection automatique des PDFs (3 méthodes)
- ✅ Gestion intelligente des erreurs de compression
- 📝 Documentation complète avec exemples pratiques
v1.x.x
- Gestion des CLOB et BLOB
- Appels simples de fonctions Oracle
Support Symfony
"'%s', '%s', %d", addslashes($data['name']), addslashes($data['email']), $data['age']);
$result = $this->oracleCaller->call('USER_PACKAGE.CREATE_USER', $params); return $this->oracleCaller->handleResult($result, Response::HTTP_CREATED); }
Upload de fichier
public function uploadDocument(Request $request): Response
{
$data = json_decode($request->getContent(), true);
$result = $this->oracleCaller->fileCall(
'GED_PACKAGE.SAVE_DOCUMENT',
"'{$data['documentId']}', '{$data['user']}', '{$data['filename']}'",
$data['fileBase64'],
""
);
// Vérifier erreur de taille
$decoded = json_decode($result);
if (isset($decoded->error)) {
return new Response($result, Response::HTTP_REQUEST_ENTITY_TOO_LARGE);
}
return $this->oracleCaller->handleResult($result, Response::HTTP_CREATED);
}
Traitement de données volumineuses
public function processBulkData(array $items): Response
{
$largeJson = json_encode($items); // Peut dépasser 32000 caractères
$result = $this->oracleCaller->largeCall(
'DATA_PACKAGE.PROCESS_BULK',
"'batch_001', 'import'",
$largeJson,
"'user@example.com'"
);
return $this->oracleCaller->handleResult($result, Response::HTTP_OK);
}
Hiérarchie de configuration
La taille maximale des fichiers est déterminée dans cet ordre (priorité décroissante) :
- Valeur passée au constructeur
- Variable d'environnement
FILE_MAX_SIZE - Valeur par défaut (10MB)
Prérequis
- PHP >= 8.0
- Doctrine ORM >= 2.13 ou >= 3.0
- Symfony HttpFoundation >= 5.4
- Symfony HttpKernel >= 5.4
- Base de données Oracle avec fonctions PL/SQL configurées
Sécurité
⚠️ Important : Cette bibliothèque construit des requêtes SQL dynamiques.
- Les noms de fonctions doivent provenir de sources fiables
- Les paramètres doivent être correctement échappés (utilisez
addslashes()) - Les fonctions Oracle doivent avoir les permissions appropriées
- Ne passez jamais directement les entrées utilisateur sans validation
Licence
Propriétaire - Amsom Habitat
Auteur : Amsom Habitat