PHP code example of cmatosbc / desired-patterns

1. Go to this page and download the library: Download cmatosbc/desired-patterns library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

cmatosbc / desired-patterns example snippets


use DesiredPatterns\Traits\Singleton;

class Database
{
    use Singleton;

    private function __construct()
    {
        // Initialize database connection
    }

    public function query(string $sql): array
    {
        // Execute query
    }
}

// Usage
$db = Database::getInstance();

use DesiredPatterns\Traits\Multiton;

class Configuration
{
    use Multiton;

    private string $environment;

    private function __construct(string $environment)
    {
        $this->environment = $environment;
    }

    public function getEnvironment(): string
    {
        return $this->environment;
    }
}

// Usage
$devConfig = Configuration::getInstance('development');
$prodConfig = Configuration::getInstance('production');

// Check if instance exists
if (Configuration::hasInstance('testing')) {
    // ...
}

use DesiredPatterns\Commands\AbstractCommand;
use DesiredPatterns\Commands\AbstractCommandHandler;

// Command
class CreateUserCommand extends AbstractCommand
{
    public function __construct(
        public readonly string $name,
        public readonly string $email
    ) {}
}

// Handler
class CreateUserHandler extends AbstractCommandHandler
{
    public function handle(CreateUserCommand $command): void
    {
        // Create user logic here
    }

    public function supports(object $command): bool
    {
        return $command instanceof CreateUserCommand;
    }
}

// Usage
$command = new CreateUserCommand('John Doe', '[email protected]');
$handler = new CreateUserHandler();
$handler->handle($command);

use DesiredPatterns\Chain\AbstractHandler;

// Create concrete handlers
class PayPalHandler extends AbstractHandler
{
    public function handle($request)
    {
        if ($request['type'] === 'paypal') {
            return [
                'status' => 'success',
                'message' => 'Payment processed via PayPal'
            ];
        }
        
        return parent::handle($request);
    }
}

class CreditCardHandler extends AbstractHandler
{
    public function handle($request)
    {
        if ($request['type'] === 'credit_card') {
            return [
                'status' => 'success',
                'message' => 'Payment processed via credit card'
            ];
        }
        
        return parent::handle($request);
    }
}

// Usage
$paypalHandler = new PayPalHandler();
$creditCardHandler = new CreditCardHandler();

// Build the chain
$paypalHandler->setNext($creditCardHandler);

// Process payment
$result = $paypalHandler->handle([
    'type' => 'credit_card',
    'amount' => 100.00
]);

use DesiredPatterns\Registry\Registry;

// Store a value
Registry::set('config.database', [
    'host' => 'localhost',
    'name' => 'myapp'
]);

// Retrieve a value
$dbConfig = Registry::get('config.database');

// Check if key exists
if (Registry::has('config.database')) {
    // ...
}

// Remove a key
Registry::remove('config.database');

// Get all keys
$keys = Registry::keys();

use DesiredPatterns\ServiceLocator\ServiceLocator;

class DatabaseService
{
    public function connect(): void
    {
        // Connection logic
    }
}

// Create a service locator
$locator = new ServiceLocator();

// Register a service
$locator->register('database', fn() => new DatabaseService());

// Resolve the service
$db = $locator->resolve('database');

// Check if service exists
if ($locator->has('database')) {
    // ...
}

// Extend an existing service
$locator->extend('database', function($service) {
    // Modify or decorate the service
    return $service;
});

use DesiredPatterns\Specifications\AbstractSpecification;
use DesiredPatterns\Specifications\Composite\{AndSpecification, OrSpecification, NotSpecification};

// Create specifications
class AgeSpecification extends AbstractSpecification
{
    public function __construct(private int $minAge) {}

    public function isSatisfiedBy(mixed $candidate): bool
    {
        return $candidate->age >= $this->minAge;
    }
}

class VerifiedSpecification extends AbstractSpecification
{
    public function isSatisfiedBy(mixed $candidate): bool
    {
        return $candidate->isVerified;
    }
}

// Usage
$isAdult = new AgeSpecification(18);
$isVerified = new VerifiedSpecification();

// Combine specifications
$canAccessContent = $isAdult->and($isVerified);

// Check if specifications are met
$user = new stdClass();
$user->age = 25;
$user->isVerified = true;

if ($canAccessContent->isSatisfiedBy($user)) {
    // Allow access
}


