[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"theme-db":3,"$fU8mJblgVVQeU7mxU4X6wGu0n6vrPtcWj8SiB77V0Y3k":22,"$fWdYmiT2Y-MdUt9HQJvirfEjXWCjNJEoLu6MiHoaJvkU":60,"megamenu":75,"$fKnz2vuX4bZz1LbUTiuFsvSZ3e07l5_5fqNYp4Tzdhi8":143,"header-db":211,"footer-db":224},{"theme":4},{"colors":5,"typography":13,"ui":17,"defaultColorMode":21},{"primary":6,"secondary":7,"background":8,"foreground":9,"muted":10,"headerBg":11,"footerBg":12,"topBarBg":9,"topBarText":11},"#4F46E5","#0D9488","#F9FAFB","#111827","#6B7280","#ffffff","#020617",{"fontFamily":14,"fontUrl":15,"baseFontSize":16},"Inter, system-ui, sans-serif","https:\u002F\u002Ffonts.googleapis.com\u002Fcss2?family=Inter:wght@400;500;600;700&family=Playfair+Display:ital,wght@0,400;0,700;0,800;0,900;1,400;1,700&display=swap","16px",{"borderRadius":18,"contentWidth":19,"shadow":20},"lg","7xl",true,"light",{"title":23,"slug":24,"metaDescription":25,"category":26,"tags":27,"difficulty":33,"psVersions":34,"content":38,"faq":39,"tldr":55,"readingTime":56,"generatedAt":57,"publishDate":57,"relatedArticles":58,"sourceCategory":59},"Récupérer l'ID d'une image après insertion en base PrestaShop","recuperer-id-image-apres-insertion-base-prestashop","Comment récupérer l'identifiant d'une image produit après insertion en base de données PrestaShop avec Insert_ID() et l'ObjectModel Image.","developpement",[28,29,30,31,32],"images produit","base de données","ObjectModel","module PrestaShop","API images","intermediaire",[35,36,37],"1.6","1.7","8.x","\u003Ch2>Le problème : synchroniser les ID d'images entre les tables PrestaShop\u003C\u002Fh2>\n\u003Cp>Lorsque vous développez un module PrestaShop qui gère l'upload d'images produit de manière programmatique, vous êtes confronté à un défi classique : la table \u003Ccode>ps_image\u003C\u002Fcode> génère un \u003Ccode>id_image\u003C\u002Fcode> en auto-incrémentation, et vous devez ensuite réutiliser cet identifiant pour alimenter les tables liées comme \u003Ccode>ps_image_shop\u003C\u002Fcode> ou \u003Ccode>ps_image_lang\u003C\u002Fcode>.\u003C\u002Fp>\n\u003Cp>Une erreur fréquente consiste à tenter de \u003Cstrong>deviner\u003C\u002Fstrong> l'ID suivant avec un calcul comme \u003Ccode>$id_image + 1\u003C\u002Fcode>. Cette approche est fondamentalement fragile : elle échoue dès qu'un autre processus insère une image entre-temps, ou si l'utilisateur n'uploade pas toutes les images prévues, créant des décalages dans la séquence d'auto-incrémentation.\u003C\u002Fp>\n\u003Ch2>Solution rapide : Db::getInstance()->Insert_ID()\u003C\u002Fh2>\n\u003Cp>La méthode \u003Ccode>Insert_ID()\u003C\u002Fcode> de la classe \u003Ccode>Db\u003C\u002Fcode> retourne le dernier identifiant auto-incrémenté généré par la connexion MySQL courante. C'est l'équivalent PrestaShop de \u003Ccode>mysqli_insert_id()\u003C\u002Fcode> ou \u003Ccode>LAST_INSERT_ID()\u003C\u002Fcode> en SQL.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n\u002F\u002F Insertion de l'image en base\n$sql = 'INSERT INTO ' . _DB_PREFIX_ . 'image (id_product, position, cover) VALUES (' . (int)$idProduct . ', 2, NULL)';\nDb::getInstance()-&gt;execute($sql);\n\n\u002F\u002F Récupération fiable de l'ID généré\n$idImage = (int)Db::getInstance()-&gt;Insert_ID();\n\n\u002F\u002F Utilisation pour ps_image_shop\n$sqlShop = 'INSERT INTO ' . _DB_PREFIX_ . 'image_shop (id_image, id_shop, cover) VALUES (' . $idImage . ', ' . (int)Context::getContext()-&gt;shop-&gt;id . ', NULL)';\nDb::getInstance()-&gt;execute($sqlShop);\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Cp>\u003Cstrong>Points importants :\u003C\u002Fstrong>\u003C\u002Fp>\n\u003Cul>\n\u003Cli>Utilisez `execute()` et non `executeS()` pour les requêtes INSERT. La méthode `executeS()` est conçue pour les SELECT et retourne un tableau de résultats.\u003C\u002Fli>\n\u003Cli>Appelez `Insert_ID()` **immédiatement** après l'INSERT, avant toute autre requête.\u003C\u002Fli>\n\u003Cli>Castez toujours en `(int)` les valeurs injectées dans vos requêtes pour prévenir les injections SQL.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Ch2>La bonne pratique : utiliser l'ObjectModel Image\u003C\u002Fh2>\n\u003Cp>Si la méthode \u003Ccode>Insert_ID()\u003C\u002Fcode> fonctionne, elle reste une approche bas niveau qui vous oblige à gérer manuellement chaque table associée. PrestaShop fournit la classe \u003Ccode>Image\u003C\u002Fcode> (ObjectModel) qui encapsule toute cette logique.\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\nuse PrestaShop\\PrestaShop\\Adapter\\Image\\ImageRetriever;\n\n\u002F\u002F Création d'une image via l'ObjectModel\n$image = new Image();\n$image-&gt;id_product = (int)$idProduct;\n$image-&gt;position = Image::getHighestPosition($idProduct) + 1;\n$image-&gt;cover = false;\n\nif ($image-&gt;add()) {\n    \u002F\u002F L'ID est automatiquement disponible\n    $idImage = (int)$image-&gt;id;\n    \n    \u002F\u002F Le dossier de destination est calculé automatiquement\n    $destinationPath = $image-&gt;getPathForCreation();\n    \n    \u002F\u002F Copie du fichier uploadé\n    ImageManager::resize(\n        $tmpFilePath,\n        $destinationPath . '.' . $image-&gt;image_format,\n        null,\n        null,\n        $image-&gt;image_format\n    );\n    \n    \u002F\u002F Génération de toutes les déclinaisons de tailles\n    $types = ImageType::getImagesTypes('products');\n    foreach ($types as $type) {\n        ImageManager::resize(\n            $tmpFilePath,\n            $destinationPath . '-' . stripslashes($type['name']) . '.' . $image-&gt;image_format,\n            (int)$type['width'],\n            (int)$type['height'],\n            $image-&gt;image_format\n        );\n    }\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch3>Avantages de l'ObjectModel par rapport au SQL brut\u003C\u002Fh3>\n\u003Ctr>\u003Cth>Aspect\u003C\u002Fth>\u003Cth>SQL brut + Insert_ID()\u003C\u002Fth>\u003Cth>ObjectModel Image\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>Tables gérées\u003C\u002Fth>\u003Cth>Manuelle (image, image_shop, image_lang)\u003C\u002Fth>\u003Cth>Automatique\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>Multiboutique\u003C\u002Fth>\u003Cth>À gérer soi-même\u003C\u002Fth>\u003Cth>Natif\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>Hooks déclenchés\u003C\u002Fth>\u003Cth>Aucun\u003C\u002Fth>\u003Cth>actionObjectImageAddAfter, etc.\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>Calcul du chemin fichier\u003C\u002Fth>\u003Cth>Manuel\u003C\u002Fth>\u003Cth>`getPathForCreation()`\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>Validation des données\u003C\u002Fth>\u003Cth>Aucune\u003C\u002Fth>\u003Cth>Validation ObjectModel\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ctr>\u003Cth>Compatibilité versions\u003C\u002Fth>\u003Cth>Fragile\u003C\u002Fth>\u003Cth>Maintenue par le core\u003C\u002Fth>\u003C\u002Ftr>\n\u003Ch2>Gestion complète d'un upload multi-images\u003C\u002Fh2>\n\u003Cp>Voici un exemple complet et robuste pour gérer l'upload de plusieurs images produit dans un module PrestaShop 8.x :\u003C\u002Fp>\n\u003Cpre>\u003Ccode class=\"language-php\">\n\u002F**\n * Associe des images uploadées à un produit PrestaShop.\n *\n * @param int $idProduct L'identifiant du produit\n * @param array $uploadedFiles Tableau de fichiers ($_FILES)\n * @return array Les IDs des images créées\n *\u002F\npublic function addProductImages(int $idProduct, array $uploadedFiles): array\n{\n    $createdIds = [];\n    $position = (int)Image::getHighestPosition($idProduct);\n\n    foreach ($uploadedFiles as $file) {\n        if ($file['error'] !== UPLOAD_ERR_OK || !$file['size']) {\n            continue;\n        }\n\n        \u002F\u002F Validation du type MIME\n        $allowedTypes = ['image\u002Fjpeg', 'image\u002Fpng', 'image\u002Fwebp', 'image\u002Fgif'];\n        if (!in_array($file['type'], $allowedTypes)) {\n            continue;\n        }\n\n        $position++;\n\n        $image = new Image();\n        $image-&gt;id_product = $idProduct;\n        $image-&gt;position = $position;\n        $image-&gt;cover = ($position === 1);\n\n        if (!$image-&gt;add()) {\n            PrestaShopLogger::addLog(\n                'Échec ajout image produit #' . $idProduct,\n                3\n            );\n            continue;\n        }\n\n        $path = $image-&gt;getPathForCreation();\n\n        \u002F\u002F Redimensionnement et copie\n        if (!ImageManager::resize(\n            $file['tmp_name'],\n            $path . '.' . $image-&gt;image_format\n        )) {\n            $image-&gt;delete();\n            continue;\n        }\n\n        \u002F\u002F Génération des miniatures\n        $types = ImageType::getImagesTypes('products');\n        foreach ($types as $type) {\n            ImageManager::resize(\n                $file['tmp_name'],\n                $path . '-' . stripslashes($type['name']) . '.' . $image-&gt;image_format,\n                (int)$type['width'],\n                (int)$type['height'],\n                $image-&gt;image_format\n            );\n        }\n\n        $createdIds[] = (int)$image-&gt;id;\n    }\n\n    \u002F\u002F Vider le cache des images produit\n    if (!empty($createdIds)) {\n        Hook::exec('actionProductUpdate', ['id_product' =&gt; $idProduct]);\n    }\n\n    return $createdIds;\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\n\u003Ch2>Évolutions entre PrestaShop 1.6 et 8.x\u003C\u002Fh2>\n\u003Cp>Le stockage des images a évolué de manière significative entre les versions :\u003C\u002Fp>\n\u003Cul>\n\u003Cli>**PrestaShop 1.6** : les images étaient stockées dans des dossiers basés sur l'ID produit (`\u002Fimg\u002Fp\u002F1\u002F2\u002F3\u002F123-home_default.jpg`). Le format de stockage \"nouveau\" (par ID image éclaté) existait déjà mais n'était pas activé par défaut.\u003C\u002Fli>\n\u003Cli>**PrestaShop 1.7+** : le format éclaté par ID image est devenu le standard. L'image avec `id_image = 456` se trouve dans `\u002Fimg\u002Fp\u002F4\u002F5\u002F6\u002F456.jpg`.\u003C\u002Fli>\n\u003Cli>**PrestaShop 8.x** : support natif du format WebP et AVIF. La classe `ImageManager` gère automatiquement la conversion si le serveur le supporte.\u003C\u002Fli>\n\u003C\u002Ful>\n\u003Cp>Le chemin retourné par \u003Ccode>getPathForCreation()\u003C\u002Fcode> tient compte de ces différences, ce qui rend l'ObjectModel encore plus pertinent pour écrire du code portable.\u003C\u002Fp>\n\u003Ch2>Erreurs courantes à éviter\u003C\u002Fh2>\n\u003Col>\n\u003Cli>**Utiliser `executeS()` pour un INSERT** : cette méthode est réservée aux SELECT. Utilisez `execute()` pour INSERT, UPDATE et DELETE.\u003C\u002Fli>\n\u003Cli>**Deviner l'ID suivant** avec `MAX(id_image) + 1` : en cas d'accès concurrent (deux clients qui uploadent en même temps), vous obtiendrez des doublons.\u003C\u002Fli>\n\u003Cli>**Oublier `ps_image_shop`** : en contexte multiboutique, une image sans entrée dans `ps_image_shop` est invisible en front-office.\u003C\u002Fli>\n\u003Cli>**Ne pas générer les miniatures** : l'insertion en base ne suffit pas. Sans les fichiers physiques redimensionnés, le front-office affichera des images cassées.\u003C\u002Fli>\n\u003Cli>**Ignorer les permissions de dossier** : le répertoire `\u002Fimg\u002Fp\u002F` doit être accessible en écriture par le processus PHP (généralement `www-data`).\u003C\u002Fli>\n\u003C\u002Ful>",[40,43,46,49,52],{"q":41,"a":42},"Comment récupérer l'ID d'une image après un INSERT en base PrestaShop ?","Utilisez la méthode Db::getInstance()->Insert_ID() immédiatement après votre requête INSERT. Cette méthode retourne le dernier identifiant auto-incrémenté généré par votre connexion MySQL. Cependant, la bonne pratique en PrestaShop est d'utiliser l'ObjectModel Image dont la propriété $image->id est automatiquement renseignée après un appel à $image->add().",{"q":44,"a":45},"Pourquoi ne pas calculer l'ID image avec MAX(id_image) + 1 en PrestaShop ?","Cette approche crée une condition de concurrence (race condition). Si deux processus exécutent le même calcul simultanément, ils obtiendront le même résultat et tenteront d'insérer le même ID, provoquant des erreurs de clé dupliquée ou des incohérences entre les tables ps_image et ps_image_shop. Insert_ID() ou l'ObjectModel résolvent ce problème nativement.",{"q":47,"a":48},"Quelle est la différence entre execute() et executeS() dans PrestaShop ?","La méthode execute() est destinée aux requêtes qui modifient les données (INSERT, UPDATE, DELETE) et retourne un booléen de succès. La méthode executeS() est conçue pour les requêtes SELECT et retourne un tableau de résultats. Utiliser executeS() pour un INSERT fonctionne techniquement mais constitue un mauvais usage qui peut provoquer des comportements inattendus.",{"q":50,"a":51},"Comment ajouter des images produit par programmation dans un module PrestaShop 8 ?","Instanciez un objet Image, définissez id_product, position et cover, puis appelez la méthode add(). Utilisez ensuite getPathForCreation() pour obtenir le chemin de destination et ImageManager::resize() pour copier et redimensionner le fichier. N'oubliez pas de générer toutes les tailles définies dans ImageType::getImagesTypes('products').",{"q":53,"a":54},"Pourquoi mes images produit n'apparaissent pas en front-office PrestaShop ?","Plusieurs causes possibles : l'entrée manque dans la table ps_image_shop (obligatoire en multiboutique), les fichiers physiques des miniatures n'ont pas été générés, les permissions du dossier \u002Fimg\u002Fp\u002F sont insuffisantes, ou le cache des images n'a pas été vidé. Utilisez l'ObjectModel Image qui gère automatiquement les entrées multiboutique et vérifiez que les miniatures existent pour tous les types d'images définis.","Pour récupérer l'ID d'une image après insertion en base PrestaShop, utilisez Db::getInstance()->Insert_ID() juste après l'INSERT. La méthode recommandée reste l'ObjectModel Image qui gère automatiquement l'ID, le multiboutique et le chemin des fichiers.",5,"2026-03-21T14:55:02.000Z",[],"Utilisation de PrestaShop : configuration et difficultés",{"academy":61,"blog":62,"expertise":74},[],[63,68,71],{"title":64,"url":65,"score":66,"type":67},"PrestaShop headless avec Nuxt 3 : pourquoi séparer back et front","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fprestashop-headless-nuxt-separation-front-back",1,"blog",{"title":69,"url":70,"score":66,"type":67},"PrestaShop headless : Nuxt 3, pas Next.js — le choix souverain","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fprestashop-headless-nuxt-nextjs-souverainete",{"title":72,"url":73,"score":66,"type":67},"Sylius rachète PrestaShop : ce que ça change pour vous","\u002Fblog\u002Fprestashop\u002Farchitecture\u002Fsylius-rachat-prestashop-headless-souverainete",[],{"items":76},[77,88,95,103,111,120,127,135],{"id":78,"type":79,"label":80,"href":82,"icon":83,"description":83,"badge":83,"groupTitle":83,"style":83,"gridColumns":83,"cssClass":83,"psCategoryId":83,"showPsChildren":84,"position":85,"children":86,"psChildren":87},41,"link",{"fr":81},"Expertise","\u002Fexpertise",null,false,0,[],[],{"id":89,"type":79,"label":90,"href":92,"icon":83,"description":83,"badge":83,"groupTitle":83,"style":83,"gridColumns":83,"cssClass":83,"psCategoryId":83,"showPsChildren":84,"position":66,"children":93,"psChildren":94},42,{"fr":91},"Blog","\u002Fblog",[],[],{"id":96,"type":79,"label":97,"href":99,"icon":83,"description":83,"badge":83,"groupTitle":83,"style":83,"gridColumns":83,"cssClass":83,"psCategoryId":83,"showPsChildren":84,"position":100,"children":101,"psChildren":102},43,{"fr":98},"Modules PrestaShop","\u002Fmodules",2,[],[],{"id":104,"type":79,"label":105,"href":107,"icon":83,"description":83,"badge":83,"groupTitle":83,"style":83,"gridColumns":83,"cssClass":83,"psCategoryId":83,"showPsChildren":84,"position":108,"children":109,"psChildren":110},44,{"fr":106},"Outils IA","\u002Foutils-ia",3,[],[],{"id":112,"type":79,"label":113,"href":115,"icon":83,"description":83,"badge":83,"groupTitle":83,"style":116,"gridColumns":83,"cssClass":83,"psCategoryId":83,"showPsChildren":84,"position":117,"children":118,"psChildren":119},45,{"fr":114},"Offre Starter ✨","\u002Foffre-starter",{"highlight":20},4,[],[],{"id":121,"type":79,"label":122,"href":124,"icon":83,"description":83,"badge":83,"groupTitle":83,"style":83,"gridColumns":83,"cssClass":83,"psCategoryId":83,"showPsChildren":84,"position":56,"children":125,"psChildren":126},46,{"fr":123},"Academy","\u002Facademy",[],[],{"id":128,"type":79,"label":129,"href":131,"icon":83,"description":83,"badge":83,"groupTitle":83,"style":83,"gridColumns":83,"cssClass":83,"psCategoryId":83,"showPsChildren":84,"position":132,"children":133,"psChildren":134},47,{"fr":130},"À propos","\u002Fa-propos",6,[],[],{"id":136,"type":79,"label":137,"href":139,"icon":83,"description":83,"badge":83,"groupTitle":83,"style":83,"gridColumns":83,"cssClass":83,"psCategoryId":83,"showPsChildren":84,"position":140,"children":141,"psChildren":142},48,{"fr":138},"Contact","\u002Fcontact",7,[],[],{"columns":144},[145,157,187,203],{"title":146,"links":147},"Plateforme",[148,150,153,154],{"label":149,"href":115,"external":84},"Offre Starter (2 500 €)",{"label":151,"href":152,"external":84},"Devenir Ambassadeur","\u002Fambassadeur",{"label":98,"href":99,"external":84},{"label":155,"href":156,"external":20},"CodeMyShop.com","https:\u002F\u002Fcodemyshop.com",{"title":158,"links":159},"Le Synedre",[160,163,166,169,172,175,178,181,184],{"label":161,"href":162,"external":84},"L'histoire","\u002Fsynedre",{"label":164,"href":165,"external":84},"Constitution","\u002Fsynedre\u002Fconstitution",{"label":167,"href":168,"external":84},"L'équipe","\u002Fequipe",{"label":170,"href":171,"external":84},"Le réacteur en direct","\u002Freacteur",{"label":173,"href":174,"external":84},"Le Drill (entraînement)","\u002Fdrill",{"label":176,"href":177,"external":84},"Protocole de réunion","\u002Fsynedre\u002Freunion",{"label":179,"href":180,"external":84},"Les agents IA","\u002Fagents-ia",{"label":182,"href":183,"external":84},"La Conduite","\u002Fsynedre\u002Fconduite",{"label":185,"href":186,"external":84},"Charte plateforme","\u002Fsynedre\u002Fcharte",{"title":188,"links":189},"Ressources",[190,191,192,195,197,200],{"label":91,"href":92,"external":84},{"label":123,"href":124,"external":84},{"label":193,"href":194,"external":84},"Dictionnaire","\u002Fdictionnaire",{"label":196,"href":82,"external":84},"Expertise PrestaShop",{"label":198,"href":199,"external":84},"Flywheel","\u002Fflywheel",{"label":201,"href":202,"external":84},"Manifeste","\u002Fmanifeste",{"title":130,"links":204},[205,207,210],{"label":206,"href":131,"external":84},"Alexandre Carette",{"label":208,"href":209,"external":84},"Dossier de presse","\u002Fpresse",{"label":138,"href":139,"external":84},{"header":212},{"logo":213,"topBar":218,"contactEmail":221,"features":222,"navBar":83},{"src":214,"alt":215,"text":206,"href":216,"class":217},"\u002Flogo-ac.svg","Alexandre Carette — Architecte E-commerce Souverain","\u002F","h-10 w-10",{"message":83,"showLanguages":84,"align":219,"languages":220},"left",[],"contact@alexandrecarette.fr",{"showSearch":84,"showWishlist":84,"showLogin":20,"showContact":84,"showCart":84,"stickyHeader":20,"headerLayout":223},"inline",{"footer":225},{"theme":226,"description":83,"hours":83,"logo":227,"contact":228,"social":229,"bottomBar":239},"dark",{"src":214,"href":216,"alt":206},{"email":83,"phone":83,"address":83,"cta":83},[230,233,236],{"platform":231,"href":232,"label":231},"linkedin","https:\u002F\u002Fwww.linkedin.com\u002Fin\u002Falexandre-carette\u002F",{"platform":234,"href":235,"label":234},"malt","https:\u002F\u002Fwww.malt.fr\u002Fprofile\u002Falexandrecarette",{"platform":237,"href":238,"label":237},"github","https:\u002F\u002Fgithub.com\u002Fprest4cafe",{"copyright":83}]