BCard - Documentation technique

BusinessCardApiController extends AbstractController
in package

Contrôleur REST des cartes de visite numériques (BusinessCardAize).

Expose sous le préfixe /api/business-cards (préfixe de nom de route api_business_cards_) les opérations CRUD sur les cartes de visite, la recherche dans le réseau BCard, la consultation publique par hash, les transitions de statut (publication, brouillon, désactivation, marquage de l'email comme envoyé) et l'upload du logo personnalisé.

Sauf pour l'endpoint public par hash, l'accès est protégé par JWT (#[IsGranted('IS_AUTHENTICATED')] ou IS_AUTHENTICATED_FULLY) et chaque action sur une carte existante vérifie que l'appelant en est le propriétaire ou possède ROLE_ADMIN. Certaines fonctionnalités (numéros multiples, secteur d'activité, type d'organisation, compétences, logo personnalisé, réseau BCard) sont réservées aux offres Pro/Entreprise via SubscriptionService.

Les corps de requête des endpoints d'écriture sont en multipart/form-data (et non en JSON) car ils transportent des fichiers ; la sérialisation des réponses est déléguée à BusinessCardSerializerService.

Attributes
#[Route]
'/api/business-cards'
$name: 'api_business_cards_'
#[Tag]
$name: 'Business Cards'
$description: 'Gestion des cartes de visite numériques'

Table of Contents

Properties

$businessCardSerializer  : BusinessCardSerializerService
$entityManager  : EntityManagerInterface
$logoManagementService  : LogoManagementService
$qrCodeService  : QRCodeService
$subscriptionService  : SubscriptionService
$uploaderService  : UploaderService
$validator  : ValidatorInterface

Methods

__construct()  : mixed
create()  : JsonResponse
Crée une carte de visite pour l'utilisateur connecté à partir d'un envoi multipart.
delete()  : JsonResponse
Supprime une carte de visite ainsi que ses fichiers associés.
disable()  : JsonResponse
Désactive une carte de visite.
list()  : JsonResponse
Renvoie la liste paginée des cartes de visite de l'utilisateur connecté.
markEmailAsSent()  : JsonResponse
Marque comme envoyé l'email associé à une carte de visite.
networkSearch()  : JsonResponse
Recherche des cartes de visite partagées dans le réseau BCard.
publicShow()  : JsonResponse
Expose publiquement une carte de visite identifiée par son hash.
publish()  : JsonResponse
Fait passer une carte de visite au statut publié.
setAsDraft()  : JsonResponse
Repasse une carte de visite au statut brouillon.
show()  : JsonResponse
Renvoie le détail d'une carte de visite appartenant à l'utilisateur connecté.
update()  : JsonResponse
Met à jour partiellement une carte de visite existante.
uploadCustomLogo()  : JsonResponse
Téléverse le logo personnalisé d'une carte de visite.
applyActivities()  : void
Synchronise les activités d'une carte de visite avec les données fournies.
applyActivitiesFromJson()  : void
Décode une charge utile JSON d'activités et l'applique à une carte de visite.
getFileSizeLimit()  : int
Détermine la limite de taille de fichier selon l'offre de l'utilisateur
normalizePhoneNumber()  : string
Normalise un numéro de téléphone au format international.
normalizePhoneNumbersPayload()  : array<int, array{number: string, visible: bool}>
Normalise chaque numéro d'une liste déjà structurée.
parseMultipartPut()  : array<string|int, mixed>
Parser manuel pour récupérer les champs/fichiers en PUT multipart
parsePhoneNumbersPayload()  : array<int, array{number: string, visible: bool}>
Convertit une charge utile de numéros de téléphone en liste structurée.
setNestedValue()  : void
Écrit une valeur dans un tableau à partir d'un nom de champ HTML éventuellement indexé.
validateFile()  : void
Valide un fichier uploadé

Properties

Methods

__construct()

public __construct(EntityManagerInterface $entityManager, ValidatorInterface $validator, UploaderService $uploaderService, QRCodeService $qrCodeService, SubscriptionService $subscriptionService, BusinessCardSerializerService $businessCardSerializer, LogoManagementService $logoManagementService) : mixed
Parameters
$entityManager : EntityManagerInterface

Gestionnaire Doctrine utilisé pour persister, supprimer et flusher les cartes et leurs activités.

$validator : ValidatorInterface

Valideur Symfony appliqué à l'entité BusinessCardAize avant enregistrement.

$uploaderService : UploaderService

Service d'upload des fichiers (CV, photo de profil, brochures) et de suppression des fichiers associés à une carte.

$qrCodeService : QRCodeService

Service de génération du QR code de la carte à partir de son hash public.

$subscriptionService : SubscriptionService

Service d'abonnement : création de l'abonnement gratuit, quota de cartes, accès aux fonctionnalités premium.

$businessCardSerializer : BusinessCardSerializerService

Service de sérialisation d'une carte ou d'une collection de cartes en tableaux JSON.

$logoManagementService : LogoManagementService

Service de gestion et d'upload du logo personnalisé d'une carte.

create()

Crée une carte de visite pour l'utilisateur connecté à partir d'un envoi multipart.

public create(Request $request, EmployeeRepository $employeeRepository) : JsonResponse

Enchaîne les contrôles suivants : interdiction faite aux comptes ROLE_ADMIN, refus des comptes d'entreprise non activés, création automatique d'un abonnement gratuit si l'utilisateur n'en a aucun, puis vérification du quota de cartes du plan (canCreateCard). Les champs phoneNumbers, industry, organizationType et skills sont réservés aux offres Pro/Entreprise. skills doit être un tableau JSON ; ses entrées sont converties en chaînes et les valeurs vides écartées. firstname, lastname et email sont obligatoires ; en l'absence de phoneNumbers, phoneNumber devient obligatoire et est normalisé, sinon le premier numéro normalisé de la liste alimente aussi phoneNumber. Si employee_id est fourni, l'employé doit exister, appartenir à la même entreprise que l'utilisateur et avoir le même email que la carte. Les fichiers cv (PDF, 5 Mo max) et image (JPEG/PNG, 2 Mo max) sont validés selon les limites du plan puis uploadés, et les activités décrites par le JSON activities sont créées avec leurs brochures activity_brochures[i]. Après le premier flush, un publicHash est calculé par hash_hmac('sha256', id, APP_SECRET) s'il est absent, puis le QR code est généré ; un échec de génération du QR code est seulement journalisé via error_log() et n'interrompt pas la création.

Route : /api/business-cards (POST), nom api_business_cards_create. Authentification complète requise (IS_AUTHENTICATED_FULLY).

Corps attendu (multipart/form-data) : {"firstname": "string — requis", "lastname": "string — requis", "email": "string — requis", "phoneNumber": "string — requis si phoneNumbers absent", "phoneNumbers": "string JSON — liste de numéros, Pro/Entreprise uniquement", "skills": "string JSON — tableau de compétences, Pro/Entreprise", "industry": "string — Pro/Entreprise", "organizationType": "string — Pro/Entreprise", "shareInNetwork": "bool — partage dans le réseau BCard", "company"|"compagny": "string — raison sociale", "jobTitle": "string", "website": "string", "address": "string", "linkedin": "string", "twitter": "string", "facebook": "string", "instagram": "string", "bio": "string", "additionalInfo": "string", "employee_id": "int — employé associé", "cv": "fichier PDF", "image": "fichier JPEG/PNG", "activities": "string JSON — [{\"name\": \"...\"}]", "activity_brochures": "fichiers indexés alignés sur activities"}.

Réponses : 201 carte créée ; 400 champ requis manquant, skills non tableau JSON, liste de numéros vide, employé introuvable ou non autorisé, email différent de celui de l'employé, ou erreur d'upload/validation de l'entité ; 401 si le jeton JWT est absent ou invalide ; 403 pour un administrateur, un compte entreprise non activé, un quota de cartes atteint ou l'usage d'un champ réservé aux offres Pro/Entreprise.

Parameters
$request : Request

Requête multipart contenant les champs et fichiers de la carte.

$employeeRepository : EmployeeRepository

Repository utilisé pour résoudre employee_id.

Attributes
#[IsGranted]
'IS_AUTHENTICATED_FULLY'
#[Post]
$path: '/api/business-cards'
$description: 'Crée une nouvelle carte de visite numérique avec support des fichiers (CV, photo, activités)'
$summary: 'Crée une nouvelle carte de visite numérique'
$security: [['bearerAuth' => []]]
$requestBody: new OA\RequestBody(required: true, content: new OA\MediaType(mediaType: 'multipart/form-data', schema: new OA\Schema(required: ['firstname', 'lastname', 'email', 'compagny'], properties: [new OA\Property(property: 'firstname', type: 'string', example: 'John'), new OA\Property(property: 'lastname', type: 'string', example: 'Doe'), new OA\Property(property: 'email', type: 'string', example: 'john@example.com'), new OA\Property(property: 'phoneNumber', description: 'Numéro principal (utilisateurs Free)', type: 'string', example: '+33123456789'), new OA\Property(property: 'phoneNumbers', description: 'JSON des numéros de téléphone (utilisateurs Pro/Entreprise uniquement)', type: 'string', example: '[{"number": "+33123456789", "visible": true}]'), new OA\Property(property: 'jobTitle', type: 'string', example: 'Développeur'), new OA\Property(property: 'organizationType', type: 'string', example: 'Entreprise'), new OA\Property(property: 'industry', type: 'string', example: 'Logiciels informatiques'), new OA\Property(property: 'skills', description: 'JSON des compétences', type: 'string', example: '["PHP", "Symfony", "React"]'), new OA\Property(property: 'shareInNetwork', type: 'boolean', example: "true or false"), new OA\Property(property: 'compagny', type: 'string', example: 'Ma Société'), new OA\Property(property: 'website', type: 'string', example: 'https://example.com'), new OA\Property(property: 'address', type: 'string', example: '123 Rue Example'), new OA\Property(property: 'linkedin', type: 'string', example: 'https://linkedin.com/in/johndoe'), new OA\Property(property: 'twitter', type: 'string', example: 'https://twitter.com/johndoe'), new OA\Property(property: 'facebook', type: 'string', example: 'https://facebook.com/johndoe'), new OA\Property(property: 'instagram', type: 'string', example: 'https://instagram.com/johndoe'), new OA\Property(property: 'bio', type: 'string', example: 'Développeur passionné...'), new OA\Property(property: 'additionalInfo', type: 'string', example: 'Informations supplémentaires'), new OA\Property(property: 'employee_id', description: 'ID de l\'employé associé (optionnel)', type: 'integer', example: 1), new OA\Property(property: 'cv', description: 'Fichier CV (PDF)', type: 'string', format: 'binary'), new OA\Property(property: 'image', description: 'Photo de profil', type: 'string', format: 'binary'), new OA\Property(property: 'activities', description: 'JSON des activités (ordre important pour les brochures) [{"name":"Activité 1"},{"name":"Activité 2"}]', type: 'string'), new OA\Property(property: 'activity_brochures', description: 'Fichiers brochures alignés par index (activity_brochures[0], activity_brochures[1], ...)', type: 'array', items: new OA\Items(type: 'string', format: 'binary'))])))
$tags: ['Business Cards']
$responses: [new OA\Response(response: 201, description: 'Carte de visite créée avec succès', content: new OA\JsonContent(properties: [new OA\Property(property: 'message', type: 'string', example: 'Carte de visite créée avec succès'), new OA\Property(property: 'business_card_id', type: 'integer', example: 1)])), new OA\Response(response: 400, description: 'Données invalides'), new OA\Response(response: 401, description: 'Non authentifié'), new OA\Response(response: 403, description: 'Accès refusé - Compte entreprise requis')]
#[Route]
''
$name: 'create'
$methods: ['POST']
Return values
JsonResponse

Objet {"message", "business_card_id", "qr_code"} en cas de succès, sinon {"error"} ou {"errors"}.

delete()

Supprime une carte de visite ainsi que ses fichiers associés.

public delete(int $id, BusinessCardAizeRepository $businessCardRepository) : JsonResponse

Charge la carte, retourne 404 si elle est introuvable, exige que l'appelant en soit le propriétaire ou possède ROLE_ADMIN, puis appelle deleteAssociatedFiles() (CV, image, brochures, QR code…) avant de retirer l'entité et de flusher. Toute exception survenant pendant la suppression est convertie en réponse 500 contenant le message d'origine.

Route : /api/business-cards/{id} (DELETE), nom api_business_cards_delete. Authentification complète requise (IS_AUTHENTICATED_FULLY).

Réponses : 200 suppression réussie ; 401 si le jeton JWT est absent ou invalide ; 403 carte appartenant à un autre utilisateur ; 404 carte introuvable ; 500 exception levée lors de la suppression des fichiers ou de l'entité.

Parameters
$id : int

Identifiant de la carte à supprimer.

$businessCardRepository : BusinessCardAizeRepository

Repository utilisé pour charger la carte.

Attributes
#[Delete]
$path: '/api/business-cards/{id}'
$description: 'Supprime une carte de visite numérique'
$summary: 'Supprime une carte de visite'
$security: [['bearerAuth' => []]]
$tags: ['Business Cards']
$parameters: [new OA\Parameter(name: 'id', description: 'ID de la carte de visite à supprimer', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))]
$responses: [new OA\Response(response: 200, description: 'Carte de visite supprimée avec succès', content: new OA\JsonContent(properties: [new OA\Property(property: 'message', type: 'string', example: 'Carte de visite supprimée avec succès')])), new OA\Response(response: 404, description: 'Carte de visite non trouvée'), new OA\Response(response: 403, description: 'Accès refusé')]
#[IsGranted]
'IS_AUTHENTICATED_FULLY'
#[Route]
'/{id}'
$name: 'delete'
$methods: ['DELETE']
Return values
JsonResponse

Objet {"message": "Carte de visite et tous les fichiers associés supprimés avec succès"}, sinon {"error"}.

disable()

Désactive une carte de visite.

public disable(int $id, BusinessCardAizeRepository $businessCardRepository) : JsonResponse

Charge la carte, retourne 404 si elle est introuvable, exige que l'appelant en soit le propriétaire ou possède ROLE_ADMIN, puis délègue le changement d'état à BusinessCardAize::disable() avant de flusher. Aucun corps de requête n'est lu et aucun fichier n'est supprimé.

Route : /api/business-cards/{id}/disable (POST), nom api_business_cards_disable. Authentification complète requise (IS_AUTHENTICATED_FULLY).

Réponses : 200 carte désactivée ; 401 si le jeton JWT est absent ou invalide ; 403 carte appartenant à un autre utilisateur ; 404 carte introuvable.

Parameters
$id : int

Identifiant de la carte à désactiver.

$businessCardRepository : BusinessCardAizeRepository

Repository utilisé pour charger la carte.

Attributes
#[IsGranted]
'IS_AUTHENTICATED_FULLY'
#[Post]
$path: '/api/business-cards/{id}/disable'
$summary: 'Désactiver une carte de visite numérique'
$tags: ['Business Cards']
$parameters: [new OA\Parameter(name: 'id', description: 'ID de la carte de visite', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))]
$responses: [new OA\Response(response: 200, description: 'Carte de visite désactivée avec succès', content: new OA\JsonContent(properties: ['message' => new OA\Property(property: 'message', type: 'string', example: 'Carte de visite désactivée avec succès')])), new OA\Response(response: 404, description: 'Carte de visite non trouvée'), new OA\Response(response: 403, description: 'Accès refusé')]
#[Route]
'/{id}/disable'
$name: 'disable'
$methods: ['POST']
Return values
JsonResponse

