<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>Forem: Raziel Rodrigues</title>
    <description>The latest articles on Forem by Raziel Rodrigues (@razielrodrigues).</description>
    <link>https://forem.com/razielrodrigues</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1102303%2Ff528214e-5717-4e45-8a25-f2532d23910d.jpeg</url>
      <title>Forem: Raziel Rodrigues</title>
      <link>https://forem.com/razielrodrigues</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://forem.com/feed/razielrodrigues"/>
    <language>en</language>
    <item>
      <title>June Celebrations - São João from Porto Portugal 🎆</title>
      <dc:creator>Raziel Rodrigues</dc:creator>
      <pubDate>Wed, 25 Jun 2025 22:51:30 +0000</pubDate>
      <link>https://forem.com/razielrodrigues/june-celebrations-sao-joao-from-porto-portugal-1eo3</link>
      <guid>https://forem.com/razielrodrigues/june-celebrations-sao-joao-from-porto-portugal-1eo3</guid>
      <description>&lt;p&gt;This is a submission for &lt;a href="https://dev.to/challenges/frontend-2025-06-04"&gt;Frontend Challenge - June Celebrations, CSS Art: June Celebrations&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Inspiration
&lt;/h2&gt;

&lt;p&gt;My inspiration for this project was the vibrant and traditional São João festival in Porto, Portugal. I wanted to create a digital experience that captured the essence of this unique celebration, perfectly aligning with the hackathon’s “June Celebrations” theme.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;I developed an interactive website in React.js that simulates the atmosphere of São João do Porto. The website includes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A fun game of "greeting with leeks".&lt;/li&gt;
&lt;li&gt;The possibility of releasing hot air balloons with animations.&lt;/li&gt;
&lt;li&gt;Informational modals about the history and traditions of the festival.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Você pode conferir a demo ao vivo aqui: &lt;a href="https://june-celebration-challenge.vercel.app" rel="noopener noreferrer"&gt;https://june-celebration-challenge.vercel.app&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Journey
&lt;/h2&gt;

&lt;p&gt;The project was built using React.js with Vite for fast and efficient development. I opted for a single file structure (&lt;code&gt;App.jsx&lt;/code&gt;) to keep things simple and focus on functionality. I learned how to integrate animations with Framer Motion and create an engaging user experience, combining interactivity with educational content. The deployment was configured for Vercel, ensuring easy access and scalability.&lt;/p&gt;

</description>
      <category>frontendchallenge</category>
      <category>devchallenge</category>
      <category>css</category>
    </item>
    <item>
      <title>Publish to Dev.to Straight from Your Inbox 📖</title>
      <dc:creator>Raziel Rodrigues</dc:creator>
      <pubDate>Sun, 08 Jun 2025 22:41:38 +0000</pubDate>
      <link>https://forem.com/razielrodrigues/postmark-challenge-publish-to-devto-straight-from-your-inbox-e16</link>
      <guid>https://forem.com/razielrodrigues/postmark-challenge-publish-to-devto-straight-from-your-inbox-e16</guid>
      <description>&lt;p&gt;This is a submission for the &lt;a href="https://dev.to/challenges/postmark"&gt;Postmark Challenge: Inbox Innovators&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I created &lt;strong&gt;Dev.to Email Publisher&lt;/strong&gt;, a handy tool that lets developers post articles to the Dev.to platform straight from their email inbox! Powered by Postmark’s inbound email feature and integrated with the Dev.to API, this project showcases a practical way to streamline content creation. It’s a simple yet reusable solution that can be adapted for other platforms or used as-is for Dev.to. My goal was to make publishing as easy as sending an email, saving time for busy developers who want to share their ideas quickly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Clone the repostitory&lt;/strong&gt;: &lt;a href="https://github.com/RazielRodrigues/postmark-challenge" rel="noopener noreferrer"&gt;Repostiory&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Connect Dev.to&lt;/strong&gt;: Add your Dev.to API key (found in Dev.to settings under “Extensions”).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Send Test Email&lt;/strong&gt;: From your inbox, send to your email registered in postmark inbound:&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subject&lt;/strong&gt;: &lt;code&gt;Post: [Your Article Title]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Subject&lt;/strong&gt;: &lt;code&gt;Post: [Your Article Title (tags: webdev programming php)]&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Body&lt;/strong&gt;: Markdown content&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check Response&lt;/strong&gt;: You’ll get a confirmation email from Postmark with an success or error of the publication.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  How It Works
&lt;/h3&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Compose Email&lt;/strong&gt;: Write your article in Markdown format and send it to the app’s designated email address (provided after setup).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Postmark Processing&lt;/strong&gt;: Postmark’s inbound webhook captures the email and parses its content.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Dev.to Publishing&lt;/strong&gt;: The app formats the email content and uses the Dev.to API to publish the article.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Email Notification&lt;/strong&gt;: Receive a confirmation email via Postmark with the publication status or any errors.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Code Repository
&lt;/h2&gt;

&lt;p&gt;Explore the code: &lt;a href="https://github.com/RazielRodrigues/postmark-challenge" rel="noopener noreferrer"&gt;github.com/RazielRodrigues/postmark-challenge&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Setup Instructions
&lt;/h3&gt;