namespace Examples\Strategy\Payment;

use DesiredPatterns\Strategy\AbstractStrategy;
use DesiredPatterns\Traits\ConfigurableStrategyTrait;

/**
 * Credit Card Payment Strategy
 */
class CreditCardStrategy extends AbstractStrategy
{
    use ConfigurableStrategyTrait;

    protected array $a['expiry'])
            && isset($data['cvv']);
    }

    public function execute(array $data): array
    {
        // Process credit card payment
        return [
            'status' => 'success',
            'transaction_id' => uniqid('cc_'),
            'method' => 'credit_card',
            'amount' => $data['amount']
        ];
    }
}

/**
 * PayPal Payment Strategy
 */
class PayPalStrategy extends AbstractStrategy
{
    use ConfigurableStrategyTrait;

    protected array $   public function supports(array $data): bool
    {
        return isset($data['payment_method']) 
            && $data['payment_method'] === 'crypto';
    }

    public function validate(array $data): bool
    {
        return isset($data['crypto_address']) 
            && isset($data['crypto_currency']);
    }

    public function execute(array $data): array
    {
        // Process crypto payment
        return [
            'status' => 'success',
            'transaction_id' => uniqid('crypto_'),
            'method' => 'crypto',
            'amount' => $data['amount'],
            'currency' => $data['crypto_currency']
        ];
    }
}

// Usage Example
$context = new StrategyContext();

// Configure payment strategies
$context->addStrategy(
    new CreditCardStrategy(),
    ['api_key' => 'sk_test_123']
)
->addStrategy(
    new PayPalStrategy(),
    [
        'client_id' => 'client_123',
        'client_secret' => 'secret_456'
    ]
)
->addStrategy(
    new CryptoStrategy(),
    ['wallet_address' => '0x123...']
);

// Process a credit card payment
$ccPayment = $context->executeStrategy([
    'payment_method' => 'credit_card',
    'amount' => 99.99,
    'card_number' => '4242424242424242',
    'expiry' => '12/25',
    'cvv' => '123'
]);

// Process a PayPal payment
$ppPayment = $context->executeStrategy([
    'payment_method' => 'paypal',
    'amount' => 149.99,
    'paypal_email' => '[email protected]'
]);

// Process a crypto payment
$cryptoPayment = $context->executeStrategy([
    'payment_method' => 'crypto',
    'amount' => 199.99,
    'crypto_address' => '0x456...',
    'crypto_currency' => 'ETH'
]);

use DesiredPatterns\State\StateMachineTrait;
use DesiredPatterns\State\AbstractState;

// Define your states
class PendingState extends AbstractState
{
    public function getName(): string
    {
        return 'pending';
    }

    protected array $allowedTransitions = ['processing', 'cancelled'];
    
    protected array $validationRules = [
        'order_id' => 'ruct(string $orderId)
    {
        // Initialize states
        $this->addState(new PendingState(), true)
            ->addState(new ProcessingState())
            ->addState(new ShippedState());

        // Set initial context
        $this->updateContext([
            'order_id' => $orderId,
            'created_at' => date('Y-m-d H:i:s')
        ]);
    }

    public function process(array $paymentDetails): array
    {
        $this->transitionTo('processing', $paymentDetails);
        return $this->getCurrentState()->handle($this->getContext());
    }
}

// Usage
$order = new Order('ORD-123');

try {
    $result = $order->process([
        'payment_id' => 'PAY-456',
        'amount' => 99.99
    ]);
    echo $result['message']; // "Payment verified, preparing shipment"
} catch (StateException $e) {
    echo "Error: " . $e->getMessage();
}

use DesiredPatterns\Pipeline\Pipeline;

// Basic pipeline
$result = Pipeline::of(5)
    ->pipe(fn($x) => $x * 2)    // 10
    ->pipe(fn($x) => $x + 1)    // 11
    ->get();                     // Returns: 11

// Pipeline with error handling
$result = Pipeline::of($value)
    ->try(
        fn($x) => processData($x),
        fn(\Throwable $e) => handleError($e)
    )
    ->get();

// Pipeline with validation
$result = Pipeline::of($data)
    ->when(
        fn($x) => $x > 0,
        fn($x) => sqrt($x)
    )
    ->get();

use DesiredPatterns\Pipeline\PipelineBuilder;

$builder = new PipelineBuilder();
$result = $builder
    ->withValidation(fn($x) => $x > 0, 'Value must be positive')
    ->withValidation(fn($x) => $x < 100, 'Value must be less than 100')
    ->withErrorHandling(fn(\Throwable $e) => handleValidationError($e))
    ->add(fn($x) => $x * 2)
    ->add(fn($x) => "Result: $x")
    ->build(50)
    ->get();

class UserDataProcessor
{
    private PipelineBuilder $pipeline;