Objet {"message": "Carte de visite désactivée avec succès"}, sinon {"error"}.

list()

Renvoie la liste paginée des cartes de visite de l'utilisateur connecté.

public list(Request $request, BusinessCardAizeRepository $businessCardRepository) : JsonResponse

Refuse l'accès aux comptes rattachés à une entreprise non activée. Lit les paramètres de requête page (borné à 1 minimum), limit (borné entre 1 et 50, 10 par défaut) et search, puis délègue au repository (findByUserWithSearch / countByUserWithSearch) la recherche filtrée sur les cartes du seul utilisateur courant. Les cartes sont sérialisées via BusinessCardSerializerService et le nombre total de pages est calculé avec ceil().

Route : /api/business-cards (GET), nom api_business_cards_list. Authentification requise (IS_AUTHENTICATED).

Paramètres de requête : page (int, optionnel), limit (int, optionnel), search (string, optionnel — nom, prénom, email, entreprise, poste, téléphone).

Réponses : 200 liste et bloc de pagination renvoyés ; 401 si le jeton JWT est absent ou invalide ; 403 si l'utilisateur appartient à une entreprise dont le compte n'est pas activé.

Parameters
$request : Request

Requête HTTP portant les paramètres de pagination et de recherche.

$businessCardRepository : BusinessCardAizeRepository