&lt;p&gt;To run locally, clone the repo and configure the &lt;code&gt;.env&lt;/code&gt; file with:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;SENDER_EMAIL&lt;/code&gt;: An email registered with your domain.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;DEV_TO_TOKEN&lt;/code&gt;: Your Dev.to API key (get it from &lt;a href="https://dev.to/settings/extensions"&gt;Dev.to Settings &amp;gt; Extensions&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;POSTMARK_TOKEN&lt;/code&gt;: Your Postmark API key (available at &lt;a href="https://account.postmarkapp.com" rel="noopener noreferrer"&gt;Postmark Account &amp;gt; Tokens&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The README includes detailed setup steps.&lt;/p&gt;

&lt;h2&gt;
  
  
  How I Built It
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Development Process
&lt;/h3&gt;

&lt;p&gt;I kicked off by exploring Postmark’s inbound webhook and Dev.to’s API documentation. My approach was straightforward:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;API Setup&lt;/strong&gt;: Generated a Dev.to API key and configured Postmark’s webhook for inbound emails.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Backend&lt;/strong&gt;: Built a Node.js server to handle email parsing, API requests, and user feedback.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Email Workflow&lt;/strong&gt;: Parsed incoming emails to extract Markdown content and metadata, then sent them to Dev.to via its API.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Notifications&lt;/strong&gt;: Used Postmark’s API to send confirmation emails to users.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment&lt;/strong&gt;: Deployed the app on Vercel for a smooth, scalable demo.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Tech Stack
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Backend&lt;/strong&gt;: Node.js&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Deployment&lt;/strong&gt;: Vercel&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;APIs&lt;/strong&gt;: Dev.to API (publishing), Postmark Inbound Webhooks (email processing), Postmark API (notifications)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Email Client&lt;/strong&gt;: Postmark for sending confirmations&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Further improvement
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Image Attachments&lt;/strong&gt;: Add images attachments into the post using email attachments&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Edit Tools&lt;/strong&gt;: Ability to use the other tools for editing posts using the email&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Experience
&lt;/h3&gt;

&lt;p&gt;Working with Postmark was nice! Their clear documentation and intuitive setup let me build the core functionality in under two hours. The inbound webhook was easy to configure, and the API for sending emails was reliable. This project convinced me to explore Postmark for future email-driven apps—it’s fast, developer-friendly, and perfect for this kind of innovation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Thanks for Participating!
&lt;/h2&gt;

&lt;p&gt;This hackathon was a blast, and I’m thrilled to share my project. Thanks to Postmark for the awesome tools and to the Dev.to community for the inspiration!&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>postmarkchallenge</category>
      <category>webdev</category>
      <category>api</category>
    </item>
    <item>
      <title>InstaAnalyzer: An AI Instagram Analyst Powered by PHP, Neuron AI and Bright Data 📸</title>
      <dc:creator>Raziel Rodrigues</dc:creator>
      <pubDate>Mon, 19 May 2025 21:32:20 +0000</pubDate>
      <link>https://forem.com/razielrodrigues/instaanalyzer-an-ai-instagram-analyst-powered-by-php-neuron-ai-and-bright-data-1041</link>
      <guid>https://forem.com/razielrodrigues/instaanalyzer-an-ai-instagram-analyst-powered-by-php-neuron-ai-and-bright-data-1041</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/brightdata-2025-05-07"&gt;Bright Data AI Web Access Hackathon&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Before start reading:
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://get.brightdata.com/mu7jxb4shara" rel="noopener noreferrer"&gt;Create your account with this link in Bright Data Platform&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  Table of Contents
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;What I Built&lt;/li&gt;
&lt;li&gt;Demo&lt;/li&gt;
&lt;li&gt;How I Used Bright Data's Infrastructure&lt;/li&gt;
&lt;li&gt;Performance Improvements&lt;/li&gt;
&lt;li&gt;Tech Stack&lt;/li&gt;
&lt;li&gt;Main Features&lt;/li&gt;
&lt;li&gt;Real world problem solves&lt;/li&gt;
&lt;li&gt;Bonus: Tutorials&lt;/li&gt;
&lt;li&gt;Conclusion&lt;/li&gt;
&lt;li&gt;References&lt;/li&gt;
&lt;li&gt;Repository&lt;/li&gt;
&lt;/ol&gt;




&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Scrape. Analyze. Optimize. Let AI decode Instagram profiles for you.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Everyone wants to know info about Instagram profiles whether it's about yourself or someone else. With &lt;a href="https://insta-analyzer.razielrodrigues.dev/" rel="noopener noreferrer"&gt;InstaAnalyzer&lt;/a&gt; you are able to get insights not only from the profile but also from the posts of the profile (posts analyses will work only if the profile is public) plus you can have insights about your profile across the web so we deliver to you research based in the search results from Google, which will help you to see your digital footprint.&lt;/p&gt;

&lt;p&gt;It can give you a fast overview from the eye of a specialized AI Agent which was built for it using &lt;strong&gt;&lt;em&gt;REAL TIME DATA&lt;/em&gt;&lt;/strong&gt;. This means if the person totally rebuilds the profile you will be able to see it even if the changes were made one minute ago.&lt;/p&gt;

&lt;p&gt;Of course you can also use other AIs for this such as ChatGPT or Perplexity, but the problem is that such data are not "well distilled" plus those LLMs do not have full access to data or scrape those data like &lt;a href="https://get.brightdata.com/mu7jxb4shara" rel="noopener noreferrer"&gt;Bright Data&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I have dedicated a topic in this article showing some Real World Use Cases for this application. You can check it afterwards, but in a nutshell:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This AI tool helps you understand profiles of people you're curious about, even if you're not on their friends list. It brings you insights in an easy and friendly way and sometimes can be just for fun to share with your friends or to use as a tool for your company to understand your customers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;To make this happen, I used some cool technologies, which I'll explain in this article. Most of the tools are free, and &lt;a href="https://get.brightdata.com/mu7jxb4shara" rel="noopener noreferrer"&gt;Bright Data&lt;/a&gt; even gives &lt;strong&gt;free credits&lt;/strong&gt; to every user to test their product. That means you can try the code below on your own machine after signing up.&lt;/p&gt;




&lt;h2&gt;
  
  
  Demo
&lt;/h2&gt;

&lt;p&gt;You can test this project live! Just type an Instagram username, and you'll get all the info formatted in a nice front-end. Plus, you can share it on your own Instagram like the Spotify Wrapper feature! This would help me grow the project and get more eyes on this article and also show the power of Bright Data Tools. I'd be super thankful!&lt;/p&gt;

&lt;h3&gt;
  
  
  &amp;gt; &lt;a href="http://insta-analyzer.razielrodrigues.dev/" rel="noopener noreferrer"&gt;InstaAnalyzer Live Demo&lt;/a&gt;
&lt;/h3&gt;




&lt;h5&gt;
  
  
  Profile example
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F17ry6bj6gcwas76vpiah.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F17ry6bj6gcwas76vpiah.png" alt=" " width="560" height="1202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Posts example
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqk1y3orbri25z33sakh1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fqk1y3orbri25z33sakh1.png" alt=" " width="560" height="1454"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h5&gt;
  
  
  Web example
&lt;/h5&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6pzejqm0jm8e2ziiwz53.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6pzejqm0jm8e2ziiwz53.png" alt=" " width="366" height="1812"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  API Demo
&lt;/h2&gt;

&lt;p&gt;Here you can access the repository of the API from this code&lt;/p&gt;

&lt;h3&gt;
  
  
  &amp;gt; &lt;a href="https://github.com/RazielRodrigues/ai-brightdata-challenge-api" rel="noopener noreferrer"&gt;Repository&lt;/a&gt;
&lt;/h3&gt;




&lt;h4&gt;
  
  
  Node JS MCP Server
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsj1dfhjtim25xke4yer4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fsj1dfhjtim25xke4yer4.png" alt=" " width="800" height="358"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4eijs6kjg1uv98crq9rc.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F4eijs6kjg1uv98crq9rc.png" alt=" " width="800" height="422"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h4&gt;
  
  
  PHP MCP API
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl9bne9jk1t440in72qmp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fl9bne9jk1t440in72qmp.png" alt=" " width="800" height="457"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi1lc6zfvczebfadeil8g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fi1lc6zfvczebfadeil8g.png" alt=" " width="800" height="392"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  How I Used Bright Data's Infrastructure
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzg9l61sf5vra9tltzxmm.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzg9l61sf5vra9tltzxmm.png" alt=" " width="800" height="418"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h3&gt;
  
  
  MCP Servers usage
&lt;/h3&gt;

&lt;p&gt;For this project, I have done a few things:&lt;/p&gt;

&lt;p&gt;First I connected to the MCP Server from &lt;a href="https://get.brightdata.com/mu7jxb4shara" rel="noopener noreferrer"&gt;Bright Data&lt;/a&gt; using the Smithery SDK to get &lt;strong&gt;&lt;em&gt;REAL TIME DATA&lt;/em&gt;&lt;/strong&gt; from Instagram profiles.&lt;/p&gt;

&lt;p&gt;Since some people are posting new things everyday or changing their Instagram, it is important to have new data every time we check the profile, and using Bright Data tools is perfect for that! Then I have used some tools from their MCP Server:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;web_data_instagram_profiles&lt;/code&gt; (Quickly read structured Instagram profile data)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;web_data_instagram_posts&lt;/code&gt; (Quickly read structured Instagram post data)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;search_engine&lt;/code&gt; (Quickly read real time data from search engines)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So after I have sent this data to the LLM model using &lt;a href="https://docs.neuron-ai.dev/" rel="noopener noreferrer"&gt;Neuron AI&lt;/a&gt;, a PHP framework to work with AI Agents, when I got all the data from the Instagram I started to process it, doing a deep analysis of the profile and the posts as well.&lt;/p&gt;

&lt;p&gt;With that I was able to give information to the user about the profile that they are searching for. You can see more details on how the technical side works by looking at the System Design.&lt;/p&gt;




&lt;h2&gt;
  
  
  Performance Improvements
&lt;/h2&gt;

&lt;p&gt;Here's what I'd like to do next:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Build a custom scraper with Bright Data for specific Instagram data&lt;/li&gt;
&lt;li&gt;Improve the posts analysis since I am just checking the last five ones. Due to profiles which have a lot of posts, it needs a proper backend solution to not crash the LLM analysis&lt;/li&gt;
&lt;li&gt;Add RAG search using Bright Data's Instagram dataset&lt;/li&gt;
&lt;li&gt;Nowadays the AI response is on average 30s ~ 45s for non-cached responses and 15s ~ 25s for cached responses (when using REST API). This is one of the most critical points I am thinking to improve. Maybe I will add stream support in the future or other approaches like showing data in parts or other kinds of caching approaches, this is probably from the AI side which needs some seconds to give the proper analyze&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Tech Stack
&lt;/h2&gt;

&lt;p&gt;Here's what I used to build both projects:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Brightdata MCP Server&lt;/li&gt;
&lt;li&gt;PHP and NodeJS for backend&lt;/li&gt;
&lt;li&gt;ReactJS for frontend&lt;/li&gt;
&lt;li&gt;NeuronAI for AI Agent&lt;/li&gt;
&lt;li&gt;Mistral for LLM Model&lt;/li&gt;
&lt;li&gt;Vercel for frontend deploy&lt;/li&gt;
&lt;li&gt;Render for MCP Server deploy&lt;/li&gt;
&lt;li&gt;Hostinger for PHP Server deploy&lt;/li&gt;
&lt;li&gt;MySQL for database&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Main Features
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Profile analyzes and Posts analyzes with AI based in social frameworks and the behavior of the content provided by the instagram profile&lt;/li&gt;
&lt;li&gt;Web Search analyzes comparing the results of your profile with other people which has similar username or content&lt;/li&gt;
&lt;li&gt;PDF Report with everything so you can share or save the information you got&lt;/li&gt;
&lt;li&gt;Individual information export by images which can be easily shared or posted in your social networks&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Real world problem solves
&lt;/h2&gt;

&lt;p&gt;Here's what this project can help solve real world problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Customer Insights for Businesses: 

&lt;ul&gt;
&lt;li&gt;Provides companies with detailed analytics about their Instagram customer profiles to inform marketing strategies.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Authentic Connections: 

&lt;ul&gt;
&lt;li&gt;Facilitates meaningful connections by matching people based on their preferences and interests.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Profile Optimization: 

&lt;ul&gt;
&lt;li&gt;Offers personalized recommendations to enhance user profiles for increased engagement.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;External Perspective: 

&lt;ul&gt;
&lt;li&gt;Helps users understand how others perceive their Instagram profiles.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Content Alignment: 

&lt;ul&gt;
&lt;li&gt;Enables users to assess whether their posts align with their intended personal or brand image.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Accessible Insights: 

&lt;ul&gt;
&lt;li&gt;Delivers valuable profile analytics to all users, even those without an Instagram business account.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;li&gt;Make fun with your friends: 

&lt;ul&gt;
&lt;li&gt;Sharing your profile description on Instagram or other social media platforms just for fun.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;




&lt;h2&gt;
  
  
  Bonus: Tutorials
&lt;/h2&gt;

&lt;p&gt;I have written two tutorials for you to be able to quickly test Bright Data Services.&lt;/p&gt;

&lt;h3&gt;
  
  
  Using Bright Data Smithery MCP Server on the website
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;I will cover in four steps how to test their MCP server on the Smithery platform and you will see how easy it is to work with their MCP Server&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;1 - Access Bright Data Smithery MCP Server and make your account on Smithery&lt;br&gt;
    - &lt;a href="https://smithery.ai/server/@luminati-io/brightdata-mcp/api" rel="noopener noreferrer"&gt;https://smithery.ai/server/@luminati-io/brightdata-mcp/api&lt;/a&gt;&lt;br&gt;
    - Create your user and profile&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9qh8stn6ryldgfp7bra0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9qh8stn6ryldgfp7bra0.png" alt=" " width="800" height="527"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;2 - Grab your token from Bright Data after making your registration&lt;br&gt;
    - &lt;a href="https://brightdata.com/cp/setting/users" rel="noopener noreferrer"&gt;https://brightdata.com/cp/setting/users&lt;/a&gt;&lt;br&gt;
    - Create a new user or use your existing one&lt;br&gt;
    - Set your API key configuration&lt;br&gt;
    - Grab it&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fan75oj9om75qrkoq8clk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fan75oj9om75qrkoq8clk.png" alt=" " width="800" height="403"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;3 - Connect to the MCP Server&lt;br&gt;
    - Click on tools&lt;br&gt;
    - Select one of them&lt;br&gt;
    - On the right side put your API Key From Bright Data&lt;br&gt;
    - Select your "profile" from Smithery&lt;br&gt;
    - Click on connect&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzh3abf8wtjbg27jzdj3y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fzh3abf8wtjbg27jzdj3y.png" alt=" " width="800" height="449"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;4 - Use the MCP Server&lt;br&gt;
    - Put the required parameters&lt;br&gt;
    - Run the tool&lt;br&gt;
    - Get your Results&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fver8p730wifbt49lu5sy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fver8p730wifbt49lu5sy.png" alt=" " width="800" height="475"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In those simple four steps you are already testing and using their powerful MCP Server on the Smithery platform. You can see more ways to connect or just access &lt;a href="https://github.com/brightdata-com/brightdata-mcp" rel="noopener noreferrer"&gt;Bright Data Github&lt;/a&gt; where you can see a lot of examples on how to use the MCP Server using code.&lt;/p&gt;
&lt;h3&gt;
  
  
  Using Bright Data Smithery MCP Server SDK
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;If you want to use the SDK you can try it out in this way, it's straightforward and will work like a charm with node js&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;1 - run &lt;code&gt;npm install @modelcontextprotocol/sdk @smithery/sdk&lt;/code&gt;&lt;br&gt;
2 - Create a file called index.js and paste the code below&lt;br&gt;
3 - then &lt;code&gt;node ./index.js&lt;/code&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;StreamableHTTPClientTransport&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@modelcontextprotocol/sdk/client/streamableHttp.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;createSmitheryUrl&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@smithery/sdk&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;apiToken&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Mandatory, just use the previous API TOKEN generated for you&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;browserAuth&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Optional&lt;/span&gt;
    &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;webUnlockerZone&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;// Optional&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;serverUrl&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;createSmitheryUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;https://server.smithery.ai/@luminati-io/brightdata-mcp&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;config&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;apiKey&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;your-smithery-api-key&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;transport&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StreamableHTTPClientTransport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;serverUrl&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// Create MCP client&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;Client&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;from&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;@modelcontextprotocol/sdk/client/index.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;

&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Test client&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;1.0.0&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;
&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;connect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;transport&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// List available tools&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;tools&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;listTools&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`Available tools: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;map&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;t&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;t&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;// How to use the tool from the SDK&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;callTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;search_engine&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;arguments&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Bright Data documentation&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;engine&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;google&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With those steps you will be able to access Bright Data MCP Servers and work with them using NodeJS. They also provide one with Python, you can take a look &lt;a href="https://smithery.ai/server/@luminati-io/brightdata-mcp/api" rel="noopener noreferrer"&gt;over here&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Bright Data is an amazing platform! It lets you use your AI skills to create real-life projects that solve business problems. Their tech infrastructure is awesome, and everything just works.&lt;/p&gt;

&lt;p&gt;I loved working with their tools and can't wait to keep using them. Their interface and setup are so easy and straightforward it'll definitely take your project to the next level!&lt;/p&gt;

&lt;p&gt;You can use it as REST API or MCP Server. Since MCP server is a new technology, it's very cool seeing new stuff coming up and the power that this gives to us. I hope you enjoyed the article and it can be helpful for you to create your next amazing project using Bright Data.&lt;/p&gt;

&lt;p&gt;Please comment below your thoughts about it and what you are thinking to build using all those Technologies :)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9bkzxc7llkah6v7k1o8d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9bkzxc7llkah6v7k1o8d.png" alt="Bright Data Conclusion" width="480" height="270"&gt;&lt;/a&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/luminati-io/brightdata-mcp" rel="noopener noreferrer"&gt;Bright Data MCP GitHub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.brightdata.com" rel="noopener noreferrer"&gt;Bright Data Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://smithery.ai/server/@luminati-io/brightdata-mcp/tools" rel="noopener noreferrer"&gt;Smithery MCP Server&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Repository
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/RazielRodrigues/ai-brightdata-challenge-api" rel="noopener noreferrer"&gt;Bright Data MCP Server API&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>devchallenge</category>
      <category>brightdatachallenge</category>
      <category>ai</category>
      <category>webdata</category>
    </item>
    <item>
      <title>A new AI open source framework for PHP!</title>
      <dc:creator>Raziel Rodrigues</dc:creator>
      <pubDate>Thu, 15 May 2025 11:21:12 +0000</pubDate>
      <link>https://forem.com/razielrodrigues/-103g</link>
      <guid>https://forem.com/razielrodrigues/-103g</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/razielrodrigues/neuron-ai-o-framework-php-de-inteligencia-artificial-37nm" class="crayons-story__hidden-navigation-link"&gt;Neuron AI: O Framework PHP de Inteligência Artificial 🐘&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/razielrodrigues" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1102303%2Ff528214e-5717-4e45-8a25-f2532d23910d.jpeg" alt="razielrodrigues profile" class="crayons-avatar__image"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/razielrodrigues" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Raziel Rodrigues
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Raziel Rodrigues
                
              
              &lt;div id="story-author-preview-content-2481901" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/razielrodrigues" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F1102303%2Ff528214e-5717-4e45-8a25-f2532d23910d.jpeg" class="crayons-avatar__image" alt=""&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Raziel Rodrigues&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/razielrodrigues/neuron-ai-o-framework-php-de-inteligencia-artificial-37nm" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;May 13 '25&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/razielrodrigues/neuron-ai-o-framework-php-de-inteligencia-artificial-37nm" id="article-link-2481901"&gt;
          Neuron AI: O Framework PHP de Inteligência Artificial 🐘
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/php"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;php&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/braziliandevs"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;braziliandevs&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/ai"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;ai&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/opensource"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;opensource&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
          &lt;a href="https://dev.to/razielrodrigues/neuron-ai-o-framework-php-de-inteligencia-artificial-37nm" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left"&gt;
            &lt;div class="multiple_reactions_aggregate"&gt;
              &lt;span class="multiple_reactions_icons_container"&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/exploding-head-daceb38d627e6ae9b730f36a1e390fca556a4289d5a41abb2c35068ad3e2c4b5.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/multi-unicorn-b44d6f8c23cdd00964192bedc38af3e82463978aa611b4365bd33a0f1f4f3e97.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
                  &lt;span class="crayons_icon_container"&gt;
                    &lt;img src="https://assets.dev.to/assets/sparkle-heart-5f9bee3767e18deb1bb725290cb151c25234768a0e9a2bd39370c382d02920cf.svg" width="18" height="18"&gt;
                  &lt;/span&gt;
              &lt;/span&gt;
              &lt;span class="aggregate_reactions_counter"&gt;36&lt;span class="hidden s:inline"&gt; reactions&lt;/span&gt;&lt;/span&gt;
            &lt;/div&gt;
          &lt;/a&gt;
            &lt;a href="https://dev.to/razielrodrigues/neuron-ai-o-framework-php-de-inteligencia-artificial-37nm#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              Comments


              &lt;span class="hidden s:inline"&gt;Add Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            6 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
      <category>php</category>
      <category>braziliandevs</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Neuron AI: O Framework PHP de Inteligência Artificial 🐘</title>
      <dc:creator>Raziel Rodrigues</dc:creator>
      <pubDate>Tue, 13 May 2025 09:14:37 +0000</pubDate>
      <link>https://forem.com/razielrodrigues/neuron-ai-o-framework-php-de-inteligencia-artificial-37nm</link>
      <guid>https://forem.com/razielrodrigues/neuron-ai-o-framework-php-de-inteligencia-artificial-37nm</guid>
      <description>&lt;p&gt;Neuron AI é um framework para lidar com IA usando PHP puro ou seus diversos frameworks como o Laravel ou Symfony. Neuron AI foi criado por Valerio Barbera &lt;a href="https://www.linkedin.com/in/valeriobarbera/" rel="noopener noreferrer"&gt;https://www.linkedin.com/in/valeriobarbera/&lt;/a&gt; da equipe do software inspector.dev, uma ferramenta de observabilidade PHP. Com este framework é possível trabalhar com AI de uma maneira muito flexível e prática usando PHP. Neste repositório, estou abordando os aspectos mais importantes do framework e do mundo da IA, onde é possível fazer tudo o que fazemos em outras linguagens de programação, como Node, Python ou Go, mas tudo usando o glorioso PHP em sua melhor forma.&lt;/p&gt;

&lt;p&gt;Para isso, eu irei usar o PHP puro, pois assim acredito que conseguimos realizar os testes de forma mais simples e sem acoplamento de muitas coisas. Então será necessário que você tenha o PHP rodando na sua versão 8+ e o Composer para assim começarmos a trabalhar com o projeto. Outros requerimentos serão o Ollama para rodarmos o nosso LLM de forma local sem gastar dinheiro com serviços de nuvem (mas isso não te impede de usar uma outra API como o ChatGPT ou Claude).&lt;/p&gt;

&lt;h1&gt;
  
  
  Introdução
&lt;/h1&gt;

&lt;p&gt;Cara, eu estou realmente muito empolgado escrevendo esse artigo porque eu sei como isso é importante para a comunidade do PHP. Sabendo que agora temos um framework que é tão flexível e desacoplado, eu consigo ver um futuro enorme para a nossa linguagem preferida e a forma como usamos ela para trabalhar com AI. É importante ressaltar que o PHP já possui alguns frameworks para trabalhar com AI como: LLPhant, PHP-ML, TensorFlow PHP e Rubix ML.&lt;/p&gt;

&lt;p&gt;Mas eu realmente acho que o Neuron AI, dentro do que eu vi dos outros frameworks, sai na frente em questão de flexibilidade e pouca dependência. Portanto, é um novo projeto open source e eu convido vocês a irem ao GitHub dessa maravilha e já deixar uma estrela ou mesmo ajudar a contribuir. O que mais me faz acreditar nesse projeto é que foi algo criado por pessoas que já têm um histórico sólido e profissional com PHP e na comunidade open source. Segue o link do repositório Neuron AI: &lt;a href="https://github.com/inspector-apm/neuron-ai" rel="noopener noreferrer"&gt;https://github.com/inspector-apm/neuron-ai&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Então aqui nesse artigo eu vou criar com vocês uma mini aplicação de AI que vai contar piadas e vai retornar também o tipo da piada. Massa demais, né?&lt;/p&gt;

&lt;p&gt;Posteriormente, irei escrever mais artigos explicando como funcionam os Agentes MCP, RAG, Vector Store, Chat e muito mais! Será um conteúdo denso, então eu pretendo escrever uma série de artigos sobre o tema.&lt;/p&gt;

&lt;p&gt;Sem mais delongas, vamos começar a parte DIVERTIDA!&lt;/p&gt;

&lt;h1&gt;
  
  
  Sumário
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Conceitos chave e instalação dos pacotes&lt;/li&gt;
&lt;li&gt;Agentes de AI com PHP&lt;/li&gt;
&lt;li&gt;Ferramentas e chamadas de funções&lt;/li&gt;
&lt;li&gt;Saída de dados estruturadas&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Conceitos chave e instalação
&lt;/h1&gt;

&lt;p&gt;Basicamente, o Neuron AI funciona com Agentes. Essa é uma das classes principais que utilizamos para criar um agente de inteligência artificial. Então, após criar a sua classe e implementar o seu agente, é possível configurar ele e dar a ele uma "personalidade" e "funções", assim como damos um contexto quando criamos uma janela no ChatGPT. Mas, nesse caso, é você que define e deixa isso chumbado no código, abrindo a possibilidade de podermos criar diversos agentes para regras de negócio específicas.&lt;/p&gt;

&lt;p&gt;Nesse caso, será necessário ter o Ollama rodando no seu computador. Para isso, eu te convido a ler esse primeiro artigo de minha autoria. Nesse artigo, eu ensino como instalar e usar o Ollama, que é praticamente o mesmo processo para usarmos com o NeuronAI:&lt;/p&gt;

&lt;p&gt;Tutorial | Usando Deepseek no Visual Studio Code de graça 💸 &lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/razielrodrigues/usando-deepseek-no-visual-studio-code-de-graca-2764"&gt;https://dev.to/razielrodrigues/usando-deepseek-no-visual-studio-code-de-graca-2764&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Após ter o Ollama instalado, será necessário rodar esse comando:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;composer require inspector-apm/neuron-ai&lt;/code&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Agente de AI
&lt;/h1&gt;

&lt;p&gt;Vamos criar um agente de AI que vai ajudar a gente a fazer umas piadas, sabe? No estilo tiosão de churrasco. Crie agora um arquivo chamado &lt;code&gt;AgenteComediante.php&lt;/code&gt; dentro de uma pasta &lt;code&gt;src&lt;/code&gt; e copie e cole o seguinte código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;src&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;require_once&lt;/span&gt; &lt;span class="k"&gt;__DIR__&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/../vendor/autoload.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;NeuronAI\Agent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;NeuronAI\SystemPrompt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;NeuronAI\Providers\Ollama\Ollama&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;NeuronAI\Chat\Messages\UserMessage&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;NeuronAI\Providers\AIProviderInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AgenteComediante&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;Agent&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;provider&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;AIProviderInterface&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Ollama&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'http://localhost:11434/api/'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s1"&gt;'qwen3:1.7b'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;# adicione aqui o modelo que baixou&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;instructions&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;SystemPrompt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;background&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="s1"&gt;'Você deve agir como um comediante Brasileiro'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;steps&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="s1"&gt;'Você usa a linguagem Português Brasileiro'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;],&lt;/span&gt;
            &lt;span class="n"&gt;output&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="s1"&gt;'A sua piada tem um texto bem divertido para dar contexto'&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;$response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AgenteComediante&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;chat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Olá, me conte uma piada!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nb"&gt;var_dump&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$response&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getContent&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Ferramentas ou chamada de funções
&lt;/h1&gt;

&lt;p&gt;Após rodar o código, será possível ver o seu agente de AI agindo como um tiosão e fazendo uma piada que pode ser boa ou ruim hahaha. Isso vai depender de muitas coisas, mas principalmente do tanto de parâmetro que a sua AI tem. Caso ela tenha mais parâmetros, é possível que a piada saia mais engraçada.&lt;/p&gt;

&lt;p&gt;Mas para resolver essa limitação, o Neuron Framework conta com uma feature muito boa que são as chamadas "Tools" ou também "Function Call". Isso é basicamente uma forma de pegar dados de outro lugar ou respostas e adicionar à sua AI, dando assim a ela mais "poderes" e possibilitando uma resposta mais inteligente e com um contexto maior. Então vamos adicionar um novo método na nossa classe. Copie e cole essas linhas de código:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
        &lt;span class="nc"&gt;Tool&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s1"&gt;'pegar_piadas'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'Recuperar as piadas'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;setCallable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;BuscarPiada&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;];&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E adicione isso no &lt;code&gt;steps&lt;/code&gt; para garantir que vai usar a tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="n"&gt;steps&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;'Você usa a ferramenta disponível'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s1"&gt;'Você usa a linguagem Português Brasileiro'&lt;/span&gt;
&lt;span class="p"&gt;],&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Crie um novo arquivo chamado &lt;code&gt;BuscarPiada.php&lt;/code&gt;, copie e cole, e não se esqueça de importar a nova classe dentro do agente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;src&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;GuzzleHttp\Client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;require_once&lt;/span&gt; &lt;span class="k"&gt;__DIR__&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/../vendor/autoload.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BuscarPiada&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="kt"&gt;Client&lt;/span&gt; &lt;span class="nv"&gt;$client&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Client&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'base_uri'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'https://official-joke-api.appspot.com'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s1"&gt;'headers'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
                &lt;span class="s1"&gt;'accept'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s1"&gt;'application/json'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__invoke&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$resposta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'/random_joke'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$resposta&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getStatusCode&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!==&lt;/span&gt; &lt;span class="mi"&gt;200&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;'Error :('&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="nv"&gt;$resposta&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;json_decode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$resposta&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getBody&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getContents&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$piada&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;''&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$piada&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'tipo: '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$resposta&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'type'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="kc"&gt;PHP_EOL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$piada&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'setup: '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$resposta&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'setup'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="kc"&gt;PHP_EOL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="nv"&gt;$piada&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'punchline:'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$resposta&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'punchline'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="kc"&gt;PHP_EOL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$piada&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Respostas estruturadas