    public function __construct()
    {
        $this->pipeline = new PipelineBuilder();
        $this->pipeline
            ->withValidation(
                fn($data) => isset($data['email']),
                'Email is rror' => $e->getMessage()
            ])
            ->add(function($data) {
                // Normalize email
                $data['email'] = strtolower($data['email']);
                return $data;
            })
            ->add(function($data) {
                // Hash password if present
                if (isset($data['password'])) {
                    $data['password'] = password_hash(
                        $data['password'],
                        PASSWORD_DEFAULT
                    );
                }
                return $data;
            })
            ->add(function($data) {
                // Add metadata
                $data['created_at'] = new DateTime();
                $data['status'] = 'active';
                return $data;
            });
    }

    public function process(array $userData): array
    {
        return $this->pipeline
            ->build($userData)
            ->get();
    }
}

// Usage
$processor = new UserDataProcessor();

// Successful case
$result = $processor->process([
    'email' => '[email protected]',
    'password' => 'secret123'
]);
// Returns: [
//     'email' => '[email protected]',
//     'password' => '$2y$10$...',
//     'created_at' => DateTime,
//     'status' => 'active'
// ]

// Error case
$result = $processor->process([
    'email' => 'invalid-email'
]);
// Returns: [
//     'success' => false,
//     'error' => 'Invalid email format'
// ]

use DesiredPatterns\Contracts\PoolableInterface;
use DesiredPatterns\Pool\ObjectPool;
use DesiredPatterns\Pool\PoolFactory;

// Define a poolable resource
class DatabaseConnection implements PoolableInterface
{
    private ?PDO $connection = null;
    
    public function __construct(
        private readonly string $dsn,
        private readonly string $username,
        private readonly string $password
    ) {}
    
    public function reset(): void
    {
        if ($this->connection) {
            $this->connection->setAttribute(PDO::ATTR_AUTOCOMMIT, true);
        }
    }
    
    public function validate(): bool
    {
        try {
            $this->connection?->query('SELECT 1');
            return true;
        } catch (PDOException) {
            $this->connection = null;
            return false;
        }
    }
}

// Use the pool
$pool = PoolFactory::getPool(
    'database',
    DatabaseConnection::class,
    [
        'min_instances' => 2,
        'max_instances' => 10,
        'constructor_args' => [
            'mysql:host=localhost;dbname=test',
            'username',
            'password'
        ]
    ]
);

// Acquire and use a connection
$connection = $pool->acquire();
try {
    // Use the connection
} finally {
    $pool->release($connection);
}

use DesiredPatterns\NullObject\NullableInterface;
use DesiredPatterns\NullObject\AbstractNullObject;

// Define the interface
interface LoggerInterface extends NullableInterface
{
    public function log(string $level, string $message, array $context = []): void;
    public function getLogs(): array;
}

// Real implementation
class FileLogger implements LoggerInterface
{
    public function __construct(
        private readonly string $logFile
    ) {}
    
    public function log(string $level, string $message, array $context = []): void
    {
        file_put_contents(
            $this->logFile,
            "[$level] $message " . json_encode($context) . PHP_EOL,
            FILE_APPEND
        );
    }
    
    public function getLogs(): array
    {
        return file($this->logFile);
    }
    
    public function isNull(): bool
    {
        return false;
    }
}

// Null implementation
class NullLogger extends AbstractNullObject implements LoggerInterface
{
    public function log(string $level, string $message, array $context = []): void
    {
        // Do nothing
    }
    
    public function getLogs(): array
    {
        return [];
    }
}

// Usage
class UserService
{
    public function __construct(
        private readonly LoggerInterface $logger = new NullLogger()
    ) {}
    
    public function createUser(string $username): void
    {
        // Create user...
        $this->logger->log('info', 'User created', ['username' => $username]);
    }
}