Repository interrogé pour la recherche et le comptage.

Attributes
#[Get]
$path: '/api/business-cards'
$description: 'Récupère la liste des cartes de visite numériques de l\'utilisateur connecté (utilisateurs normaux et entreprises)'
$summary: 'Liste les cartes de visite numériques'
$security: [['bearerAuth' => []]]
$tags: ['Business Cards']
$parameters: [new OA\Parameter(name: 'page', description: 'Numéro de page', in: 'query', required: false, schema: new OA\Schema(type: 'integer', default: 1)), new OA\Parameter(name: 'limit', description: 'Nombre d\'éléments par page', in: 'query', required: false, schema: new OA\Schema(type: 'integer', default: 10)), new OA\Parameter(name: 'search', description: 'Terme de recherche (nom, prénom, email, entreprise, poste, téléphone)', in: 'query', required: false, schema: new OA\Schema(type: 'string'))]
$responses: [new OA\Response(response: 200, description: 'Liste des cartes de visite récupérée avec succès', content: new OA\JsonContent(properties: [new OA\Property(property: 'business_cards', type: 'array', items: new OA\Items(properties: [new OA\Property(property: 'id', type: 'integer', example: 1), new OA\Property(property: 'firstname', type: 'string', example: 'John'), new OA\Property(property: 'lastname', type: 'string', example: 'Doe'), new OA\Property(property: 'email', type: 'string', example: 'john@example.com'), new OA\Property(property: 'phone', type: 'string', example: '+33123456789'), new OA\Property(property: 'phoneNumber', type: 'string', example: '+33123456789'), new OA\Property(property: 'phoneNumbers', type: 'array', items: new OA\Items(properties: [new OA\Property(property: 'number', type: 'string', example: '+33123456789'), new OA\Property(property: 'visible', type: 'boolean', example: true)])), new OA\Property(property: 'visiblePhoneNumbers', type: 'array', items: new OA\Items(type: 'string', example: '+33123456789')), new OA\Property(property: 'position', type: 'string', example: 'Développeur'), new OA\Property(property: 'organizationType', type: 'string', example: 'Entreprise'), new OA\Property(property: 'industry', type: 'string', example: 'Informatique'), new OA\Property(property: 'skills', type: 'array', items: new OA\Items(type: 'string', example: 'PHP')), new OA\Property(property: 'bio', type: 'string', example: 'bio'), new OA\Property(property: 'website', type: 'string', example: 'https://example.com'), new OA\Property(property: 'address', type: 'string', example: '123 Rue Example'), new OA\Property(property: 'image', type: 'string', example: 'profil.png'), new OA\Property(property: 'cv', type: 'string', example: 'cv.jpg '), new OA\Property(property: 'activities', properties: [new OA\Property(property: 'id', type: 'integer', example: 1), new OA\Property(property: 'name', type: 'string', example: "BINN"), new OA\Property(property: 'brochure', type: 'string', example: "brochure.pdf")]), new OA\Property(property: 'status', type: 'string', example: "published"), new OA\Property(property: 'hash', type: 'string', example: "hash_code"), new OA\Property(property: 'created_at', type: 'string', format: 'date-time'), new OA\Property(property: 'employee', properties: [new OA\Property(property: 'id', type: 'integer'), new OA\Property(property: 'firstname', type: 'string'), new OA\Property(property: 'lastname', type: 'string')], type: 'object')])), new OA\Property(property: 'pagination', properties: [new OA\Property(property: 'current_page', type: 'integer'), new OA\Property(property: 'total_pages', type: 'integer'), new OA\Property(property: 'total_items', type: 'integer'), new OA\Property(property: 'items_per_page', type: 'integer')], type: 'object')])), new OA\Response(response: 401, description: 'Non authentifié'), new OA\Response(response: 403, description: 'Accès refusé - Compte entreprise non activé')]
#[IsGranted]
'IS_AUTHENTICATED'
#[Route]
''
$name: 'list'
$methods: ['GET']
Return values
JsonResponse