&lt;/h1&gt;

&lt;p&gt;Após adicionar as tools, é possível ver que realmente o nosso código já retorna algo bem interessante, pois pega o que vem da API em inglês, traduz para português e depois gera a nossa piada. Mas ainda podemos reparar que as respostas não têm padrão, gerando assim uma string muito confusa e sem sentido. Além disso, a gente ainda fica vendo os pensamentos da AI e isso não é nada user-friendly. Para resolver isso, o Neuron tem um conceito chamado resposta estruturada, que são schemas e são mapeados via classe. Então vamos implementar isso e deixar a resposta formatada e sempre legível.&lt;/p&gt;

&lt;p&gt;Crie um arquivo chamado &lt;code&gt;Piada.php&lt;/code&gt; e copie e cole. Não se esqueça de importar a classe dentro do agente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;src&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;NeuronAI\StructuredOutput\SchemaProperty&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;require_once&lt;/span&gt; &lt;span class="k"&gt;__DIR__&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'/../vendor/autoload.php'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Piada&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;#[SchemaProperty(description: 'Contexto da piada', required: true)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$tipo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="na"&gt;#[SchemaProperty(description: 'Questionamento da piada', required: true)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$setup&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="na"&gt;#[SchemaProperty(description: 'Porque de ser engraçado', required: true)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$punchline&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Adicione este método dentro do agente:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getOutputClass&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nc"&gt;Piada&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;E altere a resposta para:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nv"&gt;$piada&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;AgenteComediante&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;make&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;structured&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;UserMessage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Olá, me conte uma piada!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'Aqui está a sua Piada :D'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="kc"&gt;PHP_EOL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'Tipo: '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$piada&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;tipo&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="kc"&gt;PHP_EOL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'Introdução: '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$piada&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;setup&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="kc"&gt;PHP_EOL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'Punchline: '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$piada&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;punchline&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="kc"&gt;PHP_EOL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Conclusão
&lt;/h1&gt;

