<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Consulenza Web</title>
	<atom:link href="https://www.consulenzaweb.net/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.consulenzaweb.net</link>
	<description>Il tuo esperto in rete: pillole di web marketing, web development e web design</description>
	<lastBuildDate>Mon, 23 Feb 2026 06:23:41 +0000</lastBuildDate>
	<language>it-IT</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.8.5</generator>
<site xmlns="com-wordpress:feed-additions:1">35614679</site>	<item>
		<title>Quella volta che siamo andati online con il nuovo ecommerce e ci siamo accorti che mancavano le foto dei prodotti</title>
		<link>https://www.consulenzaweb.net/2026/02/quella-volta-che-siamo-andati-online-con-il-nuovo-ecommerce-e-ci-siamo-accorti-che-mancavano-le-foto-dei-prodotti/</link>
					<comments>https://www.consulenzaweb.net/2026/02/quella-volta-che-siamo-andati-online-con-il-nuovo-ecommerce-e-ci-siamo-accorti-che-mancavano-le-foto-dei-prodotti/#respond</comments>
		
		<dc:creator><![CDATA[Emanuel Righetto]]></dc:creator>
		<pubDate>Mon, 16 Feb 2026 05:32:04 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[AIforBusiness]]></category>
		<category><![CDATA[Automation]]></category>
		<category><![CDATA[ComputerVision]]></category>
		<category><![CDATA[ConversionRate]]></category>
		<category><![CDATA[DevLife]]></category>
		<category><![CDATA[DigitalTransformation]]></category>
		<category><![CDATA[Ecommerce]]></category>
		<category><![CDATA[GrowthMindset]]></category>
		<category><![CDATA[Innovation]]></category>
		<category><![CDATA[Laravel]]></category>
		<category><![CDATA[LunarPHP]]></category>
		<category><![CDATA[Migration]]></category>
		<category><![CDATA[NextJS]]></category>
		<category><![CDATA[ProblemSolving]]></category>
		<category><![CDATA[Refactoring]]></category>
		<category><![CDATA[TechLeadership]]></category>
		<category><![CDATA[UserExperience]]></category>
		<guid isPermaLink="false">https://www.consulenzaweb.net/?p=2293</guid>

					<description><![CDATA[Nel refactoring di un e-commerce, un problema ha causato la mancanza di immagini per migliaia di prodotti. Dopo aver constatato l'assenza di backup e la sparizione di un freelance, si è sviluppata una soluzione automatizzata utilizzando PHP, Google Search e Computer Vision per recuperare immagini in modo efficiente, garantendo pertinenza e sicurezza del brand.]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><a href="https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2026/02/image.png?ssl=1"><img data-recalc-dims="1" width="750" height="563" decoding="async" loading="lazy" src="https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2026/02/image.png?resize=750%2C563&#038;ssl=1" alt="" class="wp-image-2294" srcset="https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2026/02/image.png?w=1024&amp;ssl=1 1024w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2026/02/image.png?resize=300%2C225&amp;ssl=1 300w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2026/02/image.png?resize=768%2C576&amp;ssl=1 768w" sizes="auto, (max-width: 750px) 100vw, 750px" /></a></figure>



<p>Nel refactoring di un ecommerce, ci sono due tipi di problemi:</p>



<ol class="wp-block-list">
<li>quelli previsti</li>



<li>quelli che scopri mesi dopo… quando è troppo tardi</li>
</ol>



<p>Tutti conosciamo la teoria delle migrazioni perfette: ambienti di staging, backup ridondanti, controlli QA rigorosi. E poi c&#8217;è la realtà.</p>



<p>Recentemente mi sono trovato in uno scenario da incubo durante il refactoring di un e-commerce (migrazione da WooCommerce a <strong>Next.js + LunarPHP</strong>). </p>



<p>Durante la migrazione, un freelance si occupa dell’importazione dei dati: prodotti, varianti, prezzi, categorie, media. Alla consegna facciamo controlli preliminari: tutto sembra ok, il freelance si congeda, passano settimane, poi mesi, si va online.</p>



<p>Dopo il go-live, ci accorgiamo che qualcosa non torna. Un gruppo di prodotti, nell&#8217;ordine delle migliaia, risulta senza immagini.</p>



<p>E nel commercio elettronico, un prodotto senza immagine è praticamente un prodotto invisibile:</p>



<ul class="wp-block-list">
<li>conversione bassa</li>



<li>UX compromessa</li>



<li>fiducia ridotta</li>



<li>catalogo “rotto”</li>
</ul>



<h2 class="wp-block-heading">Il disastro operativo: niente backup e freelance irreperibile</h2>



<p>A quel punto iniziano le domande: recuperiamo dal vecchio hosting? Chiediamo al freelance di rigenerare la migrazione?</p>



<p>Peccato che: il contratto con il vecchio hosting era stato disattivato e quindi sorgenti e gli upload non erano più accessibili, il freelance era impegnato su altro e quindi… sparito.</p>



<h2 class="wp-block-heading">Che si fa?</h2>



<p>La risposta classica sarebbe:</p>



<ul class="wp-block-list">
<li>ripetere shooting fotografico o recuperare manualmente immagini, magari chiedendole al fornitore</li>



<li>ricostruire tutto a mano</li>
</ul>



<p>Ma su migliaia di SKU non è una soluzione. Serviva qualcosa di diverso. Una soluzione creativa disponibile in poche ore, al massimo giorni, non settimane.</p>



<p><strong>Automatizzare l&#8217;impossibile</strong> usando PHP, Google Custom Search e Computer Vision.</p>



<p>Ma c&#8217;è un problema: cercare su Google non è semplice come sembra. <strong>Non è sempre tutto oro quel che luccica nelle prime posizioni.</strong></p>



<h2 class="wp-block-heading">Fase 1: La strategia di &#8220;scraping&#8221; (Search Fallbacks)</h2>



<p>Se cerchi <code>PRODOTTO-123 Bracciale Argento</code> potresti non trovare nulla. Magari Google ha indicizzato il prodotto, ma senza il codice SKU nel titolo. Oppure ha lo SKU, ma il nome è leggermente diverso.</p>



<p>Per questo, nel mio <code>GoogleSearchService</code>, non mi sono limitato a una singola query &#8220;secca&#8221;. Ho implementato una <strong>strategia a 4 livelli di profondità</strong> (Fallback Strategy) per &#8220;scavare&#8221; nella SERP finché non emerge qualcosa di utile.</p>



<p>Ecco come ragiona l&#8217;algoritmo quando cerca un&#8217;immagine:</p>



<ol start="1" class="wp-block-list">
<li><strong>Il Tentativo Ottimista (Query Completa)</strong> Cerca la stringa esatta: <code>SKU + Nome Prodotto</code>. È la situazione ideale, ma spesso fallisce se il vecchio sito non aveva un buon SEO o se lo SKU è interno.</li>



<li><strong>La Pulizia (Sanitization Fallback)</strong> Se il primo tentativo fallisce, l&#8217;algoritmo riprova rimuovendo la &#8220;sporcizia&#8221;. Via punteggiatura, trattini inutili e spazi doppi. Spesso Google si confonde con simboli come <code>_</code> o <code>/</code> in eccesso.</li>



<li><strong>L&#8217;Approccio Semantico (Solo Nome Prodotto)</strong> Qui si rischia di più, ma si ottengono più risultati. Se lo SKU &#8220;sporca&#8221; la ricerca, lo rimuoviamo brutalmente dalla stringa e cerchiamo solo il nome (es. &#8220;Bracciale Pandora Argento&#8221;). <em>Rischio:</em> Trovare prodotti simili ma non identici. <em>Soluzione:</em> Qui è fondamentale la validazione successiva con l&#8217;AI.</li>



<li><strong>L&#8217;Approccio Tecnico (Solo SKU)</strong> Ultima spiaggia. Cerchiamo <em>solo</em> il codice identificativo. Funziona benissimo per ricambi o elettronica, dove lo SKU è univoco nel mondo, ma malissimo per prodotti generici.</li>
</ol>



<p>Solo combinando questi quattro approcci siamo riusciti a passare dal &#8220;Nessun risultato trovato&#8221; a una lista di candidati plausibili per il 90% dei prodotti mancanti.</p>



<h2 class="wp-block-heading">Fase 2: Il Cervello (Vision + DeepL)</h2>



<p>Trovare l&#8217;immagine è solo metà dell&#8217;opera. Scaricare l&#8217;immagine sbagliata è peggio che non averne nessuna. Come distinguere un &#8220;Bracciale Pandora&#8221; dal &#8220;Vaso di Pandora&#8221; o dal pianeta di Avatar?</p>



<p>Ho creato un <code>GoogleVisionService</code> che funge da giudice imparziale:</p>



<ol start="1" class="wp-block-list">
<li><strong>Analisi Visiva:</strong> Google Cloud Vision analizza l&#8217;immagine candidata e ci dice cosa vede (es. <code>['Jewelry', 'Silver', 'Bracelet']</code>).</li>



<li><strong>Ponte Linguistico:</strong> Usiamo <strong>DeepL</strong> per tradurre le nostre keyword italiane (es. &#8220;Bracciale&#8221;) in inglese, la lingua nativa delle label di Vision.</li>



<li><strong>Relevance Score:</strong> Incrociamo i dati. Se le etichette dell&#8217;immagine matchano con le keyword tradotte del prodotto, il punteggio sale. Se il punteggio supera il <code>0.7</code> (o il 70% di confidenza), l&#8217;immagine è approvata.</li>
</ol>



<p>L’idea è stata usare Google Vision AI come “semantic gatekeeper”, quindi non come riconoscitore generico, ma come filtro semantico automatico:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>“Questa immagine appartiene davvero al contesto del prodotto?”</p>
</blockquote>



<h3 class="wp-block-heading">Il ponte linguistico è il vero &#8220;hack&#8221;</h3>



<p>Poiché Google Vision restituisce etichette in inglese, abbiamo usato <strong>DeepL</strong> (anche questo strumento è AI based) come traduttore in tempo reale degli attributi del prodotto. Questo ci ha permesso di confrontare &#8220;Silver&#8221; (etichetta AI) con &#8220;Argento&#8221; (attributo colore presente a DB), garantendo che il match semantico non andasse perso nella traduzione. Un saluto a Silver, il creatore di <a href="https://it.wikipedia.org/wiki/Lupo_Alberto" data-type="link" data-id="https://it.wikipedia.org/wiki/Lupo_Alberto" target="_blank" rel="noreferrer noopener">Lupo Aberto</a>, che grazie a questo hack non è finito in mezzo alle foto dei prodotti.</p>



<h3 class="wp-block-heading">Non solo pertinenza: la sicurezza del Brand</h3>



<p>Quando automatizzi il download di immagini da Google, il rischio &#8220;contenuti inappropriati&#8221; è dietro l&#8217;angolo. Nel codice ho integrato un filtro basato sulla <strong>SafeSearch detection</strong> di Vision AI. Se l&#8217;algoritmo rileva una probabilità elevata di contenuti <code>adult</code>, <code>violence</code> o <code>racy</code>, l&#8217;immagine viene scartata a prescindere dal punteggio di pertinenza. Automatizzare sì, ma con la cintura di sicurezza allacciata.</p>



<h3 class="wp-block-heading">Paragrafo per gli smanettoni: apriamo il cofano</h3>



<p>NB: Se ti basta quanto hai letto nella Fase 2, puoi passare alla Fase 3.</p>



<h4 class="wp-block-heading">Cosa restituisce davvero Vision (labelAnnotations, score e topicality)</h4>



<p>Per ogni immagine candidata, Google Cloud Vision non “indovina il prodotto”, ma restituisce un set di <em>etichette</em> (label) con un livello di confidenza. Questo output è perfetto per trasformare Vision in un filtro semantico: non cerco la verità assoluta, cerco indizi coerenti col contesto.</p>



<p>Ecco un esempio (ridotto) di risposta per una foto che Vision interpreta come gioielleria:</p>



<pre class="wp-block-code"><code>{
  "responses": &#91;
    {
      "labelAnnotations": &#91;
        { "description": "Jewelry", "score": 0.92, "topicality": 0.92 },
        { "description": "Bracelet", "score": 0.88, "topicality": 0.88 },
        { "description": "Silver", "score": 0.84, "topicality": 0.84 },
        { "description": "Fashion accessory", "score": 0.79, "topicality": 0.79 }
      ],
      "safeSearchAnnotation": {
        "adult": "VERY_UNLIKELY",
        "violence": "VERY_UNLIKELY",
        "racy": "UNLIKELY"
      }
    }
  ]
}</code></pre>



<p>Due dettagli importanti:</p>



<ul class="wp-block-list">
<li><strong>description</strong> è la label (spesso in inglese);</li>



<li><strong>score</strong> e <strong>topicality</strong> sono indicatori di confidenza/pertinenza, utili per pesare le evidenze (non tutte le label “valgono” uguale).</li>
</ul>



<h4 class="wp-block-heading">Il ponte linguistico: dall’italiano del catalogo alle label in inglese</h4>



<p>Il catalogo e gli attributi (colore/materiale/tipologia) erano in italiano: “bracciale”, “argento”, “ciondolo”. Vision mi rispondeva con “bracelet”, “silver”, “jewelry”. Qui entra in gioco DeepL: traduco in tempo reale (o con cache) un set di keyword “core” e confronto mele con mele.</p>



<p>In pratica genero un vocabolario atteso in inglese (derivato da nome prodotto + attributi) e poi uso le label Vision come evidenze.</p>



<h4 class="wp-block-heading">Lo scoring: pertinenza, ambiguità semantica e “forbidden labels”</h4>



<p>Un match string-based puro è fragile. Quello che ha funzionato è un piccolo modello di scoring:</p>



<ol class="wp-block-list">
<li>prendo le label Vision più forti (es. top 8 per topicality);</li>



<li>premio le label presenti nel set “expected” (tradotto da IT → EN);</li>



<li>penalizzo label che indicano un contesto <em>alternativo</em> (es. “Vase”, “Mythology”, “Planet”, “Logo”);</li>



<li>scarto a prescindere se SafeSearch segnala rischi (adult/violence/racy).</li>
</ol>



<p>Ecco uno snippet (semplificato) che rende l’idea:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
$expected = &#x5B;&#039;jewelry&#039;, &#039;bracelet&#039;, &#039;silver&#039;, &#039;necklace&#039;, &#039;ring&#039;];      // da prodotto/attributi via DeepL
$forbidden = &#x5B;&#039;vase&#039;, &#039;mythology&#039;, &#039;logo&#039;, &#039;software&#039;, &#039;planet&#039;];      // contesti “trappola”

$labels = collect($visionLabels) // es. da labelAnnotations
  -&gt;sortByDesc(fn($l) =&gt; $l&#x5B;&#039;topicality&#039;] ?? $l&#x5B;&#039;score&#039;])
  -&gt;take(8)
  -&gt;map(fn($l) =&gt; strtolower($l&#x5B;&#039;description&#039;]))
  -&gt;values();

$score = 0.0;

// Reward/Penalty semplice ma efficace
foreach ($labels as $label) {
  if (in_array($label, $expected, true)) {
    $score += 0.18;      // reward
  }
  if (in_array($label, $forbidden, true)) {
    $score -= 0.45;      // penalty forte: evita disastri tipo “Pandora = vaso”
  }
}

// Bonus se Vision è molto “sicuro” della prima label
$top = $visionLabels&#x5B;0] ?? null;
if ($top &amp;&amp; (($top&#x5B;&#039;score&#039;] ?? 0) &gt;= 0.90)) {
  $score += 0.10;
}

// SafeSearch: cintura di sicurezza
if ($safeSearch&#x5B;&#039;adult&#039;] === &#039;LIKELY&#039; || $safeSearch&#x5B;&#039;adult&#039;] === &#039;VERY_LIKELY&#039;) {
  return &#x5B;&#039;ok&#039; =&gt; false, &#039;score&#039; =&gt; $score, &#039;reason&#039; =&gt; &#039;SafeSearch: adult&#039;];
}

return &#x5B;
  &#039;ok&#039; =&gt; $score &gt;= 0.70,
  &#039;score&#039; =&gt; round($score, 2),
  &#039;labels&#039; =&gt; $labels-&gt;all(),
];
</pre></div>


<p>La cosa interessante non è tanto il valore delle costanti (che ho tarato per tentativi), ma l’idea: l’AI produce feature (label), e io costruisco sopra una policy deterministica che gestisce ambiguità semantiche. “Pandora” diventa un caso gestibile: gioiello vs mito vs altro.</p>



<h2 class="wp-block-heading">Fase 3: Persistenza e audit trail, perché Spatie Media Library è stata una scelta “da produzione”</h2>



<p>Una volta validata l’immagine, non volevo solo “attaccarla al prodotto”. Volevo anche poter rispondere, mesi dopo, a domande del tipo:</p>



<ul class="wp-block-list">
<li>Da dove arriva questa immagine?</li>



<li>Con quale query è stata trovata?</li>



<li>Quali label Vision hanno portato all’approvazione?</li>



<li>Con quale score e con che decisione SafeSearch?</li>
</ul>



<p>Qui Spatie Media Library è perfetta: offre un’API fluida per associare file ai modelli Eloquent e, soprattutto, permette di salvare metadati strutturati tramite <a href="https://spatie.be/docs/laravel-medialibrary/v11/advanced-usage/using-custom-properties" data-type="link" data-id="https://spatie.be/docs/laravel-medialibrary/v11/advanced-usage/using-custom-properties" target="_blank" rel="noreferrer noopener"><code>withCustomProperties()</code> (JSON)</a>, recuperabili e ispezionabili in modo pulito.</p>



<p>Nel mio caso ho salvato sia l’evidenza (Vision) sia la provenienza (Search):</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
$variantModel-&gt;addMedia($tempFile)
    -&gt;withCustomProperties(&#x5B;
        &#039;image_source&#039; =&gt; &#039;google&#039;,
        &#039;google_search&#039; =&gt; &#x5B;
            &#039;query&#039; =&gt; $query,
            &#039;url&#039; =&gt; $imageUrl,
            &#039;rank&#039; =&gt; $rank,
        ],
        &#039;validation&#039; =&gt; &#x5B;
            &#039;score&#039; =&gt; $decision&#x5B;&#039;score&#039;],
            &#039;labels&#039; =&gt; $decision&#x5B;&#039;labels&#039;],
            &#039;safe_search&#039; =&gt; $safeSearch,
            &#039;approved_at&#039; =&gt; now()-&gt;toIso8601String(),
        ],
    ])
    -&gt;toMediaCollection(&#039;images&#039;);
</pre></div>


<p>Il vantaggio pratico è enorme: se domani devo “spiegare” un’immagine o rifare una parte del processo, ho tutto in chiaro nei metadati del media item (e posso persino costruire strumenti interni per filtrare/ricontrollare le immagini già importate).</p>



<p>In altre parole: non ho solo ripopolato un catalogo. Ho costruito un processo ripetibile, tracciabile, e difendibile.</p>



<h2 class="wp-block-heading">Il Risultato</h2>



<p>Lanciando il comando <code>products:fetch-variant-images</code>, il terminale ha iniziato a raccontare una storia:</p>



<ul class="wp-block-list">
<li><code>&#x1f50d; Processing SKU: 123-PND...</code></li>



<li><code>&#x26a0; Query completa: 0 risultati.</code></li>



<li><code>&#x1f504; Fallback #2 (Solo Nome): Trovate 5 immagini.</code></li>



<li><code>&#x1f50e; Validating image #1... Score: 0.15 (Rejected: Low relevance)</code></li>



<li><code>&#x1f50e; Validating image #2... Score: 0.92 (Validated!)</code></li>



<li><code>&#x2705; Image attached.</code></li>
</ul>



<p>L&#8217;algoritmo ha &#8220;ragionato&#8221; come un umano: ha provato a cercare in modo specifico, poi ha allargato il campo, e infine ha usato gli occhi (digitali) per scartare i falsi positivi.</p>



<h2 class="wp-block-heading">AI come filtro operativo, non come “magia”</h2>



<p>Questa è stata la parte più interessante del progetto: Google Vision non ha “risolto tutto”.</p>



<p>Ma ha permesso di costruire un sistema di cernita automatica:</p>



<ul class="wp-block-list">
<li>Google Search = recall (trova candidate)</li>



<li>Vision AI = precision (filtra semanticamente)</li>



<li>Lunar Attach = persistenza finale</li>
</ul>



<p>Una pipeline ingegneristica completa.</p>



<h2 class="wp-block-heading">Conclusioni</h2>



<p>L&#8217;AI nel web development non serve solo a generare codice. In questo caso, l&#8217;uso combinato di <strong>Logica di Fallback</strong> (per la ricerca) e <strong>Computer Vision</strong> (per la validazione) ha trasformato un disastro annunciato in un catalogo ripopolato automaticamente.</p>



<p>A volte, quando perdi i sorgenti, sei costretto a scrivere codice migliore di quello che avevi prima.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.consulenzaweb.net/2026/02/quella-volta-che-siamo-andati-online-con-il-nuovo-ecommerce-e-ci-siamo-accorti-che-mancavano-le-foto-dei-prodotti/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2293</post-id>	</item>
		<item>
		<title>Il mio 2025: un anno di architetture, standard e scelte tecniche consapevoli</title>
		<link>https://www.consulenzaweb.net/2025/12/il-mio-2025-un-anno-di-architetture-standard-e-scelte-tecniche-consapevoli/</link>
					<comments>https://www.consulenzaweb.net/2025/12/il-mio-2025-un-anno-di-architetture-standard-e-scelte-tecniche-consapevoli/#respond</comments>
		
		<dc:creator><![CDATA[Emanuel Righetto]]></dc:creator>
		<pubDate>Wed, 24 Dec 2025 14:34:10 +0000</pubDate>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Sicurezza]]></category>
		<category><![CDATA[Accessibilità]]></category>
		<category><![CDATA[aws]]></category>
		<category><![CDATA[CD/CI]]></category>
		<category><![CDATA[cloudwatch]]></category>
		<category><![CDATA[Drupal]]></category>
		<category><![CDATA[Legacy]]></category>
		<guid isPermaLink="false">https://www.consulenzaweb.net/?p=2289</guid>

					<description><![CDATA[Il 2025 è stato un anno in cui gran parte del lavoro non è stata “scrivere codice”, ma decidere dove metterlo, perché e con quali compromessi. Molti dei progetti affrontati avevano una caratteristica comune:sistemi esistenti, stratificati, con vincoli reali (budget, legacy, team distribuiti, infrastrutture già in produzione). Di seguito una sintesi delle principali aree su cui ho lavorato. 1. Drupal ... <a class="read-more" href="https://www.consulenzaweb.net/2025/12/il-mio-2025-un-anno-di-architetture-standard-e-scelte-tecniche-consapevoli/">Read More</a>]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><a href="https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2025/10/image.png?ssl=1"><img data-recalc-dims="1" width="750" height="563" decoding="async" loading="lazy" src="https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2025/10/image.png?resize=750%2C563&#038;ssl=1" alt="" class="wp-image-2273" srcset="https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2025/10/image.png?w=1024&amp;ssl=1 1024w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2025/10/image.png?resize=300%2C225&amp;ssl=1 300w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2025/10/image.png?resize=768%2C576&amp;ssl=1 768w" sizes="auto, (max-width: 750px) 100vw, 750px" /></a></figure>



<p>Il 2025 è stato un anno in cui gran parte del lavoro non è stata “scrivere codice”, ma <strong>decidere dove metterlo, perché e con quali compromessi</strong>.</p>



<p>Molti dei progetti affrontati avevano una caratteristica comune:<br>sistemi esistenti, stratificati, con vincoli reali (budget, legacy, team distribuiti, infrastrutture già in produzione).</p>



<p>Di seguito una sintesi delle principali aree su cui ho lavorato.</p>



<h2 class="wp-block-heading">1. Drupal avanzato e sviluppo orientato alla manutenibilità</h2>



<p>Nel 2025 Drupal è stato il fulcro di diversi progetti complessi, spesso in contesti enterprise o multisite.</p>



<p>Temi ricorrenti:</p>



<ul class="wp-block-list">
<li>sviluppo di <strong>moduli custom Drupal 9/10/11</strong></li>



<li>override di plugin manager e access control handler</li>



<li>utilizzo avanzato del modulo Group e dei suoi enabler</li>



<li>comandi <strong>Drush custom</strong> per audit e standardizzazione delle configurazioni</li>



<li>gestione e uniformazione di <strong>ambienti multisite (decine di installazioni)</strong></li>
</ul>



<p>L’obiettivo non era “far funzionare il sito”, ma:</p>



<ul class="wp-block-list">
<li>ridurre la divergenza tra ambienti</li>



<li>rendere ripetibili le operazioni</li>



<li>trasformare configurazioni implicite in <strong>regole esplicite e verificabili</strong></li>
</ul>



<h2 class="wp-block-heading">2. Cloud, DevOps e automazione pragmatica</h2>



<p>L’infrastruttura non è stata trattata come un livello separato, ma come parte integrante del design applicativo.</p>



<p>Attività principali:</p>



<ul class="wp-block-list">
<li>AWS (EC2, IAM, SSM)</li>



<li>pipeline <strong>CI/CD senza accesso SSH diretto</strong></li>



<li>automazioni Bash e systemd</li>



<li>strategie di <strong>disaster recovery multi-cloud</strong></li>



<li>utilizzo di <strong>Terraform / OpenTofu</strong> come strumento di controllo, non solo di provisioning</li>



<li>migrazione e troubleshooting <strong>Elasticsearch → OpenSearch</strong></li>
</ul>



<p>Il filo conduttore: <strong>minimizzare le dipendenze implicite</strong> e rendere ogni passaggio osservabile e riproducibile.</p>



<h2 class="wp-block-heading">3. Legacy, integrazioni e refactoring controllato</h2>



<p>Una parte significativa del lavoro ha riguardato sistemi non moderni, ma ancora centrali per il business.</p>



<p>Esempi concreti:</p>



<ul class="wp-block-list">
<li>integrazione delle API REST PayPal in applicazioni <strong>ASP.NET Web Forms</strong></li>



<li>refactoring progressivo senza rompere la retrocompatibilità</li>



<li>separazione delle responsabilità (helper HTTP, builder di payload, controllo del flusso)</li>



<li>riduzione del coupling senza “riscritture eroiche”</li>
</ul>



<p>Qui il tema non è stato l’upgrade tecnologico in sé, ma <strong>la riduzione del rischio</strong>.</p>



<h2 class="wp-block-heading">4. Standardizzazione, accessibilità e qualità nel tempo</h2>



<p>Nel 2025 ho lavorato spesso su aspetti che raramente fanno headline, ma che fanno la differenza nel medio periodo:</p>



<ul class="wp-block-list">
<li>accessibilità digitale (EAA, WCAG)</li>



<li>coerenza editoriale</li>



<li>qualità delle configurazioni</li>



<li>governance tecnica</li>
</ul>



<p>Standardizzare non significa irrigidire, ma:</p>



<p>rendere il sistema prevedibile anche per chi non lo ha progettato.</p>



<h2 class="wp-block-heading">5. Tecnologia applicata a contesti non “enterprise”</h2>



<p>Parallelamente ai progetti più strutturati, ho continuato ad applicare competenze tecniche a:</p>



<ul class="wp-block-list">
<li>eventi culturali e musicali</li>



<li>associazioni locali</li>



<li>progetti personali (musica, fotografia)</li>
</ul>



<p>Stesso approccio, contesti diversi:</p>



<ul class="wp-block-list">
<li>semplicità operativa</li>



<li>resilienza</li>



<li>documentazione</li>



<li>rispetto delle persone che useranno il sistema</li>
</ul>



<h2 class="wp-block-heading">Conclusione</h2>



<p>Il 2025 non è stato un anno di hype tecnologico.<br>È stato un anno di <strong>scelte architetturali</strong>, di pulizia, di allineamento tra codice, infrastruttura e persone.</p>



<p>Meno soluzioni brillanti.<br>Più sistemi che continuano a funzionare anche quando chi li ha scritti non è più lì.</p>



<p>Ed è esattamente il tipo di lavoro che mi interessa fare.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.consulenzaweb.net/2025/12/il-mio-2025-un-anno-di-architetture-standard-e-scelte-tecniche-consapevoli/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2289</post-id>	</item>
		<item>
		<title>J’accuse: Contro i Programmatori che Ignorano Git</title>
		<link>https://www.consulenzaweb.net/2025/12/jaccuse-contro-i-programmatori-che-ignorano-git/</link>
					<comments>https://www.consulenzaweb.net/2025/12/jaccuse-contro-i-programmatori-che-ignorano-git/#respond</comments>
		
		<dc:creator><![CDATA[Emanuel Righetto]]></dc:creator>
		<pubDate>Sat, 06 Dec 2025 06:15:43 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Dev Life]]></category>
		<category><![CDATA[Git]]></category>
		<category><![CDATA[Magento]]></category>
		<guid isPermaLink="false">https://www.consulenzaweb.net/?p=2283</guid>

					<description><![CDATA[Ovvero: un girone dantesco per chi copia composer.json invece di fare commit Il Misfatto Mi sono trovato davanti a questo scempio: E mentre contemplavo questo olocausto della ragione, ho capito: serve un girone dantesco dedicato. Il Nono Cerchio dell’Inferno dei Programmatori Girone dei Traditori del Version Control «Nel mezzo del cammin della nostra codebasemi ritrovai per una selva oscuraché la ... <a class="read-more" href="https://www.consulenzaweb.net/2025/12/jaccuse-contro-i-programmatori-che-ignorano-git/">Read More</a>]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><a href="https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2025/12/Divina-Commedia.webp?ssl=1"><img data-recalc-dims="1" width="750" height="422" decoding="async" loading="lazy" src="https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2025/12/Divina-Commedia.webp?resize=750%2C422&#038;ssl=1" alt="Inferno dantesco" class="wp-image-2284" srcset="https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2025/12/Divina-Commedia.webp?resize=1024%2C576&amp;ssl=1 1024w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2025/12/Divina-Commedia.webp?resize=300%2C169&amp;ssl=1 300w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2025/12/Divina-Commedia.webp?resize=768%2C432&amp;ssl=1 768w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2025/12/Divina-Commedia.webp?resize=1536%2C864&amp;ssl=1 1536w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2025/12/Divina-Commedia.webp?w=1600&amp;ssl=1 1600w" sizes="auto, (max-width: 750px) 100vw, 750px" /></a></figure>



<h2 class="wp-block-heading" id="ovvero-un-girone-dantesco-per-chi-copia-composer.json-invece-di-fare-commit">Ovvero: un girone dantesco per chi copia composer.json invece di fare commit</h2>



<h3 class="wp-block-heading" id="il-misfatto">Il Misfatto</h3>



<p>Mi sono trovato davanti a questo scempio:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
composer.json
composer.json.bak245p8
composer.json.bak245p8bis
composer.lock
composer-lock

</pre></div>


<p>E mentre contemplavo questo olocausto della ragione, ho capito: serve un girone dantesco dedicato.</p>



<h2 class="wp-block-heading" id="il-nono-cerchio-dellinferno-dei-programmatori">Il Nono Cerchio dell’Inferno dei Programmatori</h2>



<h3 class="wp-block-heading" id="girone-dei-traditori-del-version-control"><strong>Girone dei Traditori del Version Control</strong></h3>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>«Nel mezzo del cammin della nostra codebase<br>mi ritrovai per una selva oscura<br>ché la retta via di git era smarrita»</p>
</blockquote>



<h3 class="wp-block-heading" id="le-pene-eterne">Le Pene Eterne</h3>



<p><strong>I. La Bolgia dei Suffissatori Compulsivi</strong></p>



<p>Qui soffrono coloro che invece di fare&nbsp;<code>git commit</code>&nbsp;aggiungono&nbsp;<code>.bak</code>,&nbsp;<code>.old</code>,&nbsp;<code>.backup</code>,&nbsp;<code>.2</code>,&nbsp;<code>.final</code>,&nbsp;<code>.final2</code>,&nbsp;<code>.final_DEFINITIVO</code>,&nbsp;<code>.final_DEFINITIVO_stavolta_si</code>.</p>



<p><em>Pena:</em>&nbsp;Condannati a cercare per l’eternità quale sia la versione giusta tra 47 file con nomi simili, mentre un demonio alle loro spalle urla “ERA NELL’ALTRO .BAK!”</p>



<p><strong>II. Il Pozzo dei Commentatori di Codice</strong></p>



<p>Programmatori che invece di cancellare codice vecchio lo commentano “per sicurezza”, creando migliaia di righe di codice zombie.</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: php; title: ; notranslate">
// function vecchia() {
// // non cancellarla mai
// // potrebbe servire
// // chi lo sa
// }

</pre></div>


<p><em>Pena:</em>&nbsp;Leggere all’infinito codice commentato cercando di capire quale pezzo sia ancora in uso, mentre il codice commentato si moltiplica più velocemente di quanto possano leggere.</p>



<p><strong>III. La Palude dei Maledetti composer.json</strong></p>



<p>Il cerchio più profondo. Qui dimorano coloro che:</p>



<ul class="wp-block-list">
<li>Copiano&nbsp;<code>composer.json</code>&nbsp;invece di fare branch</li>



<li>Creano&nbsp;<code>composer.json.bak245p8bis</code>&nbsp;(BIS! C’ERA GIÀ UN .bak245p8!)</li>



<li>Usano anche un altro pattern per fare la copia di&nbsp;<code>composer.lock</code>&nbsp;e ti buttano li in scioltezza un&nbsp;<code>composer-lock</code></li>



<li>Fanno&nbsp;<code>composer update</code>&nbsp;in produzione alle 3 di notte</li>



<li>Committano&nbsp;<code>vendor/</code>&nbsp;nel repository</li>
</ul>



<p><em>Pena:</em>&nbsp;Condannati a risolvere dependency conflict infiniti mentre ogni loro&nbsp;<code>composer install</code>&nbsp;installa versioni random di librerie incompatibili tra loro. Il comando&nbsp;<code>composer update</code>&nbsp;impiega 40 giorni e alla fine fallisce sempre con “Your requirements could not be resolved”.</p>



<h3 class="wp-block-heading" id="il-peccato-supremo-il-caso-magento-2">IL PECCATO SUPREMO: Il Caso Magento 2</h3>



<p>Ma c’è di peggio. Oh, c’è MOLTO di peggio.</p>



<p>Perché questa non è una codebase qualunque. Questa è&nbsp;<strong>Magento 2</strong>.</p>



<p>E questi maledetti hanno commesso il peccato imperdonabile: hanno installato lo stesso modulo (<code>Amasty_CheckoutThankYouPage</code>) in DUE POSTI DIVERSI:</p>



<ul class="wp-block-list">
<li>Una volta tramite Composer in&nbsp;<code>vendor/</code></li>



<li>Una volta copiato manualmente in&nbsp;<code>app/code/</code></li>
</ul>



<p>Il risultato?</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">
Autoload error: Module &#039;Amasty_CheckoutThankYouPage&#039; from &#039;/var/www/html/app/code/Amasty/CheckoutThankYouPage&#039; 
has been already defined 
</pre></div>


<p><strong>Magento non sa quale usare. Io non so quale sia aggiornato. Dio stesso ha perso la speranza.</strong></p>



<p>Ora dovrò passare ORE a:</p>



<ol class="wp-block-list">
<li>Controllare quale versione è in&nbsp;<code>vendor/</code></li>



<li>Controllare quale versione è in&nbsp;<code>app/code/</code></li>



<li>Verificare quale è quella “vera”</li>



<li>Capire se le dipendenze in&nbsp;<code>composer.lock</code>&nbsp;corrispondono a quello che c’è realmente</li>



<li>Scoprire quali altri moduli sono duplicati</li>



<li>Piangere silenziosamente</li>



<li>Bestemmiare rumorosamente</li>



<li>Scrivere questo pamphlet</li>
</ol>



<p><strong>Questo</strong>&nbsp;è il vero inferno: non solo non hanno usato git, ma hanno violato la regola fondamentale di Magento 2:&nbsp;<strong>O composer O app/code/, MAI ENTRAMBI PER LO STESSO MODULO</strong>.</p>



<h3 class="wp-block-heading" id="laccusa-formale">L’Accusa Formale</h3>



<p><strong>Io accuso</strong>&nbsp;questi programmatori di:</p>



<ol class="wp-block-list">
<li><strong>Crimini contro l’Umanità Digitale</strong>: Aver reso impossibile capire quali modifiche sono state fatte, quando, e perché.</li>



<li><strong>Tradimento della Fiducia</strong>: Git esiste dal 2005. DUEMILA-CINQUE. Vent’anni per imparare&nbsp;<code>git add</code>,&nbsp;<code>git commit</code>,&nbsp;<code>git push</code>. Non è chiedere troppo.</li>



<li><strong>Pigrizia Attiva</strong>: Perché copiare un file e rinominarlo richiede&nbsp;<em>più</em>&nbsp;sforzo che fare un commit. È pigrizia che genera lavoro extra. È pigrizia inefficiente. È la peggiore forma di pigrizia.</li>



<li><strong>Assassinio della Collaborazione</strong>: Come dovrebbe lavorare un team quando il “version control” consiste nel leggere i nomi dei backup come foglie di tè?</li>



<li><strong>Devastazione del Composer.json</strong>: Un file elegante, semplice, che dichiara le dipendenze del progetto. Ridotto a un arlecchino di backup incomprensibili.</li>



<li><strong>Doppia Installazione dei Moduli</strong>: Il crimine più grave in Magento 2. Installare lo stesso modulo sia via Composer che copiandolo in app/code/. Questo non è solo ignoranza. È sabotaggio attivo.</li>
</ol>



<h3 class="wp-block-heading" id="la-sentenza">La Sentenza</h3>



<p>Git non è un optional. Non è “roba da smanettoni”. Non è “complicato”.</p>



<p>È il MINIMO sindacale della professione.</p>



<p>È come un idraulico che non sa dove si chiude l’acqua.</p>



<p>È come un elettricista che non sa distinguere fase e neutro.</p>



<p>È come un chirurgo che dice “i guanti? Mah, se ho tempo”.</p>



<h3 class="wp-block-heading" id="appello-alle-generazioni-future">Appello alle Generazioni Future</h3>



<p>Giovani sviluppatori, ascoltate bene:</p>



<ul class="wp-block-list">
<li><strong>Non copiate mai</strong>&nbsp;file sorgente per “tenerli da parte”</li>



<li><strong>Git è vostro amico</strong>: ogni modifica merita un commit</li>



<li><strong>I branch esistono</strong>: usateli invece di creare file paralleli</li>



<li><strong>Composer.lock è sacro</strong>: va committato, non duplicato</li>



<li><strong>Vendor/ non va committato</strong>: MAI</li>
</ul>



<p>E se un giorno vi trovate a scrivere&nbsp;<code>composer.json.bak2</code>:</p>



<p><strong>FERMATEVI.</strong></p>



<p>Respirate.</p>



<p>Fate quel commit che state rimandando.</p>



<p>Non diventate anche voi abitanti del nono cerchio.</p>



<h3 class="wp-block-heading" id="post-scriptum">Post Scriptum</h3>



<p>Al collega dev stolto che ha creato&nbsp;<code>.bak245p8bis</code>:</p>



<p>Ti perdono.</p>



<p>Ma solo dopo che avrai fatto un corso di git.</p>



<p>E una confessione pubblica su Stack Overflow.</p>



<p>E 100 ore di community service sistemando repository aziendali.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>«Lasciate ogne speranza, voi ch’intrate…</p>



<p>…in una codebase senza git»</p>
</blockquote>



<p><strong>Fine del J’accuse</strong></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.consulenzaweb.net/2025/12/jaccuse-contro-i-programmatori-che-ignorano-git/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2283</post-id>	</item>
		<item>
		<title>Drupal Canvas e Display Builder: due strade verso lo stesso obiettivo</title>
		<link>https://www.consulenzaweb.net/2025/11/drupal-canvas-e-display-builder-due-strade-verso-lo-stesso-obiettivo/</link>
					<comments>https://www.consulenzaweb.net/2025/11/drupal-canvas-e-display-builder-due-strade-verso-lo-stesso-obiettivo/#respond</comments>
		
		<dc:creator><![CDATA[Emanuel Righetto]]></dc:creator>
		<pubDate>Thu, 20 Nov 2025 05:51:38 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Design System]]></category>
		<category><![CDATA[Drupal]]></category>
		<guid isPermaLink="false">https://www.consulenzaweb.net/?p=2280</guid>

					<description><![CDATA[Al recente DrupalCamp Italy ho scelto di parlare di Drupal Canvas, dopo averlo visto presentare in grande stile alla DrupalCon di Vienna, con ben due talk dedicati. A Roma ho avuto anche modo di incontrare Michaël Fanini e Pierre Dureau del team UI Suite e di seguire il loro intervento “Display Builder, il visual builder nativo dei design system di ... <a class="read-more" href="https://www.consulenzaweb.net/2025/11/drupal-canvas-e-display-builder-due-strade-verso-lo-stesso-obiettivo/">Read More</a>]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-full"><a href="https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2025/11/Screenshot-2025-11-20-alle-06.39.05.png?ssl=1"><img data-recalc-dims="1" width="750" height="531" decoding="async" loading="lazy" src="https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2025/11/Screenshot-2025-11-20-alle-06.39.05.png?resize=750%2C531&#038;ssl=1" alt="" class="wp-image-2281" srcset="https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2025/11/Screenshot-2025-11-20-alle-06.39.05.png?w=1005&amp;ssl=1 1005w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2025/11/Screenshot-2025-11-20-alle-06.39.05.png?resize=300%2C213&amp;ssl=1 300w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2025/11/Screenshot-2025-11-20-alle-06.39.05.png?resize=768%2C544&amp;ssl=1 768w" sizes="auto, (max-width: 750px) 100vw, 750px" /></a></figure>



<p>Al recente DrupalCamp Italy ho scelto di parlare di <strong>Drupal Canvas</strong>, dopo averlo visto presentare in grande stile alla DrupalCon di Vienna, con ben due talk dedicati.</p>



<p>A Roma ho avuto anche modo di incontrare <strong>Michaël Fanini</strong> e <strong>Pierre Dureau</strong> del team <a href="https://www.drupal.org/project/ui_suite" target="_blank" rel="noopener noreferrer">UI Suite</a> e di seguire il loro intervento <em>“Display Builder, il visual builder nativo dei design system di UI Suite”</em>.</p>



<h2 class="wp-block-heading">Due approcci, stesso problema da risolvere</h2>



<p><em>Canvas </em>e <em>Display Builder</em>, pur con approcci diversi, provano a risolvere lo stesso problema: <strong>ridurre la dipendenza dai tempi dei developer nella modellazione delle pagine</strong> e dare più autonomia operativa ai site builder.</p>



<p>In un mondo in cui strumenti come <strong>Squarespace</strong>, <strong>Webflow</strong> e <strong>Framer</strong> permettono anche a chi non scrive codice di ottenere pagine perfettamente funzionanti, i CMS tradizionali fanno ancora fatica a tenere il passo.</p>



<p>In pratica si tratta di <strong>ridurre tempi e passaggi di mano</strong> tra:</p>



<ul class="wp-block-list">
<li>il design concepito (spesso in Figma),</li>



<li>la definizione di componenti riutilizzabili,</li>



<li>la costruzione effettiva delle pagine nel CMS.</li>
</ul>



<h2 class="wp-block-heading">Un déjà-vu dal mondo WordPress</h2>



<p>Esattamente un anno fa ho seguito come consulente un team che, per alcuni progetti <strong>WordPress</strong>, mi chiedeva proprio questo: come ridurre la distanza tra l’output di Figma e la creazione di componenti riutilizzabili nel sito.</p>



<p>Lì i page builder non mancano di certo: <strong>Elementor</strong>, <strong>Gutenberg</strong>, <strong>WPBakery</strong>, e molti altri. Forse sono persino troppi, ma la direzione è chiara: <strong>meno attrito tra design e contenuto</strong>.</p>



<h2 class="wp-block-heading">Ora è il turno di Drupal</h2>



<p>Oggi anche Drupal è pronto per questo salto. Sia <strong>Canvas</strong> che <em>Display Builder</em> consentono di <strong>recepire e utilizzare Design System definiti altrove</strong> (ad esempio in uno Storybook) e portarli più vicino a chi costruisce pagine ogni giorno.</p>



<p>Il risultato atteso è chiaro: <strong>loop di feedback più brevi</strong> e maggiore velocità nel trasformare il design in pagine reali.</p>



<hr class="wp-block-separator has-alpha-channel-opacity"/>



<p>Il mio talk al DrupalCamp Italy è stato l’occasione per mettere questi temi sul tavolo e confrontarmi con la community. Ecco un po&#8217; di materiale:</p>



<ul class="wp-block-list">
<li>le <strong>slide</strong> del talk: <a href="https://docs.google.com/presentation/d/1p-bVbkM_BKPtJe8U4ZI8DISVrBkWuGtvpM5smstYR-Y/edit?usp=sharing">https://docs.google.com/presentation/d/1p-bVbkM_BKPtJe8U4ZI8DISVrBkWuGtvpM5smstYR-Y/edit?usp=sharing</a></li>



<li>la <strong>registrazione</strong> del talk: <a href="https://www.youtube.com/watch?v=rowFutR1980&amp;list=PL9purqp7U2jxr0mE-Q5TA-8eThiGQ7gIv&amp;index=13">https://www.youtube.com/watch?v=rowFutR1980&amp;list=PL9purqp7U2jxr0mE-Q5TA-8eThiGQ7gIv&amp;index=13</a></li>



<li>i <strong>due repository Git</strong> utilizzati per le demo:
<ul class="wp-block-list">
<li><a href="https://github.com/erighetto/DrupalCampRome2025-Canvas">https://github.com/erighetto/DrupalCampRome2025-Canvas</a></li>



<li><a href="https://github.com/drupalforge/drupal_cms_xb_demo">https://github.com/drupalforge/drupal_cms_xb_demo</a><br></li>
</ul>
</li>
</ul>



<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.consulenzaweb.net/2025/11/drupal-canvas-e-display-builder-due-strade-verso-lo-stesso-obiettivo/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2280</post-id>	</item>
		<item>
		<title>Da Elasticsearch a OpenSearch: cosa cambia e come migrare in sicurezza nel tuo sito Drupal</title>
		<link>https://www.consulenzaweb.net/2025/10/da-elasticsearch-a-opensearch-cosa-cambia-e-come-migrare-in-sicurezza-nel-tuo-sito-drupal/</link>
					<comments>https://www.consulenzaweb.net/2025/10/da-elasticsearch-a-opensearch-cosa-cambia-e-come-migrare-in-sicurezza-nel-tuo-sito-drupal/#respond</comments>
		
		<dc:creator><![CDATA[Emanuel Righetto]]></dc:creator>
		<pubDate>Sun, 26 Oct 2025 06:19:31 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Sicurezza]]></category>
		<category><![CDATA[Drupal]]></category>
		<category><![CDATA[Elasticsearch]]></category>
		<category><![CDATA[Full-Text]]></category>
		<category><![CDATA[OpenSearch]]></category>
		<guid isPermaLink="false">https://www.consulenzaweb.net/?p=2272</guid>

					<description><![CDATA[La ricerca full-text in Drupal ha adottato OpenSearch come alternativa a Elasticsearch, seguendo un approccio open-source con licenza Apache 2.0. OpenSearch offre compatibilità con Search API, sicurezza integrata e un ecosistema in crescita. La migrazione è semplificata, garantendo continuità nelle prestazioni e nelle funzionalità di ricerca avanzate.]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><a href="https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2025/10/Elasticsearch-OpenSearch.jpg?ssl=1"><img data-recalc-dims="1" width="750" height="375" decoding="async" loading="lazy" src="https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2025/10/Elasticsearch-OpenSearch.jpg?resize=750%2C375&#038;ssl=1" alt="" class="wp-image-2274" srcset="https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2025/10/Elasticsearch-OpenSearch.jpg?resize=1024%2C512&amp;ssl=1 1024w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2025/10/Elasticsearch-OpenSearch.jpg?resize=300%2C150&amp;ssl=1 300w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2025/10/Elasticsearch-OpenSearch.jpg?resize=768%2C384&amp;ssl=1 768w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2025/10/Elasticsearch-OpenSearch.jpg?resize=1536%2C768&amp;ssl=1 1536w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2025/10/Elasticsearch-OpenSearch.jpg?resize=2048%2C1024&amp;ssl=1 2048w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2025/10/Elasticsearch-OpenSearch.jpg?w=2250&amp;ssl=1 2250w" sizes="auto, (max-width: 750px) 100vw, 750px" /></a></figure>



<p>Negli ultimi anni la <strong>ricerca full-text</strong> è diventata uno dei pilastri dell’esperienza utente in Drupal.<br>Moduli come <strong>Search API</strong>, <strong>Facets</strong>, <strong>Better Exposed Filters</strong> e <strong>Views Autocomplete Filters</strong> permettono di realizzare ricerche dinamiche, con filtri e suggerimenti, anche su database di grandi dimensioni.</p>



<p>Per anni, la tecnologia più usata come motore di ricerca esterno è stata <strong>Elasticsearch</strong>, grazie alle sue performance e alla piena integrazione con Search API.<br>Ma dopo il cambio di licenza da parte di Elastic Inc., la community open source ha trovato in <strong>OpenSearch</strong> l’alternativa più naturale.</p>



<figure class="wp-block-table"><table class="has-fixed-layout"><thead><tr><th>Area</th><th>Elasticsearch</th><th>OpenSearch</th></tr></thead><tbody><tr><td><strong>Licenza</strong></td><td>Elastic License (non open-source)</td><td>Apache 2.0 (open-source)</td></tr><tr><td><strong>Compatibilità</strong></td><td>fino alla 7.10 interoperabile</td><td>fork della 7.10, API equivalenti</td></tr><tr><td><strong>Sicurezza</strong></td><td>X-Pack (commerciale)</td><td>Security plugin open-source</td></tr><tr><td><strong>Gestione indici</strong></td><td>ILM (Index Lifecycle Management)</td><td>ISM (Index State Management)</td></tr><tr><td><strong>Feature aggiuntive</strong></td><td>Machine Learning, Watcher, Canvas</td><td>Alerting, Anomaly Detection, SQL, kNN</td></tr><tr><td><strong>Ecosistema</strong></td><td>Elastic Stack (ELK)</td><td>OpenSearch Dashboards</td></tr><tr><td><strong>Community</strong></td><td>gestita da Elastic</td><td>community-driven, con forte supporto AWS</td></tr></tbody></table></figure>



<p>In pratica, <strong>OpenSearch nasce da Elasticsearch 7.10</strong>, ne mantiene la compatibilità e ne amplia le funzionalità, ma con un approccio open e trasparente.<br>Per Drupal, questo significa continuità nelle API e piena interoperabilità con la logica di Search API.</p>



<h2 class="wp-block-heading">Perché passare a OpenSearch</h2>



<h3 class="wp-block-heading">1. Licenza open-source</h3>



<p>OpenSearch è distribuito sotto licenza <strong>Apache 2.0</strong>, che consente l’uso e la modifica libera anche in contesti commerciali.<br>Non servono abbonamenti o licenze enterprise per attivare funzioni di sicurezza o gestione avanzata del cluster.</p>



<h3 class="wp-block-heading">2. Compatibilità nativa con Drupal</h3>



<p>Il modulo <a href="https://www.drupal.org/project/search_api_opensearch" target="_blank"><strong>search_api_opensearch</strong></a> fornisce un backend dedicato a OpenSearch, completamente compatibile con <strong>Search API</strong>, <strong>Facets</strong>, <strong>Better Exposed Filters</strong> e <strong>Views Autocomplete Filters</strong>.<br>Non è un fork improvvisato, ma un progetto stabile mantenuto in parallelo alla piattaforma OpenSearch.</p>



<h3 class="wp-block-heading">3. Sicurezza integrata</h3>



<p>OpenSearch include nativamente TLS, autenticazione HTTP Basic, API Key, ruoli e permessi granulari (RBAC), oltre ad audit logging e supporto per CA interne.</p>



<h3 class="wp-block-heading">4. Continuità tecnologica</h3>



<p>La sintassi delle query, il DSL, i mapping e gli analyzer sono equivalenti a quelli di Elasticsearch 7.x.<br>Le applicazioni Drupal che già funzionano con Elasticsearch possono passare a OpenSearch <strong>senza modificare il codice</strong>.</p>



<h3 class="wp-block-heading">5. Ecosistema in crescita</h3>



<p>La community OpenSearch evolve rapidamente: alerting, SQL, kNN, anomaly detection e osservabilità sono oggi parte integrante del core.</p>



<h2 class="wp-block-heading">Come passare a OpenSearch in Drupal</h2>



<p>Il passaggio è più semplice di quanto sembri.<br>Ecco una procedura standard, indipendente dal contesto specifico.</p>



<h3 class="wp-block-heading">1. Verifica la compatibilità del tuo stack</h3>



<p>I moduli dell&#8217;ecosistem Search API sono tantissimi ma quelli che sono in relazione con la ricerca full-text sono in genere questi:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: yaml; title: ; notranslate">
dependencies:
  - search_api:search_api
  - facets:facets
  - better_exposed_filters:better_exposed_filters
  - views_autocomplete_filters:views_autocomplete_filters
  - snowball_stemmer:snowball_stemmer
</pre></div>


<p>Tutti questi moduli <strong>restano compatibili</strong>: operano sopra <strong>Search API</strong>, quindi il cambio di backend non li coinvolge.</p>



<h3 class="wp-block-heading">2. Sostituisci il backend Elasticsearch con OpenSearch</h3>



<p>Installa il nuovo modulo:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
composer require drupal/search_api_opensearch:^2
composer remove drupal/elasticsearch_connector
</pre></div>


<p>Poi, in <strong>Configurazione → Search API → Server</strong>, crea un nuovo server con backend <strong>OpenSearch</strong>.</p>



<ul class="wp-block-list">
<li><strong>URL:</strong> <code>https://opensearch.tuodominio.it:9200</code></li>



<li><strong>Autenticazione:</strong> Basic auth o API key</li>



<li><strong>Verifica TLS:</strong> se usi una CA interna, installala sul server Drupal o usa un reverse proxy con certificato trusted.</li>
</ul>



<h3 class="wp-block-heading">3. Definisci un pattern dedicato per gli indici Drupal</h3>



<p>Per evitare conflitti con altri template o indici di sistema, usa un pattern dedicato (<code>drupal-*</code>).</p>



<p>Puoi creare su OpenSearch un <strong>Index Template</strong> con analyzer e filtro linguistico personalizzati, ad esempio per l’italiano:</p>


<div class="wp-block-syntaxhighlighter-code "><pre class="brush: bash; title: ; notranslate">
curl -u admin:password \
  -H &#039;Content-Type: application/json&#039; \
  -X PUT &#039;https://opensearch.tuodominio.it:9200/_index_template/drupal-template&#039; -d @- &lt;&lt;&#039;JSON&#039;
{
  &quot;index_patterns&quot;: &#x5B;&quot;drupal-*&quot;],
  &quot;template&quot;: {
    &quot;settings&quot;: {
      &quot;index&quot;: {
        &quot;number_of_shards&quot;: 1,
        &quot;analysis&quot;: {
          &quot;analyzer&quot;: {
            &quot;it_text&quot;: {
              &quot;type&quot;: &quot;custom&quot;,
              &quot;tokenizer&quot;: &quot;standard&quot;,
              &quot;filter&quot;: &#x5B;&quot;lowercase&quot;, &quot;asciifolding&quot;, &quot;italian_stop&quot;, &quot;italian_snowball&quot;]
            }
          },
          &quot;filter&quot;: {
            &quot;italian_stop&quot;:    { &quot;type&quot;: &quot;stop&quot;,    &quot;stopwords&quot;: &quot;_italian_&quot; },
            &quot;italian_snowball&quot;:{ &quot;type&quot;: &quot;snowball&quot;,&quot;language&quot;:  &quot;Italian&quot;  }
          }
        }
      }
    }
  },
  &quot;priority&quot;: 100
}
JSON

</pre></div>


<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Se preferisci gestire lo stemming in Drupal (tramite <code>snowball_stemmer</code>), puoi omettere la sezione <code>analysis</code>.</p>
</blockquote>



<h3 class="wp-block-heading">4. Ricostruisci gli indici</h3>



<p>Ricollega gli <strong>Index Search API</strong> al nuovo server OpenSearch e avvia la <strong>reindicizzazione</strong>.<br>Drupal ricreerà gli indici <code>drupal-*</code> da zero nel cluster OpenSearch, applicando il template appena definito.</p>



<h3 class="wp-block-heading">5. Verifica le pipeline e le policy di lifecycle</h3>



<ul class="wp-block-list">
<li>Se non usavi <strong>ingest pipeline</strong>, non devi configurare nulla.</li>



<li>Se in Elasticsearch avevi <strong>ILM</strong> (Index Lifecycle Management), in OpenSearch troverai l’equivalente <strong>ISM</strong> (Index State Management).<br>Le policy vanno ricreate, ma la logica di rollover e retention resta la stessa.</li>
</ul>



<h2 class="wp-block-heading">Risultato finale</h2>



<p>Dopo la migrazione:</p>



<ul class="wp-block-list">
<li>Drupal continua a usare Search API, Views e Facets esattamente come prima.</li>



<li>Tutte le query funzionano grazie alla compatibilità delle API.</li>



<li>OpenSearch fornisce HTTPS, sicurezza integrata e licenza libera.</li>



<li>L’indicizzazione è spesso più veloce grazie al miglioramento del cluster OS 2.x.</li>
</ul>



<h3 class="wp-block-heading"><img src="https://s.w.org/images/core/emoji/16.0.1/72x72/1f4a1.png" alt="💡" class="wp-smiley" style="height: 1em; max-height: 1em;" /> Bonus tip: OpenSearch in locale con DDEV</h3>



<p>Se utilizzi <strong>DDEV</strong> per lo sviluppo in locale, aggiorna anche il servizio di ricerca passando dall’addon Elasticsearch a quello OpenSearch.</p>



<ul class="wp-block-list">
<li><strong>Rimuovi l’addon Elasticsearch</strong><pre><code>ddev delete addon ddev/ddev-elasticsearch
ddev restart</code></pre></li>



<li><strong>Installa l’addon OpenSearch</strong><pre><code>ddev get ddev/ddev-opensearch
ddev restart</code></pre></li>
</ul>



<p>URL utili</p>



<ul class="wp-block-list">
<li>Addon DDEV Elasticsearch (da rimuovere): <a href="https://addons.ddev.com/addons/ddev/ddev-elasticsearch" target="_blank" rel="noopener">ddev/ddev-elasticsearch</a></li>



<li>Addon DDEV OpenSearch (da installare): <a href="https://addons.ddev.com/addons/ddev/ddev-opensearch" target="_blank" rel="noopener">ddev/ddev-opensearch</a></li>
</ul>



<p><strong>Dove puntare Drupal:</strong> all’interno del container PHP l’endpoint tipico è <code>http://opensearch:9200</code>; dal browser, l’istanza è normalmente esposta su <code>https://opensearch.ddev.site:9200</code>.</p>



<h2 class="wp-block-heading">Conclusione</h2>



<p><strong>OpenSearch non è più soltanto il “fork” di Elasticsearch</strong>: oggi è una piattaforma completa, libera e in costante evoluzione.<br>Per i progetti Drupal rappresenta una scelta sostenibile, a prova di futuro, per mantenere prestazioni e funzionalità di ricerca avanzate senza vincoli di licenza o costi enterprise.</p>



<p>Se stai pianificando la migrazione del tuo motore di ricerca in Drupal — o vuoi valutare una configurazione ibrida con OpenSearch — contattami.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.consulenzaweb.net/2025/10/da-elasticsearch-a-opensearch-cosa-cambia-e-come-migrare-in-sicurezza-nel-tuo-sito-drupal/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2272</post-id>	</item>
		<item>
		<title>Self-improvement ai tempi del Covid 19</title>
		<link>https://www.consulenzaweb.net/2020/07/self-improvement-ai-tempi-del-covid-19/</link>
					<comments>https://www.consulenzaweb.net/2020/07/self-improvement-ai-tempi-del-covid-19/#respond</comments>
		
		<dc:creator><![CDATA[Emanuel Righetto]]></dc:creator>
		<pubDate>Tue, 07 Jul 2020 20:46:52 +0000</pubDate>
				<category><![CDATA[.NET]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Leaflet]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[RabbitMQ]]></category>
		<category><![CDATA[RequireJS]]></category>
		<category><![CDATA[Selenium]]></category>
		<guid isPermaLink="false">https://www.consulenzaweb.net/?p=2185</guid>

					<description><![CDATA[Ho raccolto in un post pubblicato su Linkedin alcuni insegnamenti che questo 2020 mi ha regalato. https://www.linkedin.com/pulse/le-dieci-cose-che-ho-imparato-questa-prima-parte-di-2020-righetto Parliamo di: Magento 2 RabbitMQ Selenium WebDriver Siti html statici RequireJS Leaflet Analisi dei log Buona lettura.]]></description>
										<content:encoded><![CDATA[
<figure class="wp-block-image size-large"><img data-recalc-dims="1" decoding="async" loading="lazy" src="https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2020/07/pexels-photo-577585.jpeg?w=750&#038;ssl=1" alt=""/></figure>


<p>Ho raccolto in un post pubblicato su Linkedin alcuni insegnamenti che questo 2020 mi ha regalato.</p>
<p><a href="https://www.linkedin.com/pulse/le-dieci-cose-che-ho-imparato-questa-prima-parte-di-2020-righetto">https://www.linkedin.com/pulse/le-dieci-cose-che-ho-imparato-questa-prima-parte-di-2020-righetto</a></p>
<p>Parliamo di:</p>
<ul>
<li>Magento 2</li>
<li>RabbitMQ</li>
<li>Selenium WebDriver</li>
<li>Siti html statici</li>
<li>RequireJS</li>
<li>Leaflet</li>
<li>Analisi dei log</li>
</ul>
<p>Buona lettura.</p>


<p></p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.consulenzaweb.net/2020/07/self-improvement-ai-tempi-del-covid-19/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2185</post-id>	</item>
		<item>
		<title>Twitter Bootstrap  4 + Automattic _s = UnderStrap</title>
		<link>https://www.consulenzaweb.net/2019/02/twitter-bootstrap-4-plus-automattic-s-understrap/</link>
					<comments>https://www.consulenzaweb.net/2019/02/twitter-bootstrap-4-plus-automattic-s-understrap/#respond</comments>
		
		<dc:creator><![CDATA[Emanuel Righetto]]></dc:creator>
		<pubDate>Sat, 16 Feb 2019 09:33:58 +0000</pubDate>
				<category><![CDATA[Design]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[Bootstrap]]></category>
		<category><![CDATA[Responsive Web Design]]></category>
		<category><![CDATA[WordPress]]></category>
		<guid isPermaLink="false">http://www.consulenzaweb.net/?p=2060</guid>

					<description><![CDATA[UnderStrap combines the Underscores starter theme (by Automattic) and the mobile-first, responsive grid framework Bootstrap 4 (by Twitter) into a perfect open source foundation for your next WordPress theme project. In passato avevo già affrontato l&#8217;argomento: Temi per WordPress ma le tecnologie si evolvono e si aggiornano. UnderStrap mette a disposizione dello sviluppatore WordPress l&#8217;ultima release del framework Bootstrap per ... <a class="read-more" href="https://www.consulenzaweb.net/2019/02/twitter-bootstrap-4-plus-automattic-s-understrap/">Read More</a>]]></description>
										<content:encoded><![CDATA[<p><img data-recalc-dims="1" decoding="async" loading="lazy" class="alignnone size-large wp-image-2174" src="https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2019/02/best-wordpress-template-understrap-copv4-o.jpg?resize=750%2C563&#038;ssl=1" alt="" width="750" height="563" srcset="https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2019/02/best-wordpress-template-understrap-copv4-o.jpg?resize=1024%2C768&amp;ssl=1 1024w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2019/02/best-wordpress-template-understrap-copv4-o.jpg?resize=300%2C225&amp;ssl=1 300w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2019/02/best-wordpress-template-understrap-copv4-o.jpg?resize=768%2C576&amp;ssl=1 768w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2019/02/best-wordpress-template-understrap-copv4-o.jpg?w=1200&amp;ssl=1 1200w" sizes="auto, (max-width: 750px) 100vw, 750px" /></p>
<blockquote><p><a href="https://understrap.com" target="_blank" rel="noopener">UnderStrap</a> combines the Underscores starter theme (by Automattic) and the mobile-first, responsive grid framework Bootstrap 4 (by Twitter) into a perfect open source foundation for your next WordPress theme project.</p></blockquote>
<p>In passato avevo già affrontato l&#8217;argomento:</p>
<blockquote class="wp-embedded-content" data-secret="mCrLTTMj99"><p><a href="https://www.consulenzaweb.net/2011/12/temi-per-wordpress/">Temi per WordPress</a></p></blockquote>
<p><iframe class="wp-embedded-content" sandbox="allow-scripts" security="restricted"  src="https://www.consulenzaweb.net/2011/12/temi-per-wordpress/embed/#?secret=mCrLTTMj99" data-secret="mCrLTTMj99" width="600" height="338" title="&#8220;Temi per WordPress&#8221; &#8212; Consulenza Web" frameborder="0" marginwidth="0" marginheight="0" scrolling="no"></iframe><br />
ma le tecnologie si evolvono e si aggiornano.<br />
<a href="https://understrap.com" target="_blank" rel="noopener">UnderStrap</a> mette a disposizione dello sviluppatore WordPress l&#8217;ultima release del framework Bootstrap per la realizzazione di theme custom.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.consulenzaweb.net/2019/02/twitter-bootstrap-4-plus-automattic-s-understrap/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2060</post-id>	</item>
		<item>
		<title>Scrivere i log prodotti da Drupal 8 nello stream di Amazon CloudWatch</title>
		<link>https://www.consulenzaweb.net/2018/06/scrivere-i-log-prodotti-da-drupal-8-nello-stream-di-amazon-cloudwatch/</link>
					<comments>https://www.consulenzaweb.net/2018/06/scrivere-i-log-prodotti-da-drupal-8-nello-stream-di-amazon-cloudwatch/#respond</comments>
		
		<dc:creator><![CDATA[Emanuel Righetto]]></dc:creator>
		<pubDate>Wed, 27 Jun 2018 21:04:16 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[aws]]></category>
		<category><![CDATA[cloudwatch]]></category>
		<category><![CDATA[Drupal]]></category>
		<category><![CDATA[monolog]]></category>
		<guid isPermaLink="false">https://www.consulenzaweb.net/?p=2151</guid>

					<description><![CDATA[L&#8217;attività di logging se ben concepita può essere una miniera di informazioni per il debug di errori e per tenere traccia di quello che succede nell&#8217;applicazione, per capire cosa è andato storto o anche solo per monitorare l&#8217;attività degli utenti che ha indotto all&#8217;errore. Se avete dimestichezza con Symfony avrete sicuramente imparato ad amare la versatilità di Monolog, scritto dallo ... <a class="read-more" href="https://www.consulenzaweb.net/2018/06/scrivere-i-log-prodotti-da-drupal-8-nello-stream-di-amazon-cloudwatch/">Read More</a>]]></description>
										<content:encoded><![CDATA[<p><img data-recalc-dims="1" decoding="async" loading="lazy" src="https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2018/06/cUb50JD.png?resize=750%2C359&#038;ssl=1" alt="" width="750" height="359" class="alignnone size-large wp-image-2152" srcset="https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2018/06/cUb50JD.png?resize=1024%2C490&amp;ssl=1 1024w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2018/06/cUb50JD.png?resize=300%2C144&amp;ssl=1 300w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2018/06/cUb50JD.png?resize=768%2C368&amp;ssl=1 768w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2018/06/cUb50JD.png?w=1500&amp;ssl=1 1500w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2018/06/cUb50JD.png?w=2250&amp;ssl=1 2250w" sizes="auto, (max-width: 750px) 100vw, 750px" /><br />
L&#8217;attività di logging se ben concepita può essere una miniera di informazioni per il debug di errori e per tenere traccia di quello che succede nell&#8217;applicazione, per capire cosa è andato storto o anche solo per monitorare l&#8217;attività degli utenti che ha indotto all&#8217;errore.</p>
<p>Se avete dimestichezza con Symfony avrete sicuramente imparato ad amare la versatilità di <a href="https://github.com/Seldaek/monolog" target="_blank" rel="noopener">Monolog</a>, scritto dallo stesso sviluppatore che ha inventato <a href="https://getcomposer.org" target="_blank" rel="noopener">Composer</a>.<br />
Monolog supporta canali (Channels) di log differenti, ciascuno dei quali associati a degli Handler che sono in grado di scrivere un messaggio di log sulle destinazioni più disparate, da un semplice database passando per Syslog fino a soluzioni più evolute come postare un messaggio su <a href="https://slack.com" target="_blank" rel="noopener">Slack</a> o <a href="https://www.elastic.co/products/logstash" target="_blank" rel="noopener">Logstash</a>.</p>
<p>Utilizzando un handler di Monolog possiamo interfacciarci con <a href="https://aws.amazon.com/it/cloudwatch/" target="_blank" rel="noopener">Amazon CloudWatch</a> che è un servizio di monitoraggio per le risorse cloud AWS e le applicazioni in esecuzione su AWS. Si può utilizzare Amazon CloudWatch per raccogliere e monitorare parametri e file di log, impostare allarmi e reagire automaticamente ai cambiamenti nelle risorse AWS.</p>
<p>Quindi andiamo per ordine:</p>
<ul>
<li>per poter scrivere i nostri log dentro la piattaforma CloudWatch abbiamo bisogno di installare <a href="https://www.drupal.org/project/monolog" target="_blank" rel="noopener">il wrapper di Monolog per Drupal 8</a><br />
<code>composer require drupal/monolog:^1.0</code></li>
<li>sucessivamente dovremo installare l&#8217;handler specifico per CloudWatch<br />
<code>composer require maxbanton/cwh:^1.0</code></li>
<li>nella stessa directory del file <strong>settings.php</strong> del sito dovremo creare uno specifico file per il servizio (monolog.services.yml per esempio) e poi aggiungere questa riga di codice nel file <strong>settings.php</strong> stesso:<br />
<code>$settings['container_yamls'][] = 'sites/default/monolog.services.yml';</code></li>
</ul>
<p>Ora abbiamo due possibili strade, la cui scelta dipende solo dalle specifiche esigenze del progetto.</p>
<h3>Tutti i channel vengono scritti in un unico stream</h3>
<p>Nel file <code>sites/default/monolog.services.yml</code> mettiamo queste impostazioni sostituendo i parametri che iniziano con <code>my_</code> che sono solamente dei segnaposto.</p>
<pre class="brush: php; title: ; notranslate">
--- 
parameters: 
  monolog.channel_handlers: 
    default: 
      - cloudwatch_handler

  monolog.processors: 
    - message_placeholder
    - current_user
    - request_uri
    - ip
    - referer

services: 
  cloudwatch_client: 
    class: Aws\CloudWatchLogs\CloudWatchLogsClient
    arguments: 
      - 
        credentials: 
          key: my_amazon_accesskey
          secret: my_amazon_secretkey
        region: my_amazon_region
        version: latest

  cloudwatch_handler: 
    class: Maxbanton\Cwh\Handler\CloudWatch
    arguments: 
      - &quot;@cloudwatch_client&quot;
      - my_group_name
      - my_stream_name
      - 30
      - 10000
      - 
        mytag: tag
      - DEBUG

</pre>
<h3>Ogni channel di Monolog verrà scritto in uno specifico stream</h3>
<p>Se vogliamo fare in modo che ogni channel, magari per una migliore leggibilità dei log, venga scritto in un proprio stream dobbiamo prima creare un handler custom che possiamo mettere in un modulo creato appositamente oppure in un altro modulo custom. Occhio solo a mettere il <code>namespace</code> corretto.</p>
<pre class="brush: php; title: ; notranslate">
&lt;?php

namespace Drupal\my_custom_module\Logger\Handler;

use Aws\CloudWatchLogs\CloudWatchLogsClient;
use Maxbanton\Cwh\Handler\CloudWatch;
use Monolog\Handler\AbstractProcessingHandler;
use Monolog\Logger;

/**
 * Class CloudWatchHandler
 *
 * @package Drupal\my_custom_module\Logger\Handler
 */
class CloudWatchHandler extends AbstractProcessingHandler {

  /**
   * CloudWatch constructor.
   */
  public function __construct() {
    parent::__construct(Logger::DEBUG, TRUE);
  }

  /**
   * Writes the record down to the log of the implementing handler
   *
   * @param  array $record
   *
   * @return void
   */
  protected function write(array $record) {

    $sdkParams = &#x5B;
      'region' =&gt; &quot;my_amazon_region&quot;,
      'version' =&gt; &quot;latest&quot;,
      'credentials' =&gt; &#x5B;
        'key' =&gt; &quot;my_amazon_key&quot;,
        'secret' =&gt; &quot;my_amazon_secret&quot;,
      ],
    ];

    $client = new CloudWatchLogsClient($sdkParams);

    $group = &quot;my_group_name&quot;;

    if (empty($record&#x5B;'channel'])) {
      $stream = &quot;default&quot;;
    }
    else {
      $stream = $record&#x5B;'channel'];
    }

    /** @var  \Maxbanton\Cwh\Handler\CloudWatch $handler */
    $handler = new CloudWatch($client, $group, $stream, 30, 10000, &#x5B;], Logger::DEBUG);

    $handler-&gt;write($record);
  }

}
</pre>
<p>A questo punto nel nostro file <code>sites/default/monolog.services.yml</code> mettiamo le configurazioni:</p>
<pre class="brush: php; title: ; notranslate">
--- 
parameters: 
  monolog.channel_handlers: 
    default: 
      - cloudwatch_handler

  monolog.processors: 
    - message_placeholder
    - current_user
    - request_uri
    - ip
    - referer

services: 
  cloudwatch_handler: 
    class: Drupal\my_custom_module\Logger\Handler\CloudWatchHandler   
    #Modificare con il namespace corretto
</pre>
<p>Come si può notare il servizio è molto spartano, ma può essere ampliato iniettando come argomento magari <a href="https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Config%21ConfigFactoryInterface.php/8.5.x" rel="noopener" target="_blank">\Drupal\Core\Config\ConfigFactoryInterface $config_factory</a> per caricare una configurazione oppure <a href="https://api.drupal.org/api/drupal/core%21lib%21Drupal%21Core%21Entity%21EntityTypeManager.php/class/EntityTypeManager/8.5.x" rel="noopener" target="_blank">\Drupal\Core\Entity\EntityTypeManager $entity_type_manager</a> per interfacciarsi con il repository di un&#8217;entità.  </p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.consulenzaweb.net/2018/06/scrivere-i-log-prodotti-da-drupal-8-nello-stream-di-amazon-cloudwatch/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2151</post-id>	</item>
		<item>
		<title>Drupal Console + dotenv</title>
		<link>https://www.consulenzaweb.net/2017/12/drupal-console-dotenv/</link>
					<comments>https://www.consulenzaweb.net/2017/12/drupal-console-dotenv/#respond</comments>
		
		<dc:creator><![CDATA[Emanuel Righetto]]></dc:creator>
		<pubDate>Sun, 31 Dec 2017 08:25:11 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[dotenv]]></category>
		<category><![CDATA[Drupal]]></category>
		<category><![CDATA[Drupal 8]]></category>
		<category><![CDATA[Drupal Cosole]]></category>
		<category><![CDATA[Robo]]></category>
		<guid isPermaLink="false">https://www.consulenzaweb.net/?p=2141</guid>

					<description><![CDATA[Questo post nasce per dare una risposta alla domanda: quale è il modo più semplice in un progetto Drupal per gestire le variabili di ambiente? Le ultime versioni di Drupal Console includono una feature molto utile per gestire le variabili che hanno valori che possono variare tra i diversi ambienti come parametri di connessione al db o path dell&#8217;installazione. Questo ... <a class="read-more" href="https://www.consulenzaweb.net/2017/12/drupal-console-dotenv/">Read More</a>]]></description>
										<content:encoded><![CDATA[<p><img data-recalc-dims="1" decoding="async" loading="lazy" src="https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2017/12/sLxvlljXRGGlS1HghI4S_how-to-use-environment-variables.jpg?resize=750%2C375&#038;ssl=1" alt="" width="750" height="375" class="alignnone size-large wp-image-2142" srcset="https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2017/12/sLxvlljXRGGlS1HghI4S_how-to-use-environment-variables.jpg?resize=1024%2C512&amp;ssl=1 1024w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2017/12/sLxvlljXRGGlS1HghI4S_how-to-use-environment-variables.jpg?resize=300%2C150&amp;ssl=1 300w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2017/12/sLxvlljXRGGlS1HghI4S_how-to-use-environment-variables.jpg?resize=768%2C384&amp;ssl=1 768w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2017/12/sLxvlljXRGGlS1HghI4S_how-to-use-environment-variables.jpg?w=1200&amp;ssl=1 1200w" sizes="auto, (max-width: 750px) 100vw, 750px" />Questo post nasce per dare una risposta alla domanda:</p>
<blockquote><p>quale è il modo più semplice in un progetto Drupal per gestire le variabili di ambiente?</p></blockquote>
<p>Le ultime versioni di Drupal Console includono una feature molto utile per gestire le variabili che hanno valori che possono variare tra i diversi ambienti come parametri di connessione al db o path dell&#8217;installazione.</p>
<p>Questo è possibile tramite una libreria che è una dipendenza di <a href="https://github.com/hechoendrupal/drupal-console" target="_blank" rel="noopener">drupal-console</a>: <a href="https://github.com/vlucas/phpdotenv" target="_blank" rel="noopener">https://github.com/vlucas/phpdotenv</a>.<br />
In pratica ce lo troviamo già nelle nostre disponibilità senza fare nulla.<br />
Vediamo quindi come utilizzarlo, anche in un progetto già avviato.</p>
<p><code>drupal dotenv:init</code></p>
<p>Nella shell ci verrà chiesto di immettere alcuni valori, come i parametri di accesso al db: nome, utente, password.<br />
Drupal Console creerà un file <strong>.env </strong>nella root e modificherà il file <strong>web/sites/default/settings.php </strong>per fare in modo che le variabili presenti nel file <strong>.env</strong> vengano lette.<br />
Questo è un esempio di <strong>.env</strong></p>
<pre class="brush: bash; title: ; notranslate">
# ENV
ENVIRONMENT=stage

# DATABASE
DATABASE_NAME=drupal
DATABASE_USER=drupal
DATABASE_PASSWORD=aUVOicUSmS9Zn9SiW6zB
DATABASE_HOST=localhost
DATABASE_PORT=3306

# PATH
ROOT=/var/www/demowebsite.it/web

# SETTINGS
</pre>
<p>Se lavoriamo in collaborazione con altri sviluppatori possiamo creare anche un file di distribuzione .env.dist con i valori di default da includere nel repository git.</p>
<p>L&#8217;utilizzo più comodo che ci viene gratis è fare in modo che anche il nostro file <strong>.aliases </strong>legga il file <strong>.env </strong>così non dobbiamo sempre settare i path quando lanciamo un comando drush, drupalconsole oppure robo:</p>
<pre class="brush: bash; title: ; notranslate">
#!/bin/bash
export $(egrep -v '^#' .env | xargs)
alias drush=&quot;vendor/bin/drush -r $ROOT&quot;
alias drupal=&quot;vendor/bin/drupal --root=\&quot;$ROOT\&quot;&quot;
alias robo=&quot;vendor/bin/robo&quot;
</pre>
<p>Come dicevo anche il task runner <a href="http://robo.li" target="_blank" rel="noopener">Robo</a>, può leggere le variabili di ambiente dichiarate in .<strong>env</strong>.</p>
<p>Ecco un semplice esempio:</p>
<pre class="brush: php; title: ; notranslate">
/**
* RoboFile constructor.
*/
public function __construct() {
  $dotenv = new \Dotenv\Dotenv(__DIR__);
  $dotenv-&gt;load();
  $this-&gt;environment = getenv('ENVIRONMENT');
}
</pre>
]]></content:encoded>
					
					<wfw:commentRss>https://www.consulenzaweb.net/2017/12/drupal-console-dotenv/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2141</post-id>	</item>
		<item>
		<title>Magento, il terrore delle performances</title>
		<link>https://www.consulenzaweb.net/2017/06/magento-il-terrore-delle-performances/</link>
					<comments>https://www.consulenzaweb.net/2017/06/magento-il-terrore-delle-performances/#respond</comments>
		
		<dc:creator><![CDATA[Emanuel Righetto]]></dc:creator>
		<pubDate>Sat, 24 Jun 2017 15:17:31 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[MySQL]]></category>
		<category><![CDATA[Percona]]></category>
		<category><![CDATA[Performance]]></category>
		<guid isPermaLink="false">https://www.consulenzaweb.net/?p=2132</guid>

					<description><![CDATA[Magento, uno dei software per l&#8217;ecommerce più utilizzati al mondo, se non opportunamente configurato è molto ingordo di risorse e il rischio di schiantare la macchina che lo ospita è tutt&#8217;altro che remoto. Vi racconto una storia. C&#8217;era una volta un sito dove girava Magento CE (community edition). Con grande soddisfazione dei proprietari dopo un paio d&#8217;anni dalla pubblicazione del ... <a class="read-more" href="https://www.consulenzaweb.net/2017/06/magento-il-terrore-delle-performances/">Read More</a>]]></description>
										<content:encoded><![CDATA[<p><img data-recalc-dims="1" decoding="async" loading="lazy" src="https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2017/05/Magento-AGS-Technologies.png?resize=750%2C361&#038;ssl=1" alt="" width="750" height="361" class="alignnone size-large wp-image-2133" srcset="https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2017/05/Magento-AGS-Technologies.png?resize=1024%2C493&amp;ssl=1 1024w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2017/05/Magento-AGS-Technologies.png?resize=300%2C144&amp;ssl=1 300w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2017/05/Magento-AGS-Technologies.png?resize=768%2C370&amp;ssl=1 768w, https://i0.wp.com/www.consulenzaweb.net/wp-content/uploads/2017/05/Magento-AGS-Technologies.png?w=1400&amp;ssl=1 1400w" sizes="auto, (max-width: 750px) 100vw, 750px" /><strong>Magento</strong>, uno dei software per l&#8217;ecommerce più utilizzati al mondo, se non opportunamente configurato è molto ingordo di risorse e il rischio di schiantare la macchina che lo ospita è tutt&#8217;altro che remoto.<br />
Vi racconto una storia.<br />
C&#8217;era una volta un sito dove girava <strong>Magento CE (community edition)</strong>. Con grande soddisfazione dei proprietari dopo un paio d&#8217;anni dalla pubblicazione del sito gli affari andavano molto bene e girava abbastanza traffico da giustificare un hosting serio, praticamente risorse illimitate.<br />
Il database girava su una macchina dedicata, utilizzando l&#8217;ultima release di <strong>Percona Server</strong>, il fork di <strong>MySQL</strong>.<br />
Le performance inizialmente buone, a mano a mano, che il database aumentava di &#8220;volume&#8221;, diventavano sempre più problematiche: query lentissime, un sacco di deadlock, ore (ore!!!) di <code>waiting for table level lock</code>, rendendo di fatto la situazione insostenibile.<br />
Armato di santa pazienza, come si fa in questi casi, cerco su Stack Overflow e nella documentazione Percona ovviamente, una possibile soluzione.<br />
I consigli che ne ho ricavato sono abbastanza ovvi ma inefficaci: aumentare il <code>lock wait timeout</code> di InnoDb, settare la <code>transaction isolation</code> a READ-COMMITTED. Ma il database si schiantava ancora ogni tre per due.<br />
Fino a che non trovo un post che consiglia di utilizzare <a href="https://github.com/major/MySQLTuner-perl" target="_blank" rel="noopener noreferrer">https://github.com/major/MySQLTuner-perl</a>.<br />
<strong>MySQLTuner</strong> è uno script scritto in Perl che ti permette di rivedere rapidamente le configurazioni di un&#8217;installazione di MySQL e ti suggerisce le modifiche da apportare per aumentare le prestazioni e la stabilità.<br />
Facilissimo da utilizzare, anche da remoto. Non apporta modifiche direttamente al database, questo è molto importante, ma dopo aver analizzato i log e le configurazioni correnti ti fornisce una serie di suggerimenti.<br />
Nel caso citato sopra, <strong>MySQLTuner</strong> si è rivelata la provvidenziale manna: dopo aver apportato alcune delle modifiche suggerite il database è tornato a livelli di perfomance davvero ottime. Dopo questo intervento non ha più avuto problemi e down.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://www.consulenzaweb.net/2017/06/magento-il-terrore-delle-performances/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
		<post-id xmlns="com-wordpress:feed-additions:1">2132</post-id>	</item>
	</channel>
</rss>