Objet {"business_cards": [...], "pagination": {"current_page", "total_pages", "total_items", "items_per_page"}}.

markEmailAsSent()

Marque comme envoyé l'email associé à une carte de visite.

public markEmailAsSent(int $id, BusinessCardAizeRepository $businessCardRepository) : JsonResponse

Charge la carte, retourne 404 si elle est introuvable, exige que l'appelant en soit le propriétaire ou possède ROLE_ADMIN, puis appelle BusinessCardAize::markEmailAsSent() avant de flusher. Cette action ne déclenche aucun envoi de message : elle ne fait qu'enregistrer l'état d'envoi côté entité.

Route : /api/business-cards/{id}/mark-email-sent (POST), nom api_business_cards_mark_email_sent. Authentification complète requise (IS_AUTHENTICATED_FULLY).

Réponses : 200 marquage effectué ; 401 si le jeton JWT est absent ou invalide ; 403 carte appartenant à un autre utilisateur ; 404 carte introuvable.

Parameters
$id : int

Identifiant de la carte concernée.

$businessCardRepository : BusinessCardAizeRepository

Repository utilisé pour charger la carte.

Attributes
#[IsGranted]
'IS_AUTHENTICATED_FULLY'
#[Post]
$path: '/api/business-cards/{id}/mark-email-sent'
$summary: 'Marquer l\'email comme envoyé pour une carte de visite'
$tags: ['Business Cards']
$parameters: [new OA\Parameter(name: 'id', description: 'ID de la carte de visite', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))]
$responses: [new OA\Response(response: 200, description: 'Email marqué comme envoyé avec succès', content: new OA\JsonContent(properties: ['message' => new OA\Property(property: 'message', type: 'string', example: 'Email marqué comme envoyé avec succès')])), new OA\Response(response: 404, description: 'Carte de visite non trouvée'), new OA\Response(response: 403, description: 'Accès refusé')]
#[Route]
'/{id}/mark-email-sent'
$name: 'mark_email_sent'
$methods: ['POST']
Return values
JsonResponse

Objet {"message": "Email marqué comme envoyé avec succès"}, sinon {"error"}.

networkSearch()

Recherche des cartes de visite partagées dans le réseau BCard.

public networkSearch(Request $request, BusinessCardAizeRepository $businessCardRepository) : JsonResponse

Vérifie d'abord que l'utilisateur courant est bien une instance de User, puis qu'il dispose des fonctionnalités premium (via SubscriptionService) ou de l'un des rôles ROLE_EMPLOYEE / ROLE_MANAGER. Le terme q est nettoyé (trim) et converti en null s'il est vide, la pagination est bornée (page >= 1, limit entre 1 et 50, 20 par défaut) ; la sélection des cartes visibles dans le réseau, dont l'exclusion de celles sans consentement de partage, est déléguée à findNetworkCardsWithSearch(), qui reçoit également l'utilisateur courant.

Route : /api/business-cards/network/search (GET), nom api_business_cards_network_search. Authentification requise (IS_AUTHENTICATED).

Paramètres de requête : q (string, optionnel), page (int, optionnel), limit (int, optionnel).

Réponses : 200 résultats sérialisés ; 401 si aucun utilisateur User n'est authentifié ; 403 si l'utilisateur n'a ni offre Pro/Entreprise ni rôle employé/manager.

Parameters
$request : Request

Requête HTTP portant q, page et limit.

$businessCardRepository : BusinessCardAizeRepository

Repository interrogé pour la recherche réseau.

Attributes
#[Get]
$path: '/api/business-cards/network/search'
$description: 'Liste/recherche de cartes de visite dans le réseau BCard (Pro/Entreprise). Les cartes sans consentement sont exclues.'
$summary: 'Réseau BCard'
$security: [['bearerAuth' => []]]
$tags: ['Business Cards']
$parameters: [new OA\Parameter(name: 'q', in: 'query', required: false, schema: new OA\Schema(type: 'string')), new OA\Parameter(name: 'page', in: 'query', required: false, schema: new OA\Schema(type: 'integer', default: 1)), new OA\Parameter(name: 'limit', in: 'query', required: false, schema: new OA\Schema(type: 'integer', default: 20))]
$responses: [new OA\Response(response: 200, description: 'Résultats de recherche'), new OA\Response(response: 400, description: 'Paramètres invalides'), new OA\Response(response: 403, description: 'Offre Pro/Entreprise requise')]
#[IsGranted]
'IS_AUTHENTICATED'
#[Route]
'/network/search'
$name: 'network_search'
$methods: ['GET']
Return values
JsonResponse

Objet {"data": [...], "q": string|null, "page": int, "limit": int} avec le statut 200.

publicShow()

Expose publiquement une carte de visite identifiée par son hash.

public publicShow(string $hash, BusinessCardAizeRepository $businessCardRepository) : JsonResponse

Recherche la carte dont la propriété publicHash correspond au segment d'URL fourni, sans aucun contrôle d'authentification ni de propriété (endpoint déclaré security: []), et la sérialise en mode détaillé (serializeBusinessCard($card, true)). Aucun filtrage sur le statut de la carte n'est effectué : une carte en brouillon ou désactivée reste accessible si son hash est connu.

Route : /api/business-cards/public/{hash} (GET), nom api_business_cards_public_show. Aucune authentification requise.

Réponses : 200 carte trouvée et sérialisée ; 404 {"error": "Carte de visite non trouvée"} si aucune carte ne porte ce hash.

Parameters
$hash : string

Hash public de la carte, extrait de l'URL.

$businessCardRepository : BusinessCardAizeRepository

Repository utilisé pour retrouver la carte par son hash.