&lt;p&gt;Esse é um exemplo do que pode ser feito com a AI. Nos próximos artigos vamos explorar o RAG, MCP Server e, para fechar com chave de ouro, Chat e Embeddings. Com o Neuron AI vai ser possível criarmos aplicações totalmente funcionais com AI, e tudo isso usando PHP, seja com frameworks ou de forma pura. Fique ligado para os próximos artigos onde vamos nos aprofundar mais e mais e vamos criar uma AI cada vez mais funcional e com diversas funcionalidades incríveis.&lt;/p&gt;

&lt;p&gt;Aqui está o código do projeto e outros códigos que fiz sobre AI:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/RazielRodrigues/ai-projects" rel="noopener noreferrer"&gt;https://github.com/RazielRodrigues/ai-projects&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Referência
&lt;/h1&gt;

&lt;p&gt;[&lt;a href="https://docs.neuron-ai.dev/" rel="noopener noreferrer"&gt;https://docs.neuron-ai.dev/&lt;/a&gt;]&lt;/p&gt;

</description>
      <category>php</category>
      <category>braziliandevs</category>
      <category>ai</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Como Utilizar Handlebars.js para Renderizar Templates Dinâmicos 〰️</title>
      <dc:creator>Raziel Rodrigues</dc:creator>
      <pubDate>Thu, 20 Mar 2025 20:12:22 +0000</pubDate>
      <link>https://forem.com/razielrodrigues/como-utilizar-handlebarsjs-para-renderizar-templates-dinamicos--1ab7</link>
      <guid>https://forem.com/razielrodrigues/como-utilizar-handlebarsjs-para-renderizar-templates-dinamicos--1ab7</guid>
      <description>&lt;p&gt;O handlebars é uma biblioteca Javascript que compila templates HTML,&lt;br&gt;
com base em dados JSON, fazendo então um "espelhamento" dos dados JSON no HTML,&lt;br&gt;
tudo isso com base na chamada das chaves dos dados JSON.&lt;/p&gt;

&lt;p&gt;lib: &lt;a href="https://handlebarsjs.com/" rel="noopener noreferrer"&gt;https://handlebarsjs.com/&lt;/a&gt;&lt;br&gt;
repo: &lt;a href="https://github.com/RazielRodrigues/js-handlebars-learning-path" rel="noopener noreferrer"&gt;https://github.com/RazielRodrigues/js-handlebars-learning-path&lt;/a&gt;&lt;br&gt;
projeto online: &lt;a href="https://razielrodrigues.github.io/js-handlebars-learning-path/" rel="noopener noreferrer"&gt;https://razielrodrigues.github.io/js-handlebars-learning-path/&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Começando com o Handlebars
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Instalar Handlebars&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CDN: &lt;a href="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.6/handlebars.min.js" rel="noopener noreferrer"&gt;https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.6/handlebars.min.js&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Primeiro devemos definir a tag de template no HTML&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;essa tag deve ter um type="" diferente como: x-template-handlebars&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;essa tag tem que ter um ID&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script id="handlebars-template" type="text/x-handlebars-template"&amp;gt;
    //Aqui dentro vai o código do template
    {{HelloWorld}}
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Depois devemos definir a tag que ira ser injetado o conteudo&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    &amp;lt;main id="content-inject"&amp;gt;&amp;lt;/main&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Em seguida, devemos criar a função de renderização do template&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    //1. Pegamos o conteúdo do template que se encontra na tag script do handlebars
    const template = document.getElementById('handlebars-template').innerHTML;

    //2. Em seguida, chamamos a função compiladora do HB
    //que vai interpretar as tags que escrevemos como a {{HelloWorld}}
    const compiledTemplate = Handlebars.compile(template);

    //3. Após isso, pegamos a variavel que vamos injetar o template compilado
    const contentInject = document.getElementById('content-inject');

    /*
    4. Por fim, injetamos nela os dados para aparecerem no template
       perceba que chamamos novamente a variavel 'compiledTemplate'
       pois agora ela é a função que contém o conteudo do template
       o que acontece agora é basicamente um espelho dos dados JSON
       ou seja o campo que tiver aqui ou o array que tiver aqui
       vao ser "chamados" dentro do template, e assim irá refletir
       os valores desses campos JSON no nosso HTML.
    */
    contentInject.innerHTML = compiledTemplate({
        HelloWorld: 'Hello World!'
    });
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Por fim o nosso HTML ficará algo como:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        &amp;lt;!DOCTYPE html&amp;gt;
        &amp;lt;html lang="en"&amp;gt;
        &amp;lt;head&amp;gt;
            &amp;lt;meta charset="UTF-8"&amp;gt;
            &amp;lt;meta name="viewport" content="width=device-width, initial-scale=1.0"&amp;gt;
            &amp;lt;title&amp;gt;HANDLEBARS LEARNING PATH&amp;lt;/title&amp;gt;
        &amp;lt;/head&amp;gt;
        &amp;lt;body&amp;gt;
            &amp;lt;main id="content-inject"&amp;gt;&amp;lt;/main&amp;gt;



            &amp;lt;script src="https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.7.6/handlebars.min.js"&amp;gt;&amp;lt;/script&amp;gt;
            &amp;lt;script id="handlebars-template" type="text/x-handlebars-template"&amp;gt;
            &amp;lt;h1&amp;gt;{{HelloWorld}}&amp;lt;/h1&amp;gt;
            &amp;lt;/script&amp;gt;

            &amp;lt;script&amp;gt;
                const template = document.getElementById('handlebars-template').innerHTML;
                const compiledTemplate = Handlebars.compile(template);
                const contentInject = document.getElementById('content-inject');
                contentInject.innerHTML = compiledTemplate({
                    HelloWorld: 'Hello World!'
                });
            &amp;lt;/script&amp;gt;
        &amp;lt;/body&amp;gt;
        &amp;lt;/html&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Criando templates com dados JSON e EACH helper
&lt;/h2&gt;

&lt;p&gt;Dentro da função de compilação passar os dados em JSON que podem ser também a resposta de uma API JSON,&lt;br&gt;
por enquanto vamos ver com os dados de um array:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    contentInject.innerHTML = compiledTemplate({
    Users: [
        {
        "id": 1,
        "name": "Leanne Graham",
        "username": "Bret",
        "email": "Sincere@april.biz",
        "address": {
            "street": "Kulas Light",
            "suite": "Apt. 556",
            "city": "Gwenborough",
            "zipcode": "92998-3874",
            "geo": {
            "lat": "-37.3159",
            "lng": "81.1496"
            }
        },
        "phone": "1-770-736-8031 x56442",
        "website": "hildegard.org",
        "company": {
            "name": "Romaguera-Crona",
            "catchPhrase": "Multi-layered client-server neural-net",
            "bs": "harness real-time e-markets"
        }
        }
    ]
    });
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Dessa forma conseguimos acessar os dados do JSON por níveis, usando o helper {{each NomeObjeto}} {{#each}}&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script id="handlebars-template" type="text/x-handlebars-template"&amp;gt;
  &amp;lt;ul&amp;gt;
    {{#each Users}}
      &amp;lt;li&amp;gt;{{id}}&amp;lt;/li&amp;gt;
      &amp;lt;li&amp;gt;{{name}}&amp;lt;/li&amp;gt;
    {{/each}}
  &amp;lt;/ul&amp;gt;
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;A tag de template fica dessa forma assim conseguimos acessar o primeiro nivel do array, para acessar outros niveis do array&lt;br&gt;
podemos usar:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    {{#each Users}}
      {{address.street}}
    {{/each}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;ou&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    {{#each Users}}
        {{address / street}}
    {{/each}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;ou&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    {{#each Users}}
        {{#with address}}
            {{street}}
        {{/with}}
    {{/each}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;para subir um contexto usamos:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    {{#each Users}}&lt;br&gt;
        {{#with company}}&lt;br&gt;
            //pega o nome da companhia&lt;br&gt;
            &amp;lt;li&amp;gt;{{name}}&amp;lt;/li&amp;gt;&lt;br&gt;
            //pega o nome do cliente no contexto acima&lt;br&gt;
            &amp;lt;li&amp;gt;{{../name}}&amp;lt;/li&amp;gt;&lt;br&gt;
        {{/with}}&lt;br&gt;
    {{/each}}&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Operadores lógicos&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;O if no handlebars verifica se propriedade tem algum valor, se retornar false, não exibe aquilo&lt;br&gt;
podendo ser encadeado com else if e tambem com else, ficando algo como:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        {{#if image}}&lt;br&gt;
            &amp;lt;img src="{{image}}" class="card-img-top" alt="{{name}}" title="{{name}}"&amp;gt;&lt;br&gt;
        {{else}}&lt;br&gt;
            &amp;lt;img src="&lt;a href="https://upload.wikimedia.org/wikipedia/commons/thumb/a/ac/No_image_available.svg/600px-No_image_available.svg.png" rel="noopener noreferrer"&gt;https://upload.wikimedia.org/wikipedia/commons/thumb/a/ac/No_image_available.svg/600px-No_image_available.svg.png&lt;/a&gt;" class="card-img-top" alt="{{name}}" title="{{name}}"&amp;gt;&lt;br&gt;
        {{/if}}
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    {{#if email}}
        &amp;amp;lt;p class="card-text"&amp;amp;gt;
        email: {{email}}
        &amp;amp;lt;/p&amp;amp;gt;
    {{else if username}}
        &amp;amp;lt;p class="card-text"&amp;amp;gt;
        username: {{username}}
        &amp;amp;lt;/p&amp;amp;gt;
    {{else}}
        &amp;amp;lt;p class="card-text"&amp;amp;gt;
        No information!
        &amp;amp;lt;/p&amp;amp;gt;
    {{/if}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Renderizando dados com o JQUERY&lt;br&gt;
&lt;/h2&gt;
&lt;br&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    $(document).ready(function() {&lt;br&gt;
        const template = $('#handlebars-template').html();&lt;br&gt;
        const compiledTemplate = Handlebars.compile(template);&lt;br&gt;
        $.ajax("data/profiles.json").done(function(data) {&lt;br&gt;
            $('#content-inject').html(compiledTemplate(data));&lt;br&gt;
        });&lt;br&gt;
    });&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Helpers&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;Com os helpers podemos registrar nossos proprios blocos {{CapitalizarLetra 'parametro'}} que nos ajudam a formatar os textos ou outras coisas.&lt;/p&gt;

&lt;p&gt;Para usar um helper primeiro devemos registrar ele:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        //TIPO 1: Esse helper ele pega apenas um dado age como {{#if}}&lt;br&gt;
        Handlebars.registerHelper("makeBold", function(parametro){&lt;br&gt;
            return new Handlebars.SafeString("&amp;lt;strong&amp;gt;"+parametro+"&amp;lt;/strong&amp;gt;");&lt;br&gt;
        });
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    //NO HTML:
    street: {{makeBold street}}

    //TIPO 2: Esse helper ele age como os bloc {{#each}} {{#with}}
    Handlebars.registerHelper("makeTitle", function(options){
        return new Handlebars.SafeString("&amp;amp;lt;h5&amp;amp;gt;"+options.fn(this)+"&amp;amp;lt;/h5&amp;amp;gt;");
    });

    //NO HTML:
    street: {{makeBold street}}
    {{#makeTitle}}
        zipcode: {{zipcode}}
    {{/makeTitle}}
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Eventos&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;Como o template é renderizado depois da pagina os objetos nao são identificados pelo dom, para isso precisamos&lt;br&gt;
criar uma função que busque pelos elementos HTML pós renderização e assim poder capturar os eventos:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        //IF CLICK IN BUTTON YOU CAN HANDLE THE EVENT.&lt;br&gt;
        $(document).on("click", ".actions", function(e){&lt;br&gt;
            e.preventDefault();&lt;br&gt;
            console.log("click");&lt;br&gt;
        });&lt;br&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Select em dados&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;Para escolher um dado especidifico na estrutura vamos passar o indice do array clicado via parametro GET&lt;br&gt;
depois vamos procurar na URL o valor do ID que foi enviado e assim renderizar em outra página apenas o dado especifico.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;passar dado pelo HTML da pagina INDEX para montar o parametro GET:&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//Dessa forma pega o indice do elemento renderizado começando em 0
&amp;lt;a href="details.html?id={{@index}}" class="btn btn-primary"&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Varrer URL:&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;var getUrlParameter = function getUrlParameter(sParam) {
    var sPageURL = window.location.search.substring(1),
        sURLVariables = sPageURL.split('&amp;amp;'),
        sParameterName,
        i;

    for (i = 0; i &amp;lt; sURLVariables.length; i++) {
        sParameterName = sURLVariables[i].split('=');

        if (sParameterName[0] === sParam) {
            return sParameterName[1] === undefined ? true : decodeURIComponent(sParameterName[1]);
        }
    }
};
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;O HTML da pagina details nao precisa do EACH ja que vamos exibir o individual, como nos queremos apenas um elemento do array&lt;br&gt;
nos tiramos o each assim nos precisamos passar o indice do array que queremos renderizar então para isso vamos fazer uma verificação, &lt;br&gt;
caso seja sem a classe details no body exibe a lista de todos se tiver o details exibe so um, e quando achado essa classe passa o ID&lt;br&gt;
da URL como indice do array assim exibindo apenas um perfil na pagina details.&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt; if ($("body").hasClass("profile-details")) {
   var profileID = getUrlParameter("id");
   $('#content-inject').html(compiledTemplate(data.Users[profileID]));
 }else{
   $('#content-inject').html(compiledTemplate(data));
 }
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Partials
&lt;/h2&gt;

&lt;p&gt;O partials no handlebars consiste em voce separar pequenas partes do codigo e usar elas &lt;br&gt;
apenas fazendo a referencia de uma tag {{&amp;gt; nomePartials}}&lt;/p&gt;

&lt;p&gt;Devemos criar uma nova tag de template o ideal é essa tag de template ficar em um arquivo separado,&lt;br&gt;
pois dai consegue chamar ela mais organizadamente, por exemplo com o PHP se usaria o include com JS vamos fazer&lt;br&gt;
uma chamada AJAX.&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Criar a tag:&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;script id="details-partial" type="text/x-handlebars-template"&amp;gt;
&amp;lt;div class="card-text"&amp;gt;
    {{#with address}}
    street: {{makeBold street}}
    &amp;lt;br&amp;gt;
    suite: {{suite}}
    &amp;lt;br&amp;gt;
    city: {{city}}
    &amp;lt;br&amp;gt;
    {{#makeTitle}}
        zipcode: {{zipcode}}
    {{/makeTitle}}
    {{/with}}
&amp;lt;/div&amp;gt;
&amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Registrar o Partial:&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Handlebars.registerPartial("AddressPartial", $("#details-partial").html());
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fazer a chamada do arquivo que contem o partial:&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/*
    Lembrando que a tag script do partial esta em outro arquivo em outro lugar
    o que vamos fazer é incluir esse arquivo onde queremos usar o Partial,
    após registrar ele no arquivo main.js junto com as outras funções,
    vamos resgatar o arquivo que contém o template partial e embedar ele no body.
    após isso nos fazemos a chamada do partials, onde passamos o nome dele é o nome
    da tag que queremos renderizar (tag do AJAX)
*/
$.ajax("detailpartial.html").done(function(partial) {
    $("body").append(partial);
    Handlebars.registerPartial("AddressPartial", $("#details-partial").html());
});
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Após isso basta chamar o partials com uma tag {{&amp;gt; nomePartials}}&lt;/p&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;    &amp;lt;script id="handlebars-template" type="text/x-handlebars-template"&amp;gt;
        {{#each Users}}
        &amp;lt;div class="card text-center m-1 container" style="width: 18rem;"&amp;gt;
            &amp;lt;div class="card-body"&amp;gt;
                &amp;lt;h5 class="card-title"&amp;gt;{{name}}&amp;lt;/h5&amp;gt;

                {{#if email}}
                &amp;lt;p class="card-text"&amp;gt;
                    email: {{email}}
                &amp;lt;/p&amp;gt;
                {{else if username}}
                &amp;lt;p class="card-text"&amp;gt;
                    username: {{username}}
                &amp;lt;/p&amp;gt;
                {{else}}
                &amp;lt;p class="card-text"&amp;gt;
                    No information!
                &amp;lt;/p&amp;gt;
                {{/if}}
                //Chamando vai renderizar os dados de endereço
                {{&amp;gt; AddressPartial}}
            &amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        {{/each}}
    &amp;lt;/script&amp;gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Perceba que chamo o partials dentro de outra tag de template esse [e o intuito, reutilizar de forma que &lt;br&gt;
nao fique muito codigo e tudo bem mais limpos, se tiver um partial em dois lugares, basta editar um arquivo&lt;br&gt;
que ja edita em todos os lugares.&lt;/p&gt;

</description>
      <category>javascript</category>
      <category>webdev</category>
      <category>programming</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Criei um site que mostra quem eu sou (Literalmente)</title>
      <dc:creator>Raziel Rodrigues</dc:creator>
      <pubDate>Wed, 05 Mar 2025 22:09:02 +0000</pubDate>
      <link>https://forem.com/razielrodrigues/criei-um-site-que-mostra-quem-eu-sou-literalmente-2j1i</link>
      <guid>https://forem.com/razielrodrigues/criei-um-site-que-mostra-quem-eu-sou-literalmente-2j1i</guid>
      <description>&lt;p&gt;Gostaria de compartilhar a versão final do meu site pessoal com vocês. Criei este projeto como um desafio pessoal e gostei muito do resultado, coloquei minha identidade neste site, queria criar algo que mostrasse quem eu sou. Por isso usei referências a coisas que gosto, por exemplo animes, videogames e, claro, hashtag#PHP.&lt;/p&gt;

&lt;p&gt;Neste projeto, levei minha criatividade a outro nível e enfrentei muitos desafios. Compartilhei com meus amigos e coletei feedback de pessoas ao meu redor. Refinei o site e agora estou feliz com o resultado e animado para compartilhar e ouvir o feedback de vocês.&lt;/p&gt;

&lt;p&gt;Usei várias tecnologias para criar este site e aqui vou detalhar para você:&lt;/p&gt;

&lt;p&gt;Frontend:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;ReactJS&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Modelo 3D usando o Avaturn AI para criar um personagem com minhas características&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Three JS e React Three Fiber para renderizar a malha e trabalhar com o Canva&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Mixamo para adicionar ação ao modelo 3D e React Three Drei para controlar as ações&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Particle JS para adicionar fundo interativo&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;GSAP para adicionar animações suaves aos componentes e transição de página&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Tailwind CSS para adicionar estilos com Material Tailwind CSS&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;React Spoiled para aplicar efeito de sombra às palavras&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Rotating Logic para controlar o 3D e vinculá-lo ao estado do React&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Animações CSS mostram elementos&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Backend:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;Vercel para fazer a implantação&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;EmailJS para enviar e-mails&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Integração Firebase para contar visitantes do site&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;API feita em Go que se conecta com a API dev.to e a API do GitHub para obter os dados para o páginas de projetos e artigos&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Web LLM embed (AI Lab está em construção)&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Espero que você goste ou talvez lhe dê algumas dicas sobre como codificar seu site pessoal.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.razielrodrigues.dev/" rel="noopener noreferrer"&gt;https://www.razielrodrigues.dev/&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>programming</category>
      <category>react</category>
      <category>braziliandevs</category>
    </item>
    <item>
      <title>Encryptor | My first open source project 🔐</title>
      <dc:creator>Raziel Rodrigues</dc:creator>
      <pubDate>Wed, 26 Feb 2025 17:26:29 +0000</pubDate>
      <link>https://forem.com/razielrodrigues/encryptor-my-first-open-source-project-2fkf</link>
      <guid>https://forem.com/razielrodrigues/encryptor-my-first-open-source-project-2fkf</guid>
      <description>&lt;p&gt;I'm getting into the open-source world and I am excited to share my first project: &lt;strong&gt;Encryptor&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I also say more here&lt;/p&gt;

&lt;p&gt;&lt;a href="https://dev.to/razielrodrigues/how-to-use-asymetric-encryption-with-php-and-openssl-idl"&gt;https://dev.to/razielrodrigues/how-to-use-asymetric-encryption-with-php-and-openssl-idl&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Encryptor is a Web App for &lt;strong&gt;assymmetric encryption&lt;/strong&gt; using OpenSSL (I have plans to expand the supports and maybe create the own algorithm for the project), allowing you to securely encrypt and decrypt strings with ease. The code is written in raw PHP.&lt;/p&gt;

&lt;h3&gt;
  
  
  🔹 Features:
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Assymmetric encryption and decryption&lt;/li&gt;
&lt;li&gt;Lightweight and easy to use&lt;/li&gt;
&lt;li&gt;Pure PHP implementation with no dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;📌 &lt;strong&gt;Repository:&lt;/strong&gt; &lt;a href="https://github.com/RazielRodrigues/encryptor" rel="noopener noreferrer"&gt;GitHub - RazielRodrigues/encryptor&lt;/a&gt;  &lt;/p&gt;

&lt;p&gt;📌 &lt;strong&gt;Live Preview:&lt;/strong&gt; &lt;a href="https://encryptor.razielrodrigues.dev/" rel="noopener noreferrer"&gt;Live Preview&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;I would appreciate that you check it out, contribute, and help me grow this project! Whether it’s feedback, improvements, or new ideas, your contributions are welcome. Let's build something nice together!&lt;/p&gt;

</description>
      <category>php</category>
      <category>programming</category>
      <category>opensource</category>
      <category>webdev</category>
    </item>
    <item>
      <title>PHP Tips | Exploring the Flyweight/Singleton Pattern 🏗️</title>
      <dc:creator>Raziel Rodrigues</dc:creator>
      <pubDate>Wed, 26 Feb 2025 06:59:00 +0000</pubDate>
      <link>https://forem.com/razielrodrigues/php-tips-exploring-the-flyweightsingleton-pattern-f10</link>
      <guid>https://forem.com/razielrodrigues/php-tips-exploring-the-flyweightsingleton-pattern-f10</guid>
      <description>&lt;h2&gt;
  
  
  Introduction
&lt;/h2&gt;

&lt;p&gt;Design patterns provide efficient solutions to recurring software development problems. In this article, we'll explore two powerful design patterns &lt;strong&gt;Flyweight&lt;/strong&gt; and &lt;strong&gt;Singleton&lt;/strong&gt; with practical examples from my GitHub repositories.&lt;/p&gt;




&lt;h2&gt;
  
  
  Flyweight Pattern 🏗️
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Flyweight pattern&lt;/strong&gt; is a &lt;strong&gt;structural design pattern&lt;/strong&gt; that optimizes memory usage by sharing common data among objects. It divides object states into:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Intrinsic State:&lt;/strong&gt; Shared among many objects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Extrinsic State:&lt;/strong&gt; Unique to each object, provided at runtime.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This pattern is beneficial when handling a large number of similar objects efficiently, reducing memory overhead.&lt;/p&gt;

&lt;p&gt;Below is an example from my &lt;a href="https://github.com/RazielRodrigues/php-design-patterns/blob/master/Structural/Flyweight.php" rel="noopener noreferrer"&gt;PHP Design Patterns repository&lt;/a&gt;. The &lt;code&gt;Flyweight&lt;/code&gt; class encapsulates shared state and accepts unique state.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;Behavorial&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Flyweight&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="nv"&gt;$sharedState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$sharedState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;sharedState&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$sharedState&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Performs an operation using shared (intrinsic) and unique (extrinsic) states.
     *
     * @param mixed $uniqueState The extrinsic state supplied at runtime.
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$uniqueState&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Flyweight: Shared state ("&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;sharedState&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;") "&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt;
             &lt;span class="s2"&gt;"and unique state ("&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$uniqueState&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s2"&gt;")&amp;lt;br&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Example usage:&lt;/span&gt;
&lt;span class="nv"&gt;$flyweight&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Flyweight&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Shared Data'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="nv"&gt;$flyweight&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;operation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Unique Data'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Benefits of Flyweight
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Memory Efficiency:&lt;/strong&gt; Reduces redundant object storage.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance Optimization:&lt;/strong&gt; Speeds up applications dealing with numerous similar objects.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Scalability:&lt;/strong&gt; Useful for caching, rendering systems, and object pooling.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Singleton Pattern
&lt;/h2&gt;

&lt;p&gt;The &lt;strong&gt;Singleton pattern&lt;/strong&gt; is a &lt;strong&gt;creational design pattern&lt;/strong&gt; that ensures a class has only one instance, providing global access to it. It is commonly used for logging, configuration management, and shared resource control.&lt;/p&gt;

&lt;p&gt;Here’s an example from my &lt;a href="https://github.com/RazielRodrigues/php-design-patterns/blob/master/Creational/Singleton.php" rel="noopener noreferrer"&gt;Design Patterns repository&lt;/a&gt;. This &lt;code&gt;LuzSingleton&lt;/code&gt; class manages a light's state:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LuzSingleton&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;?LuzSingleton&lt;/span&gt; &lt;span class="nv"&gt;$instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nv"&gt;$lightStatus&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;__construct&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lightStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'OFF'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;LuzSingleton&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nv"&gt;$instance&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nv"&gt;$instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;self&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nv"&gt;$instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Turns the light ON.
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;turnOn&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lightStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'ON'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Light turned &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lightStatus&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Turns the light OFF.
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;turnOff&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lightStatus&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'OFF'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Light turned &lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lightStatus&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="cd"&gt;/**
     * Retrieves the current status of the light.
     *
     * @return string The current light status.
     */&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;getStatus&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;lightStatus&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Exemplo de uso&lt;/span&gt;
&lt;span class="nv"&gt;$luz&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;LuzSingleton&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;getInstance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="nv"&gt;$luz&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;turnOn&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="nv"&gt;$luz&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;getStatus&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// ON&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h4&gt;
  
  
  Benefits of Singleton
&lt;/h4&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Consistent State:&lt;/strong&gt; Ensures a single point of truth for shared resources.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Global Access:&lt;/strong&gt; Prevents redundant object creation.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Better Resource Management:&lt;/strong&gt; Useful for logging, caching, and configuration settings.&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Both &lt;strong&gt;Flyweight&lt;/strong&gt; and &lt;strong&gt;Singleton&lt;/strong&gt; patterns are essential tools in software development. While Flyweight optimizes memory usage by sharing common data, Singleton guarantees a single instance for centralized control.&lt;/p&gt;

&lt;p&gt;By integrating these design patterns into your PHP and Node.js applications, you can build more &lt;strong&gt;efficient, maintainable, and scalable&lt;/strong&gt; solutions.&lt;/p&gt;




&lt;p&gt;🚀 &lt;strong&gt;Explore my GitHub repositories for more examples:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/RazielRodrigues/php-design-patterns" rel="noopener noreferrer"&gt;PHP Design Patterns&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/RazielRodrigues/nodejs-design-patterns" rel="noopener noreferrer"&gt;Node.js Design Patterns&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;💬 &lt;strong&gt;Let’s Discuss!&lt;/strong&gt;&lt;br&gt;
Do you use these patterns in your projects? Share your thoughts in the comments below!&lt;/p&gt;

</description>
      <category>php</category>
      <category>programming</category>
      <category>tutorial</category>
      <category>designpatterns</category>
    </item>
    <item>
      <title>Automated Tests | How to mock classes with PHPUnit 🔧</title>
      <dc:creator>Raziel Rodrigues</dc:creator>
      <pubDate>Tue, 25 Feb 2025 10:20:20 +0000</pubDate>
      <link>https://forem.com/razielrodrigues/automated-tests-how-to-mock-classes-with-phpunit-14pp</link>
      <guid>https://forem.com/razielrodrigues/automated-tests-how-to-mock-classes-with-phpunit-14pp</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Mocks are basically clones of your classes. They override your class while maintaining the same type and return type as the original class. Ensuring the correct return type during the mock process is essential; otherwise, errors will occur. Let's say we want to mock a class used inside our calculator.&lt;/p&gt;

&lt;h1&gt;
  
  
  How to Mock in PHPUnit
&lt;/h1&gt;

&lt;p&gt;Following the previous code, add a new class called &lt;code&gt;PrintCalculationService&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Service&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PrintCalculationService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;array&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;array&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;# a lot of business rules...&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
            &lt;span class="s1"&gt;'result'&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nv"&gt;$result&lt;/span&gt;
        &lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;print&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;# a lot of business rules...&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s1"&gt;'result: '&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;setUp&lt;/code&gt; and &lt;code&gt;tearDown&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;These functions control the global state and execute before and after each test.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;setUp&lt;/code&gt; -&amp;gt; Executes actions before each test.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;tearDown&lt;/code&gt; -&amp;gt; Executes actions after each test.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  &lt;code&gt;createMock&lt;/code&gt; and &lt;code&gt;createStub&lt;/code&gt;
&lt;/h3&gt;

&lt;p&gt;These functions create a mock of your class. The key difference is that mocks provide more functionality than stubs. In other test frameworks, they have distinct purposes, but in PHPUnit, they are nearly identical.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;createStub&lt;/code&gt; -&amp;gt; Creates a stub based on the class.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;createMock&lt;/code&gt; -&amp;gt; Creates a mock based on the class.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-&amp;gt;method('print')&lt;/code&gt; -&amp;gt; Configures the method to return a specified value for testing purposes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-&amp;gt;willReturn('result: 2')&lt;/code&gt; -&amp;gt; Defines the return value to satisfy and pass the test.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;There are many other configurations available. You can find more details in the &lt;a href="https://docs.phpunit.de/en/12.0/test-doubles.html#test-doubles" rel="noopener noreferrer"&gt;PHPUnit Test Doubles Documentation&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Tests\Unit\Service&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Service\CalculatorService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Service\PrintCalculationService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PHPUnit\Framework\Attributes\DataProvider&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PHPUnit\Framework\Attributes\Test&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PHPUnit\Framework\MockObject\MockObject&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PHPUnit\Framework\TestCase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CalculatorServiceTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TestCase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;MockObject&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="nc"&gt;PrintCalculationService&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="kc"&gt;null&lt;/span&gt; &lt;span class="nv"&gt;$printCalculationService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;setUp&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;printCalculationService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;createMock&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;PrintCalculationService&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;protected&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;tearDown&lt;/span&gt;&lt;span class="p"&gt;():&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;printCalculationService&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;null&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;sumProvider&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="na"&gt;#[Test]&lt;/span&gt;
    &lt;span class="na"&gt;#[DataProvider('sumProvider')]&lt;/span&gt;
    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testSum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$expected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CalculatorService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;printCalculationService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertSame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;$service&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$y&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nv"&gt;$expected&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="na"&gt;#[Test]&lt;/span&gt;
    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testDivision&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CalculatorService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;printCalculationService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;$service&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;division&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="na"&gt;#[Test]&lt;/span&gt;
    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testDivisionException&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;expectException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;\Exception&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CalculatorService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;printCalculationService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$service&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;division&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="na"&gt;#[Test]&lt;/span&gt;
    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testSumPrint&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CalculatorService&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;printCalculationService&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$service&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertSame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;printCalculationService&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'array'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;willReturn&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
            &lt;span class="s1"&gt;'result mock: 2'&lt;/span&gt;
        &lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="nv"&gt;$print&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$service&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'array'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertSame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$print&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s1"&gt;'result mock: 2'&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;printCalculationService&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;method&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'print'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;willReturn&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'result mock: 2'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="nv"&gt;$print&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$service&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;show&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$result&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'print'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertSame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$print&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'result mock: 2'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Final Thoughts
&lt;/h1&gt;

&lt;p&gt;This has been an insightful journey! I hope you enjoyed it. I aimed to be as concise and to the point as possible, making it easier to quickly access the information. As I mentioned, writing tests requires a different mindset. We need to think in reverse. Mocks are an excellent way to approach this concept since they allow us to manipulate results and test every possible path in a function.&lt;/p&gt;

&lt;p&gt;Now I encourage you to go for more informations and best practives for your tests, this is just a ready to go and then you can already starting getting your code more senior&lt;/p&gt;

&lt;h1&gt;
  
  
  Additional Topics
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Code Coverage&lt;/li&gt;
&lt;li&gt;How to configure the PHPUnit XML file&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Recommended Reading
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.phpunit.de/en/12.0/attributes.html" rel="noopener noreferrer"&gt;PHPUnit Attributes Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.phpunit.de/en/12.0/fixtures.html#more-setup-than-teardown" rel="noopener noreferrer"&gt;PHPUnit Fixture Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.phpunit.de/en/12.0/code-coverage.html" rel="noopener noreferrer"&gt;PHPUnit Code Coverage Documentation&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.phpunit.de/en/12.0/extending-phpunit.html#enhancing-concrete-test-cases" rel="noopener noreferrer"&gt;PHPUnit Extending Documentation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;GitHub Repository:&lt;/strong&gt; &lt;a href="https://github.com/RazielRodrigues/php-unit-tests" rel="noopener noreferrer"&gt;Leave a star!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What do you think? Was this useful? Leave a comment!&lt;/p&gt;

</description>
      <category>php</category>
      <category>testing</category>
      <category>programming</category>
    </item>
    <item>
      <title>Automated Tests | How to unit tests with PHPUnit 🔧</title>
      <dc:creator>Raziel Rodrigues</dc:creator>
      <pubDate>Mon, 24 Feb 2025 17:52:48 +0000</pubDate>
      <link>https://forem.com/razielrodrigues/automated-tests-how-to-unit-tests-with-phpunit-1lee</link>
      <guid>https://forem.com/razielrodrigues/automated-tests-how-to-unit-tests-with-phpunit-1lee</guid>
      <description>&lt;h1&gt;
  
  
  Introduction
&lt;/h1&gt;

&lt;p&gt;Automated Tests are one of the most important parts of software engineering. Every important author of books says it is necessary and shows examples of how to do it properly. For example, when we read &lt;em&gt;Refactoring&lt;/em&gt; by Martin Fowler, we have a whole chapter dedicated to this topic, as well as other books like &lt;em&gt;Clean Code&lt;/em&gt; by Uncle Bob.&lt;/p&gt;

&lt;p&gt;Well, but then you might be thinking to yourself, "My project is legacy, and nobody writes tests." If you have this problem, I have something to say: I had the same issue, and many other developers did too.&lt;/p&gt;

&lt;p&gt;However, you should be bold with your team and explain to your tech manager or PO how important it is. Every time a bug happens, remind them how the lack of unit tests is bad. Eventually, they will understand. This is a technique from &lt;em&gt;The Pragmatic Programmer&lt;/em&gt;, where the author teaches how to achieve our technical goals.&lt;/p&gt;

&lt;p&gt;To make you more enthusiastic about it, I will share graphs from one of my work projects. When I started advocating for unit tests and worked hard for a week, I was able to increase code coverage from 0% to 30%.&lt;/p&gt;

&lt;p&gt;Okay, so now, what are automated tests? Let's begin with a concept. A while ago, someone asked me, "What is the automated test pyramid?" At that time, I didn’t know, but now I will share it with you and explain which topic we will focus on.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6m5j3cf4fi164ny5tj7r.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6m5j3cf4fi164ny5tj7r.png" alt=" " width="731" height="490"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Basically, writing tests follows a hierarchy of effort. You can research more using an AI engine:&lt;/p&gt;

&lt;p&gt;3 - E2E Tests&lt;br&gt;&lt;br&gt;
2 - Integration Tests&lt;br&gt;&lt;br&gt;
1 - Unit Tests &amp;lt;- our focus  &lt;/p&gt;
&lt;h1&gt;
  
  
  PHP Unit
&lt;/h1&gt;

&lt;p&gt;PHPUnit is one of the most famous test frameworks for PHP environments. Inside your PHP environment, run with Composer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;composer require &lt;span class="nt"&gt;--dev&lt;/span&gt; phpunit/phpunit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, navigate inside the folder and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./vendor/bin/phpunit
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will see the tests running.&lt;/p&gt;

&lt;p&gt;Create a class called &lt;code&gt;CalculatorService&lt;/code&gt; inside the &lt;code&gt;src&lt;/code&gt; folder and another one called &lt;code&gt;CalculatorServiceTest&lt;/code&gt; inside the &lt;code&gt;test&lt;/code&gt; folder.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Service&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CalculatorService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Tests\Unit\Service&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PHPUnit\Framework\TestCase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CalculatorServiceTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TestCase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;

&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Mindset
&lt;/h1&gt;

&lt;p&gt;It took me a while to understand, but unit testing is about reverse engineering. For example, if you are new to the project’s code and need to write tests for a function you don't know, prepare yourself to think in reverse. That’s actually what testing is about. You need to mock methods and other classes that are dependencies of your tests. To do it properly, you need to analyze parameters and return types, and sometimes mock objects inside the function. This is why writing unit tests is hard for classes with many dependencies, complex logic flows, or multiple conditional branches. If you want everything green, you need to use a lot of mocks.&lt;/p&gt;

&lt;p&gt;Another mindset is to test both valid and invalid responses while considering all possible edge cases.&lt;/p&gt;

&lt;h1&gt;
  
  
  Assertions and Types of Assertions
&lt;/h1&gt;

&lt;p&gt;Update your service with the following code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Service&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CalculatorService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$y&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$x&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="nv"&gt;$y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;division&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nv"&gt;$y&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;\Exception&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Error Processing Request"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nv"&gt;$x&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nv"&gt;$y&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now let's write a test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Tests\Unit\Service&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Service\CalculatorService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;AsyncAws\Core\Test\TestCase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PHPUnit\Framework\Attributes\Test&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CalculatorServiceTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TestCase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="na"&gt;#[Test]&lt;/span&gt;
    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testSum&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CalculatorService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertSame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;$service&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="mi"&gt;20&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the test:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;bin/phpunit &lt;span class="nt"&gt;--filter&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;testSum
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: Running with &lt;code&gt;--filter&lt;/code&gt; executes only the specified test method. PHPUnit has other flags, which can be found running the command with --help.&lt;/p&gt;

&lt;p&gt;You will see:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0o9bllykcvfbdq3juep0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0o9bllykcvfbdq3juep0.png" alt=" " width="669" height="157"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Assertions and Expecting
&lt;/h1&gt;

&lt;p&gt;Assertions are basically &lt;code&gt;if&lt;/code&gt; statements to check if everything is fine. PHPUnit provides different types of assertions, but these are the most important:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;assertSame&lt;/code&gt; -&amp;gt; strict equality (&lt;code&gt;===&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;assertInstanceOf&lt;/code&gt; -&amp;gt; validates two objects or interfaces&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;More details: &lt;a href="https://docs.phpunit.de/en/10.5/assertions.html" rel="noopener noreferrer"&gt;PHPUnit Assertions Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;A common use case is expecting an exception, as shown in the test code:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;expectException&lt;/code&gt; -&amp;gt; used to test exceptions&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Skipping and Data Providers
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;markTestIncomplete&lt;/code&gt; / &lt;code&gt;markTestSkipped&lt;/code&gt; -&amp;gt; marks the test as incomplete/skipped so it doesn’t count as failed.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;#[DataProvider('sumProvider')]&lt;/code&gt; -&amp;gt; Uses the return of a function as test data.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Now, copy and run the updated test file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?php&lt;/span&gt;

&lt;span class="k"&gt;declare&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;strict_types&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kn"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;App\Tests\Unit\Service&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;App\Service\CalculatorService&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PHPUnit\Framework\Attributes\DataProvider&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PHPUnit\Framework\Attributes\Test&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;use&lt;/span&gt; &lt;span class="nc"&gt;PHPUnit\Framework\TestCase&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CalculatorServiceTest&lt;/span&gt; &lt;span class="kd"&gt;extends&lt;/span&gt; &lt;span class="nc"&gt;TestCase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;sumProvider&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
        &lt;span class="k"&gt;yield&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;4&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="na"&gt;#[Test]&lt;/span&gt;
    &lt;span class="na"&gt;#[DataProvider('sumProvider')]&lt;/span&gt;
    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testSum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$y&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$expected&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CalculatorService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertSame&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;$service&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nv"&gt;$y&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nv"&gt;$expected&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="na"&gt;#[Test]&lt;/span&gt;
    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testDivision&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CalculatorService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;assertEquals&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="nv"&gt;$service&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;division&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="mi"&gt;1&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="na"&gt;#[Test]&lt;/span&gt;
    &lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;testDivisionException&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nv"&gt;$this&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;expectException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;\Exception&lt;/span&gt;&lt;span class="o"&gt;::&lt;/span&gt;&lt;span class="n"&gt;class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="nv"&gt;$service&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;CalculatorService&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="nv"&gt;$service&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="nf"&gt;division&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Run the tests, and you will get:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Firxz1tqgvg0nx7fyvhk9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Firxz1tqgvg0nx7fyvhk9.png" alt=" " width="684" height="122"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Next chapter: Mocks and Stubs with more tips to finish on a high note!&lt;/p&gt;

&lt;p&gt;Recommended reading: &lt;a href="https://docs.phpunit.de/en/12.0/attributes.html" rel="noopener noreferrer"&gt;PHPUnit Attributes Documentation&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Github repository: &lt;a href="https://github.com/RazielRodrigues/php-unit-tests" rel="noopener noreferrer"&gt;Leave a star!&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;What do you think was this useful ? Leave a comment!&lt;/p&gt;

</description>
      <category>php</category>
      <category>programming</category>
      <category>testing</category>
      <category>phpunit</category>
    </item>
    <item>
      <title>I know why I love programming again 🗯️</title>
      <dc:creator>Raziel Rodrigues</dc:creator>
      <pubDate>Wed, 05 Feb 2025 15:10:39 +0000</pubDate>
      <link>https://forem.com/razielrodrigues/i-know-why-i-love-programming-again-49fg</link>
      <guid>https://forem.com/razielrodrigues/i-know-why-i-love-programming-again-49fg</guid>
      <description>&lt;p&gt;What makes you like being a programmer? Have you ever asked yourself that? Well, in my case...&lt;/p&gt;

&lt;p&gt;The other day, I was wondering why I wanted to keep going in this profession, after all, I was going through the famous impostor syndrome, which is normal when you're a software developer. With that, I reflected on it myself, and the answer came in a very simple way: while I'm writing code, I FORGET about my personal problems, family issues, and all the other bad things this world has.&lt;/p&gt;

&lt;p&gt;Many people get into programming for the money. I did too, and I won't lie about it. However, in my case, I started programming because of video games, I wanted to understand how they work. Because when I play video games, I feel the same effect as when I program: I disconnect from everything. This brought me the reason why I program. It's simple: I enjoy it, I have fun, and I feel that every time I don't finish a piece of code, I'm still stuck on a level in a game, and I need to pass that level to move forward.&lt;/p&gt;

&lt;p&gt;You see, no matter how many levels you pass in this game of development, there are always new levels, and these levels are the new technologies, the new trends in the market, and many other variables. But just like in a game, I can't let myself be discouraged I need to take a deep breath and keep moving forward. And if I can't pass a level, I need to improve, level up, and there's absolutely no shame in that.&lt;/p&gt;

&lt;p&gt;That's why I keep evolving. I still don't know, I need to defeat more "mobs" to reach my next level in this journey. Remembering that coding is more than just making money it's my hobby and my refuge from this world full of problems brought me immense peace. Now I know what to think about when I start feeling the same way again.&lt;/p&gt;

</description>
      <category>php</category>
      <category>webdev</category>
      <category>career</category>
      <category>programming</category>
    </item>
  </channel>
</rss>
