Friday, 18 October 2024

Guide for Markdown language

Here’s a hands-on guide showing you how to use Markdown with examples of all the key features:


1. Headings

You can create headings by using # symbols. More # means a smaller heading.

# Heading 1 ## Heading 2 ### Heading 3 #### Heading 4

Result:

Heading 1

Heading 2

Heading 3

Heading 4


2. Bold and Italics

You can format text in bold, italic, or bold and italic.

**Bold Text** *Italic Text* ***Bold and Italic Text***

Result:

  • Bold Text
  • Italic Text
  • Bold and Italic Text

3. Lists

Unordered List:

Use -, *, or + to create bullet points.

- Item 1 * Item 2 + Item 3

Ordered List:

Use numbers followed by a period.

1. First 2. Second 3. Third

Result:

  • Item 1
  • Item 2
  • Item 3
  1. First
  2. Second
  3. Third

4. Links

Create a link using [Link Text](URL).

[Visit GitHub](https://github.com)

Result: Visit GitHub


5. Images

Insert an image using ![Alt Text](Image URL).

![GitHub Logo](https://github.githubassets.com/images/modules/logos_page/GitHub-Mark.png)

Result:


6. Blockquotes

Use > to create a blockquote.

> This is a blockquote.

Result:

This is a blockquote.


7. Code Blocks

You can insert inline code using backticks (`) or block code using triple backticks (```).

Inline `code` example.

For code blocks:

```python def hello_world(): print("Hello, World!")
**Result:** Inline `code` example. ```python def hello_world(): print("Hello, World!")

8. Horizontal Line

Use ---, ***, or ___ to create a horizontal rule.

---

Result:



9. Task Lists

You can create task lists with - [ ] for incomplete and - [x] for completed tasks.

- [ ] Task 1 - [x] Task 2

Result:

  • Task 1
  • Task 2

10. Tables

Use pipes (|) and dashes (-) to create tables.

| Column 1 | Column 2 | Column 3 | | -------- | -------- | -------- | | Item 1 | Item 2 | Item 3 |

Result:

Column 1Column 2Column 3
Item 1Item 2Item 3

11. Strikethrough

Strike through text using ~~.

~~This text is struck through~~

Result:

This text is struck through


12. Footnotes

Create footnotes with [^1] for reference and [^1]: text for the actual footnote.

This is a footnote reference[^1]. [^1]: This is the footnote text.

Result: This is a footnote reference1.


13. Escaping Characters

Use a backslash (\) to escape Markdown special characters like #, *, or _.

\# Not a heading \*Not italic\*

Result:

# Not a heading
*Not italic*

Guide use Botble

 

References
-
https://docs.botble.com/cms/filters.html

Thank you.

Wednesday, 16 October 2024

Optimize using memory in php with Generators

In PHP, a generator provides a memory-efficient way to handle large datasets or streams of data by producing values one at a time, rather than loading everything into memory at once. This can significantly reduce memory usage when working with large datasets, as it avoids the need to store the entire dataset in memory.

Key Concepts:

  1. Standard Iteration (Without Generators):

    • When using a regular function that returns a large dataset, PHP loads the entire dataset into memory at once, which can consume a lot of memory, especially for large collections of data.
  2. Generators:

    • A generator allows you to iterate over a sequence of values without having to create and store the entire sequence in memory. It works by "yielding" values one at a time.
    • Instead of returning a full array, the yield keyword returns one value at a time during each iteration.

Example:

Here's how a generator works in PHP compared to regular iteration:

Without a Generator (High Memory Usage):

function largeDataset() { $data = []; foreach (/* large data source */ as $item) { $data[] = $item; } return $data; } foreach (largeDataset() as $data) { process($data); }
  • This function returns the entire dataset as an array.
  • The entire array must be stored in memory, which can be problematic for large datasets, causing high memory usage.

With a Generator (Memory Efficient):

function largeDataset() { foreach (/* large data source */ as $data) { yield $data; // Yield returns one value at a time } } foreach (largeDataset() as $data) { process($data); }
  • The yield keyword in this function produces one value at a time.
  • Instead of returning a complete array, the generator produces values lazily, meaning it only generates the next value when needed.
  • This avoids loading the entire dataset into memory at once.

How Generators Work:

  • When you call a generator function, it doesn't execute immediately. Instead, it returns an object of type Generator.
  • Each time you iterate over the generator (using foreach or similar), PHP resumes execution of the generator from where it left off, until it hits the next yield.
  • The generator pauses and saves its state after each yield, allowing you to continue later without reloading all the data.

Benefits of Using Generators:

  1. Memory Efficiency: Since only one value is stored in memory at a time, this greatly reduces the memory footprint.
  2. Improved Performance: In cases where you don't need to process the entire dataset at once, generators improve performance by handling one piece of data at a time.
  3. Streaming Large Data: Generators are useful for working with large files or database queries where you can process data in chunks, instead of loading everything into memory.

Example of a Real Use Case:

Imagine you are processing a large CSV file:

function readLargeCsv($filename) { $handle = fopen($filename, 'r'); while (($row = fgetcsv($handle)) !== false) { yield $row; // Yield each row from the CSV } fclose($handle); } foreach (readLargeCsv('hugefile.csv') as $row) { process($row); // Process each row one by one without loading the entire file into memory }
  • In this case, only one row of the CSV file is in memory at any given time, even if the file contains millions of rows. This prevents memory exhaustion and allows you to process very large files efficiently.

Conclusion:

Using generators in PHP is an excellent technique to optimize memory usage and improve performance, particularly when dealing with large datasets. The key advantage is that you only work with one piece of data at a time, which allows you to process large data sources without overwhelming system resources.

Thank you

Tuesday, 15 October 2024

FileTrackingServiceProvider for Laravel

 FileTrackingServiceProvider

<?php

namespace App\Providers;

use Illuminate\Support\Facades\Log;
use Illuminate\Support\ServiceProvider;
use Laravel\Telescope\Telescope;

class FileTrackingServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     */
    public function register(): void
    {
        //
    }

    /**
     * Bootstrap services.
     */
    public function boot(): void
    {
       // Listen to each request
        $this->app['router']->matched(function () {
            // Get all included files
            $includedFiles = get_included_files();

            // Filter out files in the vendor directory
            $phpBladeFiles = array_filter($includedFiles, function ($file) {
                return preg_match('/\.(php|blade\.php)$/', $file) &&
                    strpos($file, 'Shofy\vendor') === false;  // Exclude vendor files
            });

            // Log these files using Laravel Log
            foreach ($phpBladeFiles as $file) {
                Log::info("Non-vendor file included: $file");
            }
        });
    }
}


Fix the 413 Request Entity Too Large error in Laravel running on Nginx

1. Increase client_max_body_size in Nginx

The client_max_body_size directive in Nginx controls the maximum allowed size of the client request body, which includes uploaded files.

Steps:

  • Open your Nginx configuration file. This could be located at /etc/nginx/nginx.conf or in a site-specific configuration file under /etc/nginx/sites-available/.
sudo nano /etc/nginx/nginx.conf
  • Add or update the client_max_body_size directive inside the http block (or inside server or location blocks, if you prefer):
http { client_max_body_size 100M; }
$ sudo service nginx reload
 

2. Increase post_max_size and upload_max_filesize in PHP

Nginx will pass the request to PHP, and PHP has its own limits. You need to increase the upload_max_filesize and post_max_size in your php.ini file.

Steps:

  • Find your php.ini file. It is usually located in /etc/php/7.x/fpm/php.ini (on Linux) or C:\xampp\php\php.ini (on Windows).

  • Open the file and increase the following values:

upload_max_filesize = 100M post_max_size = 100M
 
Thank you

Sunday, 13 October 2024

Compare Aimeos and Bagisto

FeatureAimeosBagisto
PerformanceHigh performance, optimized for large-scaleModerate, suitable for SMBs
Multi-VendorAdvanced multi-vendor supportBasic multi-vendor functionality
Clean CodeComplex but modular, highly customizableLaravel-friendly, clean, easier for smaller projects
FeaturesFeature-rich, subscription, B2B/B2C, multi-storeSimpler, essential features, extendable via plugins
ScalabilityEnterprise-level scalabilityGood for small to mid-sized businesses
CommunitySmaller but mature ecosystemGrowing community, lots of support

Conclusion

  • Aimeos is the best choice for large-scale e-commerce platforms or businesses that require a high degree of customization, performance, and scalability. It’s ideal for complex multi-vendor marketplaces or companies with advanced e-commerce needs.

  • Bagisto is more suitable for small to medium businesses looking for a quick and efficient e-commerce solution with multi-vendor support. Its simplicity and Laravel-friendly codebase make it a great starting point for developers who want to get a store up and running quickly without needing the complexity of Aimeos.

Thank you.

Wednesday, 9 October 2024

Optimize a Laravel application for performance

Optimizing a Laravel application for performance is crucial for ensuring that your application can handle high traffic, respond quickly, and use server resources efficiently. Here are some strategies and techniques to boost Laravel application performance:

1. Caching:

Laravel provides several types of caching that can significantly reduce the load on your server and speed up response times.

  • Route Caching: Speeds up route resolution by caching the routes to avoid re-parsing them on each request.
    php artisan route:cache
  • Config Caching: Loads configuration files faster by caching them.
    php artisan config:cache
  • View Caching: Caches Blade views to avoid recompiling them for every request.
    php artisan view:cache
  • Query Caching: Caches database query results to avoid repeated expensive queries.
    $users = User::remember(60)->get(); // Caches for 60 minutes

2. Optimize Database Queries:

Efficient database interaction can significantly reduce the load time of your application.

  • Use Eager Loading: Instead of loading related models one by one, use eager loading to load all relationships at once, reducing the number of queries.
    // Without eager loading (N+1 problem) $users = User::all(); foreach ($users as $user) { echo $user->profile->bio; } // With eager loading $users = User::with('profile')->get();
  • Database Indexing: Add appropriate indexes to database tables, especially for columns used in WHERE, JOIN, and ORDER BY clauses.
  • Use SELECT with specific columns: Only select the fields you need instead of retrieving all fields.
    $users = User::select('id', 'name')->get();
  • Batch Inserts and Updates: Use batch operations to reduce the number of database hits.
    DB::table('users')->insert([ ['name' => 'John', 'email' => 'john@example.com'], ['name' => 'Jane', 'email' => 'jane@example.com'] ]);

3. Use Queues for Time-Consuming Tasks:

Offload tasks like sending emails, resizing images, and other resource-intensive operations to queues. This frees up your application to handle more requests quickly.

ProcessImageJob::dispatch($image);

4. Optimize Middleware:

  • Reduce Middleware: Only apply middleware where necessary using only or except methods in your controllers or route definitions.
    Route::get('profile', 'ProfileController@show')->middleware('auth');
  • Use Route Grouping: Group routes that use the same middleware to avoid reapplying middleware individually.

5. Leverage HTTP Caching:

Utilize browser caching and response headers to reduce the amount of data transmitted to clients.

  • Set Cache-Control headers: Use Laravel’s Cache facade to set cache headers for static content.
    return response($content) ->header('Cache-Control', 'public, max-age=3600');
  • Use Content Delivery Networks (CDNs): Offload serving static assets (e.g., CSS, JavaScript, images) to CDNs, reducing server load and speeding up delivery.

6. Optimize Assets:

  • Minify CSS/JavaScript: Use tools like Laravel Mix or npm scripts to minify CSS and JavaScript files to reduce their size.
    npm run production
  • Defer JavaScript Loading: Use defer or async attributes on <script> tags to prevent JavaScript from blocking the rendering of the page.
  • Use Gzip Compression: Enable Gzip compression on your web server to compress HTML, CSS, and JS files sent to clients.

7. Use Redis for Session and Cache:

Redis is a fast, in-memory key-value store that can be used to store sessions, cache data, and even queues.

  • Sessions: Configure Laravel to use Redis for session management.
    SESSION_DRIVER=redis
  • Cache: Set Redis as your caching driver in the .env file.
    CACHE_DRIVER=redis

8. Database Optimization:

  • Use Pagination: Don’t load all records in one request; instead, paginate them.
    $users = User::paginate(10);
  • Database Connection Pooling: Use tools like pgbouncer (for PostgreSQL) to reduce overhead in creating new connections.

9. Optimize Blade Views:

  • Avoid Complex Logic in Views: Move complex logic to controllers or view composers instead of keeping it in Blade files.
  • Use View Composers: Share data with multiple views using view composers.
    View::composer('profile', function ($view) { $view->with('user', Auth::user()); });

10. Enable OPcache:

OPcache is a caching engine that caches PHP bytecode in memory, improving performance by eliminating the need for PHP to compile scripts on each request.

  • Enable OPcache in your PHP configuration (php.ini).
    opcache.enable=1

11. Lazy Collection for Large Datasets:

When working with large datasets, you can use Laravel's LazyCollection to handle data without loading everything into memory at once.

$users = User::lazy(); foreach ($users as $user) { // Process user... }

12. Use Optimized Composer Autoloading:

Use optimized autoloading in Composer to improve performance by avoiding unnecessary class loading.

composer install --optimize-autoloader --no-dev

13. Optimize Images:

Compress and optimize images to reduce their size and loading times. Tools like spatie/laravel-image-optimizer can help automate this process.


By combining these techniques, you can significantly boost the performance of your Laravel application.

Thank you.

Tuesday, 8 October 2024

Common pitfalls when using Eloquent

  1. N+1 Query Problem:

    • What it is: The N+1 problem occurs when Eloquent loads related data in a loop, leading to multiple unnecessary queries. For example, if you retrieve 10 users and then fetch their posts in a loop, it could result in 11 queries (1 for users, 10 for posts).
      // This will cause N+1 problem $users = User::all(); foreach ($users as $user) { $posts = $user->posts; }
    • Solution: Use eager loading with the with() method to load relationships in a single query.
      $users = User::with('posts')->get(); // Loads users and their posts in 2 queries
  2. Inefficient Queries:

    • What it is: Eloquent’s abstraction can sometimes hide inefficient queries. For example, using all() to retrieve large datasets or forgetting to limit the number of records can result in performance issues.
      // This will retrieve all users, which could be thousands $users = User::all();
    • Solution: Always use limit() or pagination (paginate()) when working with large datasets.
      $users = User::paginate(15); // Retrieves 15 users per page
  3. Overuse of Eloquent Methods:

    • What it is: Overusing Eloquent’s methods for complex or bulk operations can degrade performance. For example, updating thousands of records using Eloquent will create an individual UPDATE query for each record.
      // This will run one query per user foreach ($users as $user) { $user->active = 1; $user->save(); }
    • Solution: For bulk updates or inserts, it’s more efficient to use raw queries or Laravel’s Query Builder.
      // Use Query Builder for bulk updates DB::table('users')->update(['active' => 1]);
  4. Memory Consumption:

    • What it is: Using all() or large datasets in-memory can consume significant memory, especially in long-running processes like migrations or imports.
    • Solution: Use chunking to process large datasets in smaller portions, reducing memory usage.
      User::chunk(100, function($users) { foreach ($users as $user) { // Process user } });
  5. Failing to Handle Database Transactions:

    • What it is: When performing operations that involve multiple queries (e.g., creating a user and associated posts), not using database transactions can lead to data inconsistency if something goes wrong midway.
    • Solution: Use database transactions to ensure atomicity (all-or-nothing behavior).
      DB::transaction(function() { $user = User::create([...]); $user->posts()->create([...]); });

Conclusion

Eloquent simplifies working with databases by providing a clean, object-oriented interface. However, it can abstract away important details about performance and query efficiency. Developers need to be mindful of common pitfalls like the N+1 problem, inefficient queries, and memory management, especially when working with large datasets or complex relationships.

Thank you

Sunday, 6 October 2024

Explain Laravel's service container and dependency injection

Imagine we have two classes:

  1. A Superhero (a toy).
  2. A Cape (an extra part the superhero needs to fly).

Step-by-Step Breakdown

  1. Superhero Class (Needs a Cape):

    class Superhero { protected $cape; // Superhero needs a Cape to fly public function __construct(Cape $cape) { $this->cape = $cape; } public function fly() { return "Flying with a " . $this->cape->type(); } }
  2. Cape Class (The Extra Part):

    class Cape { public function type() { return 'red cape!'; } }

Bind Superhero and Cape in the service provider

<?php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class ToyStoreServiceProvider extends ServiceProvider
{
    /**
     * Register services.
     *
     * @return void
     */
    public function register()
    {
        // Binding Cape class
        $this->app->bind(Cape::class, function () {
            return new Cape();
        });

        // Binding Superhero class, which depends on Cape
        $this->app->bind(Superhero::class, function ($app) {
            return new Superhero($app->make(Cape::class));
        });
    }

    /**
     * Bootstrap services.
     *
     * @return void
     */
    public function boot()
    {
        // Any bootstrapping code can go here
    }
}


Resolving the Classes

Now, when you resolve the Superhero, Laravel will automatically create the Cape instance since you’re creating it directly in the closure of the Superhero binding:

$superhero = app(Superhero::class); echo $superhero->fly(); // Output: "Flying with a red cape!"

Thank you

Open-source solution for OCR (Optical Character Recognition)

1. Tesseract OCR

  • License: Apache 2.0 (Open-source)
  • Description: Tesseract is one of the most widely-used open-source OCR engines. It is highly reliable and supports many languages. You can train it for specific use cases, which can be useful for specialized motorcycle-related texts, part numbers, and more.
  • Best For: General-purpose OCR, multilingual text extraction.
  • Integration: It can be integrated with various programming languages like Python, PHP, and Node.js, making it flexible.
  • Repository: Tesseract GitHub

2. EasyOCR

  • License: Apache 2.0 (Open-source)
  • Description: EasyOCR is a lightweight and fast OCR library that supports over 80 languages. It’s easy to set up, uses deep learning, and can handle complex scripts and multilingual text extraction, making it ideal for a global audience.
  • Best For: Multilingual OCR, ease of integration, and using GPUs for faster processing.
  • Integration: Works with Python and can be integrated into larger machine learning pipelines or standalone applications.
  • Repository: EasyOCR GitHub

3. PaddleOCR

  • License: Apache 2.0 (Open-source)
  • Description: PaddleOCR is part of the PaddlePaddle ecosystem, offering strong support for over 80 languages and delivering high accuracy. It is particularly suitable for complex document layouts and multilingual scenarios.
  • Best For: High accuracy in OCR, complex layouts, and global language support.
  • Integration: Works in Python and is based on the PaddlePaddle deep learning framework.
  • Repository: PaddleOCR GitHub

4. OpenCV (with Tesseract)

  • License: BSD 3-Clause (Open-source)
  • Description: OpenCV includes support for OCR via Tesseract. It’s highly useful when combining text recognition with other computer vision tasks, like detecting objects or motorcycles before performing OCR.
  • Best For: Combining OCR with image processing tasks, preprocessing images for better text recognition.
  • Integration: Works with multiple languages such as Python, C++, and Java. It can be used with Tesseract for OCR tasks.
  • Repository: OpenCV GitHub

Recommendation

If you're looking for an open-source solution, Tesseract or EasyOCR would be the most straightforward and well-supported choices. Both offer excellent language support, flexibility, and ease of integration into your ecommerce platform. If your application involves more complex document layouts or multilingual needs, you might consider PaddleOCR for its enhanced capabilities.

Thank you.

Thursday, 3 October 2024

Isset(), empty(), and checking a variable for true behave in PHP

Key Differences:

Variable Stateisset()empty()$var == true
Unset/undefinedfalse (Notice)true (No Notice)Notice/Error
nullfalsetruefalse
"" (empty string)truetruefalse
falsetruetruefalse
0truetruefalse
1truefalsetrue
"0" (string "0")truetruefalse
truetruefalsetrue
Non-empty string "abc"true            falsetrue        
[]true            truefalse

 

 Thank you

Tuesday, 1 October 2024

List of keys you can use in a Symfony services.yaml

Here’s a comprehensive list of keys you can use in a Symfony services.yaml file, along with brief descriptions for each:

1. Global Configuration Keys

  • parameters: Defines reusable parameters throughout the service definitions.

2. Service Definitions Keys

  • services: Main section where you define services.

Service Configuration Keys

  • class: The class name of the service being defined (if using the shorthand syntax).
  • arguments: Dependencies passed to the service constructor.
  • tags: Metadata tags for the service (e.g., event listeners, commands).
  • factory: Specifies a factory method to create the service.
  • decorates: Replaces a service with a decorated version.
  • bind: Specifies parameters for specific arguments in the constructor.
  • autowire: Automatically injects dependencies into services.
  • autoconfigure: Automatically configures services based on their interfaces or parent classes.

3. Parameter Configuration Keys

  • default_logger: Example of a parameter that can hold configuration values.
  • log_file: Default log file location or similar configuration values.

4. Service-Specific Configuration Keys

  • public: Determines whether the service can be accessed from outside the service container (default is true in Symfony 4.0 and later).
  • shared: Indicates if the service is a singleton (default is true).

5. Service Factory Configuration Keys

  • factory: Specifies the method that should be called to instantiate the service.

6. Service Alias Configuration Keys

  • aliases: Allows you to create aliases for services, enabling you to refer to a service by a different name.

7. Tags Configuration Keys

  • name: The name of the tag.
  • priority: Sets the priority of the tag, determining the order in which tagged services are processed.
  • attributes: Custom attributes that can be added to tags.

8. Additional Keys for Configuration

  • calls: Specifies methods that should be called on the service after it is constructed.
  • factory: Specifies a method that should be called to create the service.
  • deprecated: Marks a service as deprecated.
  • class: Defines the class name of the service being defined (if using shorthand syntax).

Example services.yaml with All Keys

Here’s a fictive example of how these keys can be used in a services.yaml file:

parameters: default_logger: '%env(APP_DEFAULT_LOGGER)%' log_file: 'app.log' services: App\Service\Logger\LoggerInterface: '@=service(parameter("default_logger"))' App\Service\Logger\DatabaseLogger: class: App\Service\Logger\DatabaseLogger arguments: $entityManager: '@doctrine.orm.entity_manager' tags: - { name: 'logger' } App\Service\Logger\FileLogger: class: App\Service\Logger\FileLogger arguments: $logFile: '%log_file%' public: false # Example of service visibility App\Service\UserService: autowire: true autoconfigure: true arguments: $logger: '@=service(parameter("default_logger"))' App\EventListener\SomeEventListener: tags: - { name: 'kernel.event_listener', event: 'kernel.request', method: 'onKernelRequest' } App\Service\SomeService: decorates: 'original.service.id' factory: ['@some.factory.service', 'create']

Summary of Keys

  • Global Keys: parameters
  • Service Keys: services, class, arguments, tags, factory, decorates, bind, autowire, autoconfigure, public, shared, aliases, calls, deprecated

This list and the example configuration should provide you with a comprehensive overview of the configuration keys available in Symfony's service container. If you need any further details or examples, feel free to ask!

Manage multiple types of logs in Symfony

Here’s the complete implementation that allows you to select a logger dynamically based on the APP_LOGGER_TYPE environment variable. This includes the logger interface, logger implementations, user service, user controller, and the service configuration in services.yaml.

1. Logger Interface

File: src/Service/Logger/LoggerInterface.php

namespace App\Service\Logger; interface LoggerInterface { public function log(string $message): void; }

2. File Logger Implementation

File: src/Service/Logger/FileLogger.php

namespace App\Service\Logger; class FileLogger implements LoggerInterface { private string $logFile; public function __construct(string $logFile = 'app.log') { $this->logFile = $logFile; } public function log(string $message): void { file_put_contents($this->logFile, $message . PHP_EOL, FILE_APPEND); } }

3. Database Logger Implementation

File: src/Service/Logger/DatabaseLogger.php

namespace App\Service\Logger; use Doctrine\ORM\EntityManagerInterface; use App\Entity\LogEntry; class DatabaseLogger implements LoggerInterface { private EntityManagerInterface $entityManager; public function __construct(EntityManagerInterface $entityManager) { $this->entityManager = $entityManager; } public function log(string $message): void { $logEntry = new LogEntry(); $logEntry->setMessage($message); $logEntry->setCreatedAt(new \DateTime()); $this->entityManager->persist($logEntry); $this->entityManager->flush(); } }

4. Email Logger Implementation (Optional)

File: src/Service/Logger/EmailLogger.php

namespace App\Service\Logger; class EmailLogger implements LoggerInterface { public function log(string $message): void { // Implement email logging logic here // e.g., sending an email with the log message mail('admin@example.com', 'Log Entry', $message); } }

5. User Service

File: src/Service/UserService.php

namespace App\Service; use App\Service\Logger\LoggerInterface; class UserService { private LoggerInterface $logger; public function __construct(LoggerInterface $logger) { $this->logger = $logger; } public function createUser(string $username): void { $this->logger->log("User $username created."); } }

6. User Controller

File: src/Controller/UserController.php

namespace App\Controller; use App\Service\UserService; use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; use Symfony\Component\HttpFoundation\Response; class UserController extends AbstractController { private UserService $userService; public function __construct(UserService $userService) { $this->userService = $userService; } public function create(): Response { $this->userService->createUser('JohnDoe'); // Uses the injected logger return new Response('User created and logged.'); } }

7. Entity Class for Log Entry (Optional)

File: src/Entity/LogEntry.php

namespace App\Entity; use Doctrine\ORM\Mapping as ORM; /** * @ORM\Entity() */ class LogEntry { /** * @ORM\Id * @ORM\GeneratedValue * @ORM\Column(type="integer") */ private int $id; /** * @ORM\Column(type="string") */ private string $message; /** * @ORM\Column(type="datetime") */ private \DateTime $createdAt; public function setMessage(string $message): void { $this->message = $message; } public function setCreatedAt(\DateTime $createdAt): void { $this->createdAt = $createdAt; } }

8. Configure Services in services.yaml

File: config/services.yaml

parameters: log_file: 'app.log' # Default log file location services: # Conditional service based on APP_LOGGER_TYPE App\Service\Logger\LoggerInterface: '@=service("App\Service\Logger\\" . ucfirst(getenv("APP_LOGGER_TYPE")) . "Logger")' App\Service\Logger\DatabaseLogger: arguments: $entityManager: '@doctrine.orm.entity_manager' App\Service\Logger\FileLogger: arguments: $logFile: '%log_file%' # Use the default log file from parameters App\Service\Logger\EmailLogger: ~ # Add EmailLogger service if necessary App\Service\UserService: arguments: $logger: '@=service("App\Service\Logger\\" . ucfirst(getenv("APP_LOGGER_TYPE")) . "Logger")'

9. Update Your .env File

Set the desired default logger in your .env file:

File: .env

APP_LOGGER_TYPE=file # or database, or email

Summary

With this setup:

  • You can easily switch between different logging mechanisms by simply changing the value of APP_LOGGER_TYPE in your .env file.
  • The services.yaml configuration dynamically selects the appropriate logger implementation based on the environment variable, enabling you to use different logging strategies without modifying the service or application logic.

Golang Advanced Interview Q&A