Attributes
#[Get]
$path: '/api/business-cards/public/{hash}'
$description: 'Récupère les détails publics d\'une carte de visite par son hash'
$summary: 'Récupère une carte de visite par son hash public'
$security: []
$tags: ['Business Cards']
$parameters: [new OA\Parameter(name: 'hash', description: 'Hash public de la carte de visite', in: 'path', required: true, schema: new OA\Schema(type: 'string'))]
$responses: [new OA\Response(response: 200, description: 'Détails publics de la carte de visite', content: new OA\JsonContent(properties: [new OA\Property(property: 'id', type: 'integer', example: 1), new OA\Property(property: 'firstname', type: 'string', example: 'John'), new OA\Property(property: 'lastname', type: 'string', example: 'Doe'), new OA\Property(property: 'email', type: 'string', example: 'john@example.com'), new OA\Property(property: 'phone', type: 'string', example: '+33123456789'), new OA\Property(property: 'phoneNumber', type: 'string', example: '+33123456789'), new OA\Property(property: 'phoneNumbers', type: 'array', items: new OA\Items(properties: [new OA\Property(property: 'number', type: 'string', example: '+33123456789'), new OA\Property(property: 'visible', type: 'boolean', example: true)])), new OA\Property(property: 'visiblePhoneNumbers', type: 'array', items: new OA\Items(type: 'string', example: '+33123456789')), new OA\Property(property: 'jobTitle', type: 'string', example: 'Développeur'), new OA\Property(property: 'bio', type: 'string', example: 'Bio'), new OA\Property(property: 'company', type: 'string', example: 'Ma Société'), new OA\Property(property: 'website', type: 'string', example: 'https://example.com'), new OA\Property(property: 'address', type: 'string', example: '123 Rue Example'), new OA\Property(property: 'image', type: 'string', example: 'profil.png'), new OA\Property(property: 'cv', type: 'string', example: 'cv.jpg '), new OA\Property(property: 'activities', properties: [new OA\Property(property: 'id', type: 'integer', example: 1), new OA\Property(property: 'name', type: 'string', example: "BINN"), new OA\Property(property: 'brochure', type: 'string', example: "brochure.pdf")]), new OA\Property(property: 'status', type: 'string', example: "published"), new OA\Property(property: 'linkedin', type: 'string', example: 'https://linkedin.com/in/johndoe'), new OA\Property(property: 'twitter', type: 'string', example: 'https://twitter.com/johndoe'), new OA\Property(property: 'facebook', type: 'string', example: 'https://facebook.com/johndoe'), new OA\Property(property: 'instagram', type: 'string', example: 'https://instagram.com/johndoe'), new OA\Property(property: 'created_at', type: 'string', format: 'date-time'), new OA\Property(property: 'employee', type: 'object')])), new OA\Response(response: 404, description: 'Carte de visite non trouvée')]
#[Route]
'/public/{hash}'
$name: 'public_show'
$methods: ['GET']
Return values
JsonResponse

Représentation JSON détaillée de la carte, ou message d'erreur.

publish()

Fait passer une carte de visite au statut publié.

public publish(int $id, BusinessCardAizeRepository $businessCardRepository) : JsonResponse

Charge la carte, retourne 404 si elle est introuvable, exige que l'appelant en soit le propriétaire ou possède ROLE_ADMIN, puis délègue le changement d'état à BusinessCardAize::publish() avant de flusher. Aucun corps de requête n'est lu.

Route : /api/business-cards/{id}/publish (POST), nom api_business_cards_publish. Authentification complète requise (IS_AUTHENTICATED_FULLY).

Réponses : 200 carte publiée ; 401 si le jeton JWT est absent ou invalide ; 403 carte appartenant à un autre utilisateur ; 404 carte introuvable.

Parameters
$id : int

Identifiant de la carte à publier.

$businessCardRepository : BusinessCardAizeRepository

Repository utilisé pour charger la carte.

Attributes
#[IsGranted]
'IS_AUTHENTICATED_FULLY'
#[Post]
$path: '/api/business-cards/{id}/publish'
$summary: 'Publier une carte de visite numérique'
$tags: ['Business Cards']
$parameters: [new OA\Parameter(name: 'id', description: 'ID de la carte de visite', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))]
$responses: [new OA\Response(response: 200, description: 'Carte de visite publiée avec succès', content: new OA\JsonContent(properties: ['message' => new OA\Property(property: 'message', type: 'string', example: 'Carte de visite publiée avec succès')])), new OA\Response(response: 404, description: 'Carte de visite non trouvée'), new OA\Response(response: 403, description: 'Accès refusé')]
#[Route]
'/{id}/publish'
$name: 'publish'
$methods: ['POST']
Return values
JsonResponse

Objet {"message": "Carte de visite publiée avec succès"}, sinon {"error"}.

setAsDraft()

Repasse une carte de visite au statut brouillon.

public setAsDraft(int $id, BusinessCardAizeRepository $businessCardRepository) : JsonResponse

Charge la carte, retourne 404 si elle est introuvable, exige que l'appelant en soit le propriétaire ou possède ROLE_ADMIN, puis délègue le changement d'état à BusinessCardAize::setAsDraft() avant de flusher. Aucun corps de requête n'est lu.

Route : /api/business-cards/{id}/draft (POST), nom api_business_cards_set_draft. Authentification complète requise (IS_AUTHENTICATED_FULLY).

Réponses : 200 carte mise en brouillon ; 401 si le jeton JWT est absent ou invalide ; 403 carte appartenant à un autre utilisateur ; 404 carte introuvable.

Parameters
$id : int

Identifiant de la carte à repasser en brouillon.

$businessCardRepository : BusinessCardAizeRepository

Repository utilisé pour charger la carte.

Attributes
#[IsGranted]
'IS_AUTHENTICATED_FULLY'
#[Post]
$path: '/api/business-cards/{id}/draft'
$summary: 'Mettre une carte de visite en brouillon'
$tags: ['Business Cards']
$parameters: [new OA\Parameter(name: 'id', description: 'ID de la carte de visite', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))]
$responses: [new OA\Response(response: 200, description: 'Carte de visite mise en brouillon avec succès', content: new OA\JsonContent(properties: ['message' => new OA\Property(property: 'message', type: 'string', example: 'Carte de visite mise en brouillon avec succès')])), new OA\Response(response: 404, description: 'Carte de visite non trouvée'), new OA\Response(response: 403, description: 'Accès refusé')]
#[Route]
'/{id}/draft'
$name: 'set_draft'
$methods: ['POST']
Return values
JsonResponse

Objet {"message": "Carte de visite mise en brouillon avec succès"}, sinon {"error"}.

show()

Renvoie le détail d'une carte de visite appartenant à l'utilisateur connecté.

public show(int $id, BusinessCardAizeRepository $businessCardRepository) : JsonResponse

Charge la carte par son identifiant, retourne 404 si elle n'existe pas, puis vérifie que l'utilisateur courant en est le propriétaire ou possède ROLE_ADMIN avant de la sérialiser en mode détaillé (serializeBusinessCard($card, true)).

Route : /api/business-cards/{id} (GET), nom api_business_cards_show. Authentification requise (IS_AUTHENTICATED).

Réponses : 200 carte sérialisée ; 401 si le jeton JWT est absent ou invalide ; 403 {"error": "Accès refusé"} si la carte appartient à un autre utilisateur et que l'appelant n'est pas administrateur ; 404 si aucune carte ne porte cet identifiant.

Parameters
$id : int

Identifiant de la carte de visite.

$businessCardRepository : BusinessCardAizeRepository

Repository utilisé pour charger la carte.

Attributes
#[Get]
$path: '/api/business-cards/{id}'
$description: 'Récupère les détails d\'une carte de visite spécifique'
$summary: 'Récupère une carte de visite par son ID'
$security: [['bearerAuth' => []]]
$tags: ['Business Cards']
$parameters: [new OA\Parameter(name: 'id', description: 'ID de la carte de visite', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))]
$responses: [new OA\Response(response: 200, description: 'Détails de la carte de visite', content: new OA\JsonContent(properties: [new OA\Property(property: 'id', type: 'integer', example: 1), new OA\Property(property: 'firstname', type: 'string', example: 'John'), new OA\Property(property: 'lastname', type: 'string', example: 'Doe'), new OA\Property(property: 'email', type: 'string', example: 'john@example.com'), new OA\Property(property: 'phone', type: 'string', example: '+33123456789'), new OA\Property(property: 'phoneNumber', type: 'string', example: '+33123456789'), new OA\Property(property: 'phoneNumbers', type: 'array', items: new OA\Items(properties: [new OA\Property(property: 'number', type: 'string', example: '+33123456789'), new OA\Property(property: 'visible', type: 'boolean', example: true)])), new OA\Property(property: 'visiblePhoneNumbers', type: 'array', items: new OA\Items(type: 'string', example: '+33123456789')), new OA\Property(property: 'jobTitle', type: 'string', example: 'Développeur'), new OA\Property(property: 'bio', type: 'string', example: 'bio'), new OA\Property(property: 'company', type: 'string', example: 'Ma Société'), new OA\Property(property: 'website', type: 'string', example: 'https://example.com'), new OA\Property(property: 'address', type: 'string', example: '123 Rue Example'), new OA\Property(property: 'image', type: 'string', example: 'profil.png'), new OA\Property(property: 'cv', type: 'string', example: 'cv.jpg '), new OA\Property(property: 'activities', properties: [new OA\Property(property: 'id', type: 'integer', example: 1), new OA\Property(property: 'name', type: 'string', example: "BINN"), new OA\Property(property: 'brochure', type: 'string', example: "brochure.pdf")]), new OA\Property(property: 'status', type: 'string', example: "published"), new OA\Property(property: 'linkedin', type: 'string', example: 'https://linkedin.com/in/johndoe'), new OA\Property(property: 'twitter', type: 'string', example: 'https://twitter.com/johndoe'), new OA\Property(property: 'facebook', type: 'string', example: 'https://facebook.com/johndoe'), new OA\Property(property: 'instagram', type: 'string', example: 'https://instagram.com/johndoe'), new OA\Property(property: 'created_at', type: 'string', format: 'date-time'), new OA\Property(property: 'employee', type: 'object')])), new OA\Response(response: 404, description: 'Carte de visite non trouvée'), new OA\Response(response: 403, description: 'Accès refusé')]
#[IsGranted]
'IS_AUTHENTICATED'
#[Route]
'/{id}'
$name: 'show'
$methods: ['GET']
Return values
JsonResponse

Représentation JSON détaillée de la carte, ou message d'erreur.

update()

Met à jour partiellement une carte de visite existante.

public update(int $id, Request $request, BusinessCardAizeRepository $businessCardRepository, LoggerInterface $logger) : JsonResponse

Charge la carte, retourne 404 si elle est introuvable, puis exige que l'appelant en soit le propriétaire ou possède ROLE_ADMIN. En méthode PUT, le corps multipart est décodé manuellement par parseMultipartPut() (PHP ne peuplant pas $_POST/$_FILES en PUT) ; en POST, les champs et fichiers natifs de la requête sont utilisés. Seules les clés présentes sont appliquées, via une table de correspondance champ => setter (firstname, lastname, email, phoneNumber, jobTitle, organizationType, industry, compagny/company, website, address, linkedin, twitter, facebook, instagram, bio, status, additionalInfo). phoneNumbers, industry, organizationType et skills sont réservés aux offres Pro/Entreprise ; phoneNumber est normalisé et, pour un compte premium, réplique la liste phoneNumbers à un seul élément visible. Les nouveaux fichiers cv et image sont validés puis uploadés après suppression du fichier précédent sur le disque. Le JSON activities déclenche un upsert des activités sans suppression des activités absentes (replace = false). L'entité est validée avant flush(), et la mise à jour est journalisée. Note : shareInNetwork est lu sans test de présence préalable, il est donc supposé toujours transmis dans le corps.

Route : /api/business-cards/{id} (PUT et POST), nom api_business_cards_update. Authentification complète requise (IS_AUTHENTICATED_FULLY).

Corps attendu (multipart/form-data, tous les champs optionnels sauf shareInNetwork qui est lu inconditionnellement) : {"firstname": "string", "lastname": "string", "email": "string", "phoneNumber": "string — normalisé", "phoneNumbers": "string JSON — Pro/Entreprise uniquement", "skills": "string JSON — tableau, Pro/Entreprise", "industry": "string — Pro/Entreprise", "organizationType": "string — Pro/Entreprise", "shareInNetwork": "bool", "company"|"compagny": "string", "jobTitle": "string", "website": "string", "address": "string", "linkedin": "string", "twitter": "string", "facebook": "string", "instagram": "string", "bio": "string", "status": "string", "additionalInfo": "string", "cv": "fichier PDF", "image": "fichier JPEG/PNG", "activities": "string JSON", "activity_brochures": "fichiers indexés"}.

Réponses : 200 mise à jour effectuée ; 400 liste de numéros vide, skills non tableau JSON, erreur d'upload ou violations de contraintes de validation ; 401 si le jeton JWT est absent ou invalide ; 403 carte appartenant à un autre utilisateur, ou champ réservé aux offres Pro/Entreprise employé sans droits ; 404 carte introuvable.

Parameters
$id : int

Identifiant de la carte à modifier.

$request : Request

Requête multipart (PUT ou POST) contenant les champs et fichiers.

$businessCardRepository : BusinessCardAizeRepository

Repository utilisé pour charger la carte.

$logger : LoggerInterface

Journalise l'identifiant de la carte mise à jour.

Attributes
#[IsGranted]
'IS_AUTHENTICATED_FULLY'
#[Put]
$path: '/api/business-cards/{id}'
$description: 'Met à jour les informations d\'une carte de visite numérique avec support des fichiers'
$summary: 'Met à jour une carte de visite'
$security: [['bearerAuth' => []]]
$requestBody: new OA\RequestBody(required: true, content: new OA\MediaType(mediaType: 'multipart/form-data', schema: new OA\Schema(properties: [new OA\Property(property: 'firstname', type: 'string', example: 'John'), new OA\Property(property: 'lastname', type: 'string', example: 'Doe'), new OA\Property(property: 'email', type: 'string', example: 'john@example.com'), new OA\Property(property: 'phoneNumber', description: 'Numéro principal (utilisateurs Free)', type: 'string', example: '+33123456789'), new OA\Property(property: 'phoneNumbers', description: 'JSON des numéros de téléphone (utilisateurs Pro/Entreprise uniquement)', type: 'string', example: '[{"number": "+33123456789", "visible": true}]'), new OA\Property(property: 'jobTitle', type: 'string', example: 'Développeur Senior'), new OA\Property(property: 'organizationType', type: 'string', example: 'Entreprise'), new OA\Property(property: 'industry', type: 'string', example: 'Logiciels informatiques'), new OA\Property(property: 'skills', description: 'JSON des compétences', type: 'string', example: '["PHP", "Symfony", "React"]'), new OA\Property(property: 'shareInNetwork', type: 'boolean', example: "true or false"), new OA\Property(property: 'compagny', type: 'string', example: 'Ma Société'), new OA\Property(property: 'website', type: 'string', example: 'https://example.com'), new OA\Property(property: 'address', type: 'string', example: '123 Rue Example'), new OA\Property(property: 'linkedin', type: 'string', example: 'https://linkedin.com/in/johndoe'), new OA\Property(property: 'twitter', type: 'string', example: 'https://twitter.com/johndoe'), new OA\Property(property: 'facebook', type: 'string', example: 'https://facebook.com/johndoe'), new OA\Property(property: 'instagram', type: 'string', example: 'https://instagram.com/johndoe'), new OA\Property(property: 'bio', type: 'string', example: 'Développeur passionné...'), new OA\Property(property: 'additionalInfo', type: 'string', example: 'Informations supplémentaires'), new OA\Property(property: 'cv', description: 'Nouveau fichier CV (PDF)', type: 'string', format: 'binary'), new OA\Property(property: 'status', type: 'string', example: "draft"), new OA\Property(property: 'image', description: 'Nouvelle photo de profil', type: 'string', format: 'binary'), new OA\Property(property: 'activities', description: 'JSON des activités à upsert (par id si fourni, sinon par nom).', type: 'string'), new OA\Property(property: 'activity_brochures', description: 'Nouveaux fichiers brochures alignés par index (activity_brochures[0], activity_brochures[1], ...)', type: 'array', items: new OA\Items(type: 'string', format: 'binary'))])))
$tags: ['Business Cards']
$parameters: [new OA\Parameter(name: 'id', description: 'ID de la carte de visite à mettre à jour', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))]
$responses: [new OA\Response(response: 200, description: 'Carte de visite mise à jour avec succès', content: new OA\JsonContent(properties: [new OA\Property(property: 'message', type: 'string', example: 'Carte de visite mise à jour avec succès')])), new OA\Response(response: 400, description: 'Données invalides'), new OA\Response(response: 404, description: 'Carte de visite non trouvée'), new OA\Response(response: 403, description: 'Accès refusé')]
#[Route]
'/{id}'
$name: 'update'
$methods: ['PUT', 'POST']
Return values
JsonResponse

Objet {"message": "Carte de visite mise à jour avec succès"}, sinon {"error"} ou {"errors"}.

Téléverse le logo personnalisé d'une carte de visite.

public uploadCustomLogo(int $id, Request $request, BusinessCardAizeRepository $businessCardRepository) : JsonResponse

Charge la carte, retourne 404 si elle est introuvable, exige que l'appelant en soit le propriétaire ou possède ROLE_ADMIN, puis vérifie que son abonnement donne accès aux fonctionnalités premium. Le fichier est lu dans le champ logo de la requête ; sa validation (format, taille) et son stockage sont entièrement délégués à LogoManagementService::uploadCustomLogo(), dont le chemin retourné est affecté à la carte avant flush(). Toute exception levée par le service est renvoyée telle quelle au client en 400.

Route : /api/business-cards/{id}/custom-logo (POST), nom api_business_cards_upload_custom_logo. Authentification requise (IS_AUTHENTICATED).

Corps attendu (multipart/form-data) : {"logo": "fichier image (PNG, JPG, JPEG, SVG) — requis"}.

Réponses : 200 logo enregistré ; 400 aucun fichier logo fourni ou exception d'upload ; 401 si le jeton JWT est absent ou invalide ; 403 carte appartenant à un autre utilisateur ou offre PRO absente ; 404 carte introuvable.

Parameters
$id : int

Identifiant de la carte concernée.

$request : Request

Requête multipart contenant le fichier logo.

$businessCardRepository : BusinessCardAizeRepository

Repository utilisé pour charger la carte.

Attributes
#[IsGranted]
'IS_AUTHENTICATED'
#[Post]
$path: '/api/business-cards/{id}/custom-logo'
$description: 'Upload le logo personnalisé pour une carte de visite (réservé aux utilisateurs PRO)'
$summary: 'Upload du logo personnalisé pour une carte de visite'
$security: [['bearerAuth' => []]]
$requestBody: new OA\RequestBody(description: 'Fichier logo à uploader', required: true, content: new OA\MediaType(mediaType: 'multipart/form-data', schema: new OA\Schema(required: ['logo'], properties: ['logo' => new OA\Property(property: 'logo', description: 'Fichier image du logo (PNG, JPG, JPEG, SVG)', type: 'string', format: 'binary')])))
$tags: ['Business Cards']
$parameters: [new OA\Parameter(name: 'id', description: 'ID de la carte de visite', in: 'path', required: true, schema: new OA\Schema(type: 'integer'))]
$responses: [new OA\Response(response: 200, description: 'Logo d\'entreprise uploadé avec succès', content: new OA\JsonContent(properties: ['message' => new OA\Property(property: 'message', type: 'string'), 'logoPath' => new OA\Property(property: 'logoPath', type: 'string')])), new OA\Response(response: 400, description: 'Données invalides'), new OA\Response(response: 403, description: 'Accès refusé ou offre PRO requise'), new OA\Response(response: 404, description: 'Carte de visite non trouvée')]
#[Route]
'/{id}/custom-logo'
$name: 'upload_custom_logo'
$methods: ['POST']
Return values
JsonResponse

Objet {"message", "logoPath"} en cas de succès, sinon {"error"}.

applyActivities()

Synchronise les activités d'une carte de visite avec les données fournies.

private applyActivities(BusinessCardAize $businessCard, array<int, mixed> $activitiesData, array<int, mixed> $brochureFiles, User $user, bool $replace) : void

Indexe d'abord les activités existantes par identifiant et par nom en minuscules. Pour chaque entrée : ignore les valeurs non tabulaires et les noms vides après trim(), puis recherche l'activité correspondante par id (entier ou chaîne numérique), à défaut par nom insensible à la casse, et en crée une nouvelle si aucune ne correspond. Le nom est ensuite réaffecté. Si un fichier de brochure existe à l'index courant du tableau $brochureFiles, il est validé (PDF, JPEG ou PNG, 5 Mo maximum plafonnés par l'offre de l'utilisateur), l'ancienne brochure est supprimée du disque, puis le nouveau fichier est uploadé dans brochure_directory. L'alignement se fait par index : la clé du tableau d'activités doit correspondre à celle du fichier. Enfin, si $replace vaut vrai, les activités existantes non retenues sont supprimées de la carte et leurs brochures effacées du disque ; sinon la méthode se termine sans rien retirer.

Parameters
$businessCard : BusinessCardAize

Carte dont la collection d'activités est modifiée.

$activitiesData : array<int, mixed>

Données d'activités décodées, chaque entrée acceptée étant array{id?: int|string, name: string}.

$brochureFiles : array<int, mixed>

Fichiers de brochures indexés par la même clé que $activitiesData.

$user : User

Utilisateur courant, servant à déterminer la taille de fichier autorisée.

$replace : bool

Si vrai, supprime les activités existantes absentes des données fournies.

applyActivitiesFromJson()

Décode une charge utile JSON d'activités et l'applique à une carte de visite.

private applyActivitiesFromJson(BusinessCardAize $businessCard, string|null $activitiesJson, mixed $brochureFiles, User $user, bool $replace) : void

Sort silencieusement si la chaîne est nulle ou vide, ainsi que si le JSON est mal formé ou ne décode pas en tableau : aucune exception n'est levée et aucune activité n'est modifiée. Les fichiers de brochures reçus sont normalisés en tableau (toute valeur non tableau devient un tableau vide) avant d'être transmis à applyActivities().

Parameters
$businessCard : BusinessCardAize

Carte dont les activités sont mises à jour.

$activitiesJson : string|null

Chaîne JSON attendue sous la forme [{"id": 1, "name": "..."}, ...].

$brochureFiles : mixed

Fichiers de brochures indexés par position de l'activité ; ignoré s'il ne s'agit pas d'un tableau.

$user : User

Utilisateur courant, utilisé pour appliquer les limites de taille de fichier de son offre.

$replace : bool

Si vrai, les activités existantes absentes de la charge utile sont supprimées.

getFileSizeLimit()

Détermine la limite de taille de fichier selon l'offre de l'utilisateur

private getFileSizeLimit(User $user, string $fileType) : int
Parameters
$user : User
$fileType : string
Return values
int

normalizePhoneNumber()

Normalise un numéro de téléphone au format international.

private normalizePhoneNumber(string $phoneNumber) : string

Supprime tous les caractères autres que les chiffres et le signe + (espaces, points, tirets, parenthèses). Si le résultat commence déjà par +, il est renvoyé tel quel. Sinon les zéros de tête sont retirés, puis un numéro de 9 chiffres est préfixé par l'indicatif guinéen +224 ; toute autre longueur reçoit simplement un + en tête. Aucun contrôle de validité n'est effectué : une chaîne vide reste + et un numéro déjà précédé d'un indicatif sans + n'est pas corrigé.

Parameters
$phoneNumber : string

Numéro brut saisi par l'utilisateur.

Return values
string

Numéro normalisé commençant par +.

normalizePhoneNumbersPayload()

Normalise chaque numéro d'une liste déjà structurée.

private normalizePhoneNumbersPayload(array<int, array{number?: mixed, visible?: mixed}> $phoneNumbers) : array<int, array{number: string, visible: bool}>

Applique normalizePhoneNumber() à la clé number de chaque entrée (clé absente traitée comme chaîne vide) et conserve la visibilité castée en booléen, true par défaut. Les numéros dont la normalisation produit une chaîne vide sont écartés ; en pratique le filtre ne se déclenche jamais, normalizePhoneNumber() renvoyant au minimum +. La liste résultante est réindexée à partir de zéro, ce qui permet aux appelants d'utiliser [0]['number'] comme numéro principal.

Parameters
$phoneNumbers : array<int, array{number?: mixed, visible?: mixed}>

Entrées issues de parsePhoneNumbersPayload().

Return values
array<int, array{number: string, visible: bool}>

Liste des numéros normalisés au format international.

parseMultipartPut()

Parser manuel pour récupérer les champs/fichiers en PUT multipart

private parseMultipartPut(Request $request) : array<string|int, mixed>
Parameters
$request : Request
Return values
array<string|int, mixed>

parsePhoneNumbersPayload()

Convertit une charge utile de numéros de téléphone en liste structurée.

private parsePhoneNumbersPayload(mixed $payload) : array<int, array{number: string, visible: bool}>

Accepte soit une chaîne JSON (décodée après trim()), soit directement un tableau. Toute entrée invalide est ignorée sans erreur : chaîne vide, JSON mal formé ou ne décodant pas en tableau, payload non tabulaire, élément ni chaîne ni tableau, ou numéro vide après trim(). Une entrée chaîne est transformée en ['number' => ..., 'visible' => true] ; une entrée tableau reprend sa clé number et sa clé visible castée en booléen, cette dernière valant true par défaut. Les numéros ne sont pas normalisés à ce stade (voir normalizePhoneNumbersPayload()).

Parameters
$payload : mixed

Chaîne JSON ou tableau d'entrées string ou array{number: string, visible?: mixed}.

Return values
array<int, array{number: string, visible: bool}>

Liste réindexée des numéros retenus, éventuellement vide.

setNestedValue()

Écrit une valeur dans un tableau à partir d'un nom de champ HTML éventuellement indexé.

private setNestedValue(array<string|int, mixed> &$target, string|null $name, mixed $value) : void

Ne fait rien si le nom est nul ou vide. Un nom sans crochet est affecté directement à la racine du tableau. Sinon, les crochets fermants sont retirés et le nom est éclaté sur [ pour obtenir la suite de clés : activity_brochures[0] donne ['activity_brochures', '0']. Les clés exclusivement numériques sont converties en entiers ; une clé vide (notation champ[]) provoque un ajout en fin de tableau, terminal si c'est le dernier segment, sinon création d'un sous-tableau parcouru par référence. Les niveaux intermédiaires manquants ou non tabulaires sont réinitialisés en tableaux, ce qui peut écraser une valeur scalaire déjà présente à ce niveau.

Parameters
$target : array<string|int, mixed>

Tableau modifié par référence (champs ou fichiers).

$name : string|null

Nom du champ, éventuellement de la forme a[b][0] ou a[].

$value : mixed

Valeur à écrire (chaîne du corps ou instance UploadedFile).

validateFile()

Valide un fichier uploadé

private validateFile(UploadedFile $file, array<string|int, mixed> $allowedMimeTypes, int $maxSize, User $user, string $fileType) : void
Parameters
$file : UploadedFile
$allowedMimeTypes : array<string|int, mixed>
$maxSize : int
$user : User
$fileType : string

        
On this page

Search results