Introduction to Yabasi Framework

Yabasi is a powerful, flexible, and modern PHP framework designed for rapid application development. It combines the best practices of popular frameworks with innovative features to provide developers with a robust toolkit for building scalable and maintainable web applications.

Key Features

  • Elegant MVC Architecture
  • Powerful Routing System
  • Intuitive ORM with advanced database abstraction
  • Flexible Template Engine with Twig integration
  • Built-in Security Features including CSRF protection and XSS prevention
  • Dependency Injection Container for efficient service management
  • Event-driven architecture for extensibility
  • Command-line interface for automated tasks and migrations
  • Comprehensive caching system
  • RESTful API development tools
  • WebSocket support for real-time applications
  • Robust error handling and logging capabilities

Philosophy

Yabasi is built on the principles of simplicity, flexibility, and performance. It aims to provide developers with a clean and intuitive API while offering the power and features needed for complex applications. The framework encourages best practices in software design and promotes code reusability and maintainability.

Community and Ecosystem

Yabasi boasts a growing community of developers and a rich ecosystem of packages and extensions. The framework is open-source, encouraging collaboration and continuous improvement. Whether you're building a simple website or a complex enterprise application, Yabasi provides the tools and support you need to succeed.

Who is Yabasi For?

Yabasi is designed for developers of all skill levels:

  • Beginners will appreciate its clear documentation and gentle learning curve
  • Experienced developers will love its powerful features and flexibility
  • Teams will benefit from its emphasis on clean architecture and maintainable code

Getting Started

Ready to dive in? The next sections will guide you through installing Yabasi and creating your first application. Whether you're new to PHP frameworks or an experienced developer, you'll find Yabasi intuitive and powerful.

Getting Started with Yabasi

This section will guide you through the process of setting up your first Yabasi project. We'll cover installation, configuration, and creating a basic application.

System Requirements

Before installing Yabasi, ensure your system meets the following requirements:

  • PHP >= 8.1
  • Composer
  • PDO PHP Extension
  • OpenSSL PHP Extension
  • Mbstring PHP Extension
  • Tokenizer PHP Extension

Installation

Yabasi utilizes Composer for dependency management. To create a new Yabasi project, run the following command in your terminal:

composer create-project yabasi/yabasi your-project-name

This command will create a new Yabasi project in the `your-project-name` directory.

Configuration

After installation, you need to configure your application:

  1. Rename the `.env.example` file to `.env`
  2. Open the `.env` file and update the database credentials and other configuration options
  3. Generate an application key by running:
php yabasi key:generate

Directory Structure

Familiarize yourself with the Yabasi directory structure:

  • app/ - Contains the core code of your application
  • config/ - Houses all of your application's configuration files
  • public/ - The public directory contains the index.php file, which is the entry point for all requests
  • resources/ - Contains your views and raw, un-compiled assets
  • routes/ - Contains all of the route definitions for your application
  • storage/ - Contains compiled Twig templates, file based sessions, file caches and other files generated by the framework
  • tests/ - Contains your automated tests
  • vendor/ - Contains your Composer dependencies

Creating Your First Route

Let's create a simple route to test our installation. Open the `routes/web.php` file and add the following code:

routes/web.php
use Yabasi\Routing\Router;

$router->get('/', function() {
    return 'Hello, Yabasi!';
});

Running Your Application

You can use PHP's built-in server to run your application locally. Navigate to your project directory in the terminal and run:

php -S localhost:8000 -t public

Now, open your web browser and visit `http://localhost:8000`. You should see "Hello, Yabasi!" displayed.

Next Steps

Congratulations! You've successfully set up your first Yabasi application. From here, you can:

The following sections will guide you through these topics and more, helping you harness the full power of Yabasi framework.

Core Concepts

Yabasi Framework is built on several core concepts that form the foundation of its architecture and functionality. Understanding these concepts is crucial for effectively using the framework.

MVC Architecture

Yabasi follows the Model-View-Controller (MVC) architectural pattern:

  • Models: Represent your data structure and handle database interactions.
  • Views: Handle the presentation logic and render the user interface.
  • Controllers: Act as intermediaries between Models and Views, processing requests and managing application logic.

Dependency Injection

Yabasi uses a powerful Dependency Injection Container to manage class dependencies and perform dependency injection, promoting loose coupling and easier testing.

Service Providers

Service Providers are the central place of all Yabasi application bootstrapping. They allow you to register services, event listeners, middleware, and even routes within your application.

Middleware

Middleware provide a convenient mechanism for filtering HTTP requests entering your application, allowing you to perform actions before a request reaches your route or controller.

ORM (Object-Relational Mapping)

Yabasi includes a powerful ORM that makes it easy to interact with your database using eloquent, intuitive syntax, without writing raw SQL queries.

Event System

The event system allows you to subscribe and listen to various events that occur within your application, providing a great way to decouple various aspects of your application.

Facades

Facades provide a static interface to classes that are available in the application's service container, offering the benefit of a terse, expressive syntax while maintaining more testability and flexibility than traditional static methods.

As you delve deeper into Yabasi, you'll see how these core concepts work together to create a robust, flexible framework for your web applications.

Routing

Routing is a core feature of Yabasi that allows you to map URLs to specific parts of your application. Yabasi provides a powerful and flexible routing system that can handle simple routes to complex patterns with ease.

Basic Routing

The most basic Yabasi routes accept a URI and a closure:

routes/web.php
use Yabasi\Routing\Router;

$router->get('/greeting', function () {
    return 'Hello, World!';
});

Available Router Methods

The router provides methods for all common HTTP verbs:

routes/web.php
$router->get($uri, $callback);
$router->post($uri, $callback);
$router->put($uri, $callback);
$router->patch($uri, $callback);
$router->delete($uri, $callback);
$router->options($uri, $callback);

Route Groups

Route groups allow you to share route attributes across a large number of routes without needing to define those attributes on each individual route:

routes/web.php
$router->group(['middleware' => [SessionMiddleware::class]], function ($router) {
    $router->get('/dashboard', 'DashboardController@index');
    $router->get('/account', 'AccountController@show');
});

Form Method Spoofing

HTML forms don't support PUT, PATCH or DELETE actions. To use these verb, add a hidden _method field to your form:

storage/view/form.twig
<form action="/foo/bar" method="POST">
    <input type="hidden" name="_method" value="PUT">
    {{ csrf_field()|raw }}
</form>

The routing system in Yabasi is both powerful and flexible, allowing you to structure your application's URLs in a way that makes sense for your project. As you build more complex applications, you'll find that mastering the routing system is key to creating clean, maintainable code.

Controllers

Controllers are a fundamental part of Yabasi's MVC architecture. They handle incoming HTTP requests, interact with models, and return responses. Let's dive deep into how controllers work in Yabasi.

Basic Controller Structure

Here's a basic example of a controller in Yabasi:

app/Controllers/UserController.php
namespace Yabasi\Controllers;

use Exception;
use Yabasi\Container\Container;
use Yabasi\Controller\Controller;
use Yabasi\Http\Request;
use Yabasi\Http\Response;
use Yabasi\Logging\Logger;
use Yabasi\Models\Users;
use Yabasi\Requests\UserRegistrationRequest;
use Yabasi\Session\SessionManager;

class UserController extends Controller
{
    protected SessionManager $session;
    protected Logger $logger;

    public function __construct(Container $container)
    {
        parent::__construct($container);
        $this->logger = $this->container->get(Logger::class);
    }

    public function index(Request $request): Response
    {
        // Fetch users from the database
        $users = Users::all();

        // Return a view with the users
        return $this->view('users', ['users' => $users]);
    }

    public function store(UserRegistrationRequest $request): Response
    {
        // Early return if validation fails
        if (!$request->validate()) {
            return (new Response())->redirect('/register');
        }

        // Input validation
        $name = trim($request->input('name'));
        $email = filter_var($request->input('email'), FILTER_SANITIZE_EMAIL);
        $password = $request->input('password');

        // Additional input checks
        if (empty($name) || empty($email) || empty($password)) {
            $this->session->flash('error', 'All fields are required.');
            $this->session->flash('_old_input', $request->except(['password']));
            return (new Response())->redirect('/register');
        }

        // Email format check
        if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
            $this->session->flash('error', 'Invalid email format.');
            $this->session->flash('_old_input', $request->except(['password']));
            return (new Response())->redirect('/register');
        }

        try {
            // Check if email already exists
            $existingUser = Users::query()->where('email', $email)->first();
            if ($existingUser) {
                $this->session->flash('error', 'Email already registered.');
                $this->session->flash('_old_input', $request->except(['password']));
                return (new Response())->redirect('/register');
            }

            // Create new user
            $user = new Users();
            $user->setName($request->input('name'));
            $user->setEmail($request->input('email'));
            $user->setPassword(password_hash($request->input('password'), PASSWORD_DEFAULT));

            // Save user
            if ($user->save()) {
                return (new Response())->redirect('/');
            } else {
                throw new Exception("Failed to save user");
            }

        } catch (Exception $e) {
            // Log the error with more details
            $this->logger->error("User registration failed", [
                'error' => $e->getMessage(),
                'email' => $email,
                'trace' => $e->getTraceAsString()
            ]);

            // User friendly error message
            $this->session->flash('error', 'Registration failed. Please try again later.');
            return (new Response())->redirect('/register');
        }
    }
}

Controller Methods

Controller methods typically correspond to HTTP verbs and URIs. Common method names include:

  • index() - Display a list of resources
  • show($id) - Display a specific resource
  • create() - Show a form to create a new resource
  • store(Request $request) - Store a new resource
  • edit($id) - Show a form to edit an existing resource
  • update(Request $request, $id) - Update an existing resource
  • destroy($id) - Delete a resource

Dependency Injection

Yabasi's controllers support automatic dependency injection. You can type-hint any dependencies in your controller's constructor or methods:

UserController.php
public function __construct(protected UserService $userService)
{
    // UserService is automatically injected
}

public function show(Request $request, $id, Logger $logger)
{
    // Request and Logger are automatically injected
    $logger->info("Showing user with ID: {$id}");
    $user = $this->userService->find($id);
    return $this->view('users.show', ['user' => $user]);
}

Resource Controllers

Yabasi provides a convenient way to create resource controllers that handle all CRUD operations for a resource:

php yabasi make:controller UserController --resource

This command creates a controller with all the necessary methods for handling a resource.

Controller Middleware

You can apply middleware to your controllers using the middleware() method:

UserController.php
public function __construct()
{
    $this->middleware('auth')->only(['store', 'update', 'destroy']);
    $this->middleware('log')->except('index');
}

This allows you to filter HTTP requests entering your application before they reach your controller methods.

Controllers are a crucial part of your Yabasi application, handling the core logic of your requests and responses. As you become more familiar with controllers, you'll be able to structure your application logic in a clean, organized manner.

Views

Views in Yabasi are responsible for containing the HTML served by your application. They separate your controller and application logic from your presentation logic, promoting cleaner, more maintainable code.

Creating Views

Views are stored in the resources/views directory. A simple view might look like this:

storage/views/greeting.twig
<html>
    <body>
        <h1>Hello, {{ name }}!</h1>
    </body>
</html>

Returning Views from Controllers

You can return a view from your controller using the view() helper method:

UserController.php
public function show($id)
{
    $user = User::find($id);
    return $this->view('user.profile', ['user' => $user]);
}

Passing Data to Views

You can pass data to views as an array:

UserController.php
return $this->view('user.profile', [
    'user' => User::find($id),
    'articles' => Article::latest()->get()
]);

Twig Templating Engine

Yabasi uses the Twig templating engine, which provides a powerful set of features for creating views:

Variables

templates/example.twig
{{ variable }}
{{ user.name }}
{{ user['name'] }}

Control Structures

templates/example.twig
{% if user %}
    Hello, {{ user.name }}!
{% endif %}

{% for user in users %}
    <li>{{ user.name }}</li>
{% endfor %}

Template Inheritance

Twig allows you to build a base "skeleton" template that contains all the common elements of your site:

layout.twig / child.twig
<!-- layout.twig -->
<html>
    <head>
        <title>{% block title %}My Site{% endblock %}</title>
    </head>
    <body>
        {% block content %}{% endblock %}
    </body>
</html>

<!-- child.twig -->
{% extends "layout.twig" %}

{% block title %}My Page{% endblock %}

{% block content %}
    <h1>Welcome to my page!</h1>
{% endblock %}

View Composers

View composers are callbacks or class methods that are called when a view is rendered. They allow you to bind data to a view each time it's rendered:

routes/web.php
View::composer('user.profile', function($view) {
    $view->with('count', User::count());
});

Optimization

Yabasi can cache your views for faster rendering. To cache all your views, run:

php yabasi view:cache

To clear the view cache:

php yabasi view:clear

Custom Twig Extensions

Yabasi allows you to create custom Twig extensions to add extra functionality to your views:

MyCustomExtension.php
use Twig\Extension\AbstractExtension;
use Twig\TwigFilter;

class MyCustomExtension extends AbstractExtension
{
    public function getFilters()
    {
        return [
            new TwigFilter('price', [$this, 'formatPrice']),
        ];
    }

    public function formatPrice($number, $decimals = 2, $decPoint = '.', $thousandsSep = ',')
    {
        return '$' . number_format($number, $decimals, $decPoint, $thousandsSep);
    }
}

// In a service provider:
$this->app->singleton(Twig\Environment::class, function ($app) {
    $twig = new Twig\Environment(...);
    $twig->addExtension(new MyCustomExtension());
    return $twig;
});

Views are an essential part of any web application, and Yabasi provides a flexible and powerful system for managing your application's presentation layer. By leveraging Twig's features and Yabasi's view helpers, you can create complex, dynamic user interfaces with ease.

Models

Models in Yabasi represent the data structure and business logic of your application. They interact with the database, handle relationships between different entities, and provide an elegant way to work with your data.

Defining Models

To create a model, extend the Yabasi\Database\Model class:

User.php
namespace Yabasi\Models;

use Yabasi\Database\Model;

class User extends Model
{
    protected static string $table = 'users';
    protected array $fillable = ['name', 'email', 'password'];
}

Creating and Saving Models

You can create and save model instances like this:

UserController.php
$user = new User();
$user->setName("John Doe");
$user->setEmail("john@example.com");
$user->setPassword("secret");
$result = $user->save();

echo "User save result: " . ($result ? "true" : "false");

Retrieving Models

Yabasi provides various methods to retrieve models:

UserController.php
// Find by ID
$user = User::find(1);

// Find by email
$user = User::query()->where('email', 'john@example.com')->first();

// Get all users
$allUsers = User::all();

// Count users
$userCount = User::count();

Updating Models

You can update model attributes and save changes:

UserController.php
$user = User::find(1);
$user->setName("John Updated");
$updateResult = $user->save();
echo "User update result: " . ($updateResult ? "true" : "false");

Deleting Models

To delete a model:

UserController.php
$user = User::find(1);
$deleteResult = $user->delete();

Query Building

Yabasi provides a fluent query builder:

UserController.php
$recentUsers = User::query()
    ->where('name', 'LIKE', 'John%')
    ->orderBy('created_at', 'DESC')
    ->limit(5)
    ->get();

Relationships

Yabasi supports various types of relationships between models, allowing you to easily work with related data:

One-to-Many Relationship

User.php
class User extends Model
{
    public function posts() {
        return $this->hasMany(Post::class);
    }
}

Belongs-To Relationship

Post.php
class Post extends Model
{
    public function author() {
        return $this->belongsTo(User::class);
    }
}

Using Relationships

You can easily access related models:

UserController.php
$user = User::find(1);
$posts = $user->posts;
foreach ($posts as $post) {
    echo $post->title . " by " . $post->author->name . "\n";
}

$post = Post::find(1);
echo "Author: " . $post->author->name;

Eager Loading

To avoid the N+1 query problem, you can use eager loading:

UserController.php
$users = User::with('posts')->get();
foreach ($users as $user) {
    echo $user->name . " has " . $user->posts->count() . " posts.\n";
}

Mass Assignment

Yabasi allows you to set multiple attributes at once using the fill() method:

UserController.php
$user = new User();
$user->fill([
    'name' => 'Jane Doe',
    'email' => 'jane@example.com',
    'password' => 'secret'
]);

$result = $user->save();
echo "User save result: " . ($result ? "true" : "false");

Accessors and Mutators

You can define accessors and mutators to format attribute values when retrieving or setting them:

User.php
class User extends Model
{
    public function getName(): string
    {
        return ucfirst($this->attributes['name']);
    }

    public function setPassword($value): void
    {
        $this->attributes['password'] = password_hash($value, PASSWORD_DEFAULT);
    }
}

These features of Yabasi's ORM allow you to work with your database in an object-oriented manner, making your code more readable and maintainable. The relationships feature, in particular, helps you to efficiently work with related data across multiple tables.

Database

Yabasi provides a robust and flexible database layer, supporting various database systems and offering an intuitive API for database operations.

Configuration

Database configuration is typically stored in the config/config.php file:

config/config.php
return [
    'database' => [
        'driver'   => 'mysql',
        'host'     => 'localhost',
        'database' => 'yabasi_db',
        'username' => 'root',
        'password' => '',
    ],
];

Query Builder

Yabasi's query builder provides a convenient, fluent interface for creating and running database queries:

UserController.php
$users = User::query()
    ->where('active', true)
    ->where('age', '>', 18)
    ->orderBy('name', 'asc')
    ->limit(10)
    ->get();

Raw Queries

For more complex queries, you can use raw SQL:

UserController.php
$results = DB::select('SELECT * FROM users WHERE active = ?', [true]);

$affected = DB::update('UPDATE users SET status = ? WHERE id = ?', ['active', 1]);

Transactions

Yabasi supports database transactions to ensure data integrity:

TransferController.php
DB::beginTransaction();

try {
    DB::update('UPDATE accounts SET balance = balance - ? WHERE id = ?', [100, 1]);
    DB::update('UPDATE accounts SET balance = balance + ? WHERE id = ?', [100, 2]);
    DB::commit();
} catch (\Exception $e) {
    DB::rollBack();
    throw $e;
}

Migrations

Yabasi provides a powerful migration system for managing database schema:

2024_10_20_create_users_table.php
use Yabasi\Database\Schema\Blueprint;
use Yabasi\Database\Migrations\Migration;

class CreateUsersTable extends Migration
{
    public function up()
    {
        Schema::create('users', function (Blueprint $table) {
            $table->id();
            $table->string('name');
            $table->string('email')->unique();
            $table->timestamps();
        });
    }
}

These features provide a solid foundation for working with databases in your Yabasi applications. The query builder and ORM work together to offer a powerful yet intuitive interface for database operations, while migrations ensure that your database schema can be easily version-controlled and shared across different environments.

Forms & Validation

Yabasi framework provides a powerful and flexible system for handling forms and validating data. This system allows you to process and validate user inputs securely and efficiently.

Creating Forms

In Yabasi, forms are typically created within Twig templates. Here's an example of a simple form:

form.twig
<form method="POST" action="{{ url('user.store') }}">
    {{ csrf_field() }}
    <div>
        <label for="name">Name:</label>
        <input type="text" id="name" name="name" value="{{ old('name') }}">
    </div>
    <button type="submit">Submit</button>
</form>

Handling Form Submissions

Form submissions are typically handled in controller methods. Here's an example of how to handle a form submission:

UserController.php
public function store(Request $request)
{
    $validated = $request->validate([
        'name' => 'required|string|max:255',
    ]);

    // Process the validated data
    User::create($validated);
}

Validation

Yabasi provides a powerful validation system. You can define validation rules for your form data in various ways:

Using the Validator Class

UserController.php
use Yabasi\Validation\Validator;

public function store(Request $request, Validator $validator)
{
    $rules = [
        'name' => 'required|string|max:255',
        'email' => 'required|email|unique:users',
    ];

    if (!$validator->make($request->all(), $rules)) {
        return redirect()->back()->withErrors($validator)->withInput();
    }

    // Process validated data
}

Form Request Validation

For more complex validation scenarios, you can create dedicated Form Request classes:

StoreUserRequest.php
use Yabasi\Http\FormRequest;

class StoreUserRequest extends FormRequest
{
    public function rules(): array
    {
        return [
            'name' => 'required|string|max:255',
            'email' => 'required|email|unique:users',
        ];
    }
}

Then, you can use this Form Request in your controller:

UserController.php
public function store(StoreUserRequest $request)
{
    User::create($request->validated());
}

Displaying Validation Errors

Validation errors can be displayed in your Twig templates:

form.twig
{% if errors.has('name') %}
    <div class="error">
        {{ errors.first('name') }}
    </div>
{% endif %}

Yabasi's form and validation system provides a robust way to handle user input, ensuring data integrity and improving the overall security of your application.

Authentication

Yabasi framework provides a robust and flexible authentication system. It allows you to easily implement user authentication in your applications.

Configuration

Authentication configuration is typically stored in the config/config.php file:

config/config.php
return [
    'auth' => [
        'model' => Yabasi\Models\User::class,
        'table' => 'users',
        'username' => 'email',
        'password' => 'password',
    ],
];

User Registration

Here's an example of how to implement user registration:

AuthController.php
public function register(Request $request)
{
    $validated = $request->validate([
        'name' => 'required|string|max:255',
        'email' => 'required|string|email|max:255|unique:users',
        'password' => 'required|string|min:8|confirmed',
    ]);

    $user = User::create($validated);
    Auth::login($user);

    return redirect()->intended('/dashboard');
}

User Login

Here's an example of how to implement user login:

AuthController.php
public function login(Request $request)
{
    $credentials = $request->validate([
        'email' => 'required|email',
        'password' => 'required',
    ]);

    if (Auth::attempt($credentials)) {
        $request->session()->regenerate();
        return redirect()->intended('/dashboard');
    }

    return back()->withErrors(['email' => 'The provided credentials do not match our records.']);
}

Middleware

Yabasi provides middleware to protect routes that require authentication:

routes/web.php
$router->group(['middleware' => ['auth']], function ($router) {
    $router->get('/dashboard', 'DashboardController@index');
    $router->get('/profile', 'ProfileController@show');
    // Add more protected routes here
});

Yabasi's authentication system provides a secure and flexible way to manage user authentication in your application. It integrates seamlessly with the framework's other features like middleware and session management.

Caching

Yabasi framework provides a powerful and flexible caching system to improve your application's performance. The caching system supports multiple cache drivers and offers a clean, unified API.

Configuration

Caching configuration is typically stored in the config/config.php file:

config/config.php
return [
    'cache' => [
        'default' => 'file',  // Primary cache store
        'path'    => BASE_PATH . '/storage/cache',
        'stores'  => [
            'file'  => [
                'driver' => 'file',
                'path'   => BASE_PATH . '/storage/cache/data',
            ],
            'redis' => [
                'driver'     => 'redis',
                'connection' => 'default',
            ],
        ],
    ],
];

Basic Usage

Here are some basic operations you can perform with the Yabasi caching system:

Setting and Getting Cache Values

CacheExample.php
// Set a value in the cache for 1 hour
Cache::set('user_count', 100, 3600);

// Get a value from the cache
$userCount = Cache::get('user_count', 0);

Checking for Existence and Removing Cache Items

CacheExample.php
// Check if a key exists in the cache
if (Cache::has('user_count')) {
    echo "User count is cached.";
}

// Remove an item from the cache
Cache::delete('user_count');

Incrementing and Decrementing Values

CacheExample.php
// Increment a value
$newCount = Cache::increment('user_count', 5);

// Decrement a value
$decrementedCount = Cache::decrement('user_count', 2);

Working with Multiple Cache Items

CacheExample.php
// Set multiple values
Cache::setMany([
    'total_posts' => 1000,
    'total_comments' => 5000
], 1800); // Cache for 30 minutes

// Get multiple values
$stats = Cache::many(['total_posts', 'total_comments', 'nonexistent_key']);

// Delete multiple values
Cache::deleteMany(['total_posts', 'total_comments']);

Advanced Usage

Using Different Cache Stores

You can specify which cache store to use for a particular operation:

CacheExample.php
$value = Cache::store('redis')->get('key');
Cache::store('file')->put('key', 'value', 600);

Atomic Locks

Yabasi provides atomic locks to manage concurrent access to resources:

AtomicLockExample.php
$lock = Cache::lock('processing-report', 10);

if ($lock->get()) {
    // Process the report...

    $lock->release();
} else {
    // Could not obtain lock...
    return 'Try again later.';
}

Cache Tags

Cache tags allow you to tag related items in the cache and then flush all cached values tagged with a given name:

CacheTagsExample.php
Cache::tags(['people', 'artists'])->put('John', $johnData, 3600);
Cache::tags(['people', 'authors'])->put('Anne', $anneData, 3600);

$john = Cache::tags(['people', 'artists'])->get('John');
$anne = Cache::tags(['people', 'authors'])->get('Anne');

// Remove all entries tagged with 'people'
Cache::tags('people')->flush();

Cache Helpers

Yabasi provides several helper functions to make working with the cache easier:

CacheHelpers.php
// Cache a value if it doesn't exist
$value = Cache::remember('key', 3600, function () {
    return computeExpensiveValue();
});

// Cache a value forever
Cache::forever('key', 'value');

// Get and forget a value
$value = Cache::pull('key');

// Clear all items from the cache
Cache::flush();

Best Practices

  • Use meaningful keys for your cached items to avoid conflicts.
  • Set appropriate TTL (Time To Live) values for your cached data to ensure freshness.
  • Use cache tags to organize and manage related cache entries.
  • Be mindful of cache size, especially when using file-based caching.
  • Use atomic locks for operations that require exclusive access.
  • Implement cache warming strategies for critical data.

Yabasi's caching system provides a powerful tool to improve your application's performance. By strategically caching data and computationally expensive operations, you can significantly reduce load times and server load.

Session Management

Yabasi framework provides a robust and flexible session management system. It allows you to easily handle user sessions, store and retrieve data, and implement security measures.

Configuration

Session configuration is typically stored in the config/config.php file:

config/config.php
return [
    'session' => [
        'driver'    => 'file',
        'lifetime'  => 120,
        'path'      => '/tmp',
        'domain'    => null,
        'secure'    => false,
        'httponly'  => true,
    ],
];

Basic Usage

Here are some basic operations you can perform with the Yabasi session management system:

Starting a Session

SessionExample.php
use Yabasi\Session\SessionManager;

$sessionManager = new SessionManager($config, $securityHandler);
$sessionManager->start();

Setting and Getting Session Data

SessionExample.php
// Set a session value
$sessionManager->set('user_id', 123);

// Get a session value
$userId = $sessionManager->get('user_id');

Checking and Removing Session Data

SessionExample.php
if ($sessionManager->has('user_id')) {
    // The 'user_id' exists in the session
    $sessionManager->remove('user_id');
}

Advanced Features

Flash Messages

Flash messages are temporary session data, typically used for one-time notifications:

FlashExample.php
// Set a flash message
$sessionManager->flash('success', 'Operation completed successfully.');

// Retrieve a flash message
$flashMessage = $sessionManager->getFlash('success');

Session Security

Yabasi provides built-in security features for sessions:

SecurityExample.php
use Yabasi\Session\SecurityHandler;

$securityHandler = new SecurityHandler();
$securityHandler->setSessionIdentifiers();
SecurityHandler::preventSessionFixation();

Best Practices

  • Always start the session before using any session-related functions.
  • Use flash messages for temporary data that should only be available for the next request.
  • Implement proper session security measures to prevent attacks like session fixation.
  • Regularly regenerate session IDs to enhance security.
  • Clear sensitive session data when it's no longer needed.

Yabasi's session management system provides a secure and flexible way to handle user sessions in your application. By leveraging these features, you can create robust and secure web applications.

Error Handling & Logging

Yabasi framework provides robust error handling and logging capabilities to help you manage and debug your application effectively.

Error Handling

Yabasi uses a custom exception handler to manage errors gracefully. Here's how you can configure and use it:

Bootstrap.php
use Yabasi\Logging\CustomExceptionHandler;

$config = $this->container->get('config');
$this->exceptionHandler = new CustomExceptionHandler(
    $config->get('app.debug', false)
);

Handling Exceptions

You can use the custom exception handler to manage exceptions in your application:

ExampleController.php
public function exampleAction()
{
    try {
        // Your code here
    } catch (\Exception $e) {
        $this->exceptionHandler->handle($e);
    }
}

Logging

Yabasi provides a powerful logging system through the Logger class. Here's how to use it:

LoggerExample.php
use Yabasi\Logging\Logger;

$logger = new Logger($config);

$logger->info('This is an informational message');
$logger->warning('This is a warning');
$logger->error('An error occurred', ['error_code' => 500]);
$logger->critical('A critical error occurred');

Log Levels

Yabasi supports various log levels, allowing you to categorize your log messages:

  • emergency
  • alert
  • critical
  • error
  • warning
  • notice
  • info
  • debug

Custom Log Files

You can create custom log files for different parts of your application:

CustomLoggerExample.php
$apiLogger = new Logger($config, 'api');
$apiLogger->info('API request received', ['endpoint' => '/users']);

Best Practices

  • Use appropriate log levels to categorize your messages.
  • Include relevant context data in your log messages.
  • Implement proper error handling to catch and log exceptions.
  • Regularly review and analyze your log files.
  • Use custom log files for different components or services in your application.
  • Configure log rotation to manage log file sizes.

Proper error handling and logging are crucial for maintaining and debugging your Yabasi application. By leveraging these features, you can quickly identify and resolve issues, improving the overall reliability of your application.

Security

Yabasi framework provides robust security features to help protect your application against common web vulnerabilities. This section covers the key security components and best practices.

CSRF Protection

Cross-Site Request Forgery (CSRF) protection is built into Yabasi to prevent unauthorized commands from being transmitted from a user that the web application trusts.

Generating CSRF Tokens

CsrfProtection.php
use Yabasi\Security\CsrfProtection;

$csrfProtection = new CsrfProtection($session);
$token = $csrfProtection->generateToken();

Validating CSRF Tokens

CsrfMiddleware.php
public function handle(Request $request, Closure $next): Response
{
    $token = $this->csrfProtection->getTokenFromRequest($request);
    if (!$token || !$this->csrfProtection->validateToken($token)) {
        return new Response('CSRF token mismatch', 403);
    }
    return $next($request);
}

XSS Protection

Yabasi includes built-in protection against Cross-Site Scripting (XSS) attacks by automatically escaping output.

XssProtection.php
$userInput = "<script>alert('XSS');</script>";
$cleanInput = XssProtection::clean($userInput);
// Output: &lt;script&gt;alert('XSS');&lt;/script&gt;

Session Security

Yabasi provides robust session security features to protect against session hijacking and fixation attacks.

Secure Session Configuration

SecurityHandler.php
SecurityHandler::setSecureCookieParams();
SecurityHandler::preventSessionFixation();

Session Validation

SecurityHandler.php
$securityHandler = new SecurityHandler();
if (!$securityHandler->validateSession()) {
    // Session is invalid, handle accordingly
    $session->regenerate();
}

Password Hashing

Yabasi uses secure password hashing by default when working with user models.

User.php
public function setPassword($value): void
{
    $this->attributes['password'] = password_hash($value, PASSWORD_DEFAULT);
}

Database Security

Yabasi uses prepared statements to prevent SQL injection attacks.

QueryBuilder.php
$users = User::query()
    ->where('email', '=', $email)
    ->get();

API Security

For API security, Yabasi includes rate limiting to prevent abuse.

CLI & Artisan

Yabasi framework provides a powerful Command Line Interface (CLI) tool, similar to Laravel's Artisan, to help you manage and interact with your application. This tool simplifies many common tasks and allows you to create custom commands for your specific needs.

1. Yabasi CLI Overview

The Yabasi CLI is a versatile tool that automates many development tasks, from generating boilerplate code to managing database migrations. To use the Yabasi CLI, you typically run commands in your terminal from your project's root directory.

php yabasi command:name

2. Basic Commands

Yabasi comes with several built-in commands to help you generate common components of your application:

make:controller

Creates a new controller class.

php yabasi make:controller UserController

make:model

Generates a new model class.

php yabasi make:model User

make:middleware

Creates a new middleware class.

php yabasi make:middleware AuthMiddleware

make:migration

Generates a new database migration file.

php yabasi make:migration create_users_table

3. Database Commands

Yabasi provides several commands to manage your database migrations:

  • migrate: Run all pending migrations
  • migrate:rollback: Rollback the last database migration
  • migrate:reset: Rollback all database migrations
  • migrate:refresh: Reset and re-run all migrations
  • migrate:status: Show the status of each migration
  • db:dump: Create a database dump
  • db:restore: Restore a database from a dump

4. Creating Custom Commands

You can create your own custom commands in Yabasi. Here's an example of how to structure a custom command:

CustomCommand.php
use Symfony\Component\Console\Command\Command;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;

class CustomCommand extends Command
{
    protected static $defaultName = 'app:custom-command';

    protected function configure()
    {
        $this->setDescription('A custom command description');
    }

    protected function execute(InputInterface $input, OutputInterface $output)
    {
        $output->writeln('Custom command executed!');
        return Command::SUCCESS;
    }
}

After creating your custom command, you need to register it in the Console class:

Console.php
protected function registerCommands(): void
{
    $this->console->add(new CustomCommand());
}

5. Console Class

The Console class in Yabasi is responsible for registering and running CLI commands. It uses Symfony's Console component to manage commands.

Console.php
class Console
{
    protected Container $container;
    protected SymfonyConsole $console;

    public function __construct(Container $container)
    {
        $this->container = $container;
        $this->console = new SymfonyConsole('Yabasi', '1.0.0');
        $this->registerCommands();
    }

    public function run(array $argv): int
    {
        return $this->console->run();
    }
}

6. Arguments and Options

You can add arguments and options to your custom commands to make them more flexible and powerful. Here's an example of how to define and use arguments and options:

CustomCommand.php
protected function configure()
{
    $this
        ->setName('app:greet')
        ->setDescription('Greet someone')
        ->addArgument('name', InputArgument::REQUIRED, 'Who do you want to greet?')
        ->addOption('yell', 'y', InputOption::VALUE_NONE, 'Yell in uppercase letters');
}

protected function execute(InputInterface $input, OutputInterface $output)
{
    $name = $input->getArgument('name');
    $greeting = "Hello, $name!";

    if ($input->getOption('yell')) {
        $greeting = strtoupper($greeting);
    }

    $output->writeln($greeting);
    return Command::SUCCESS;
}

7. Output Formatting

Yabasi CLI commands support colorized and formatted output to enhance readability and user experience. Here's how you can use various output styles:

FormattedOutputCommand.php
protected function execute(InputInterface $input, OutputInterface $output)
{
    $output->writeln('<info>This is a success message</info>');
    $output->writeln('<comment>This is a comment</comment>');
    $output->writeln('<question>This is a question</question>');
    $output->writeln('<error>This is an error</error>');

    return Command::SUCCESS;
}

8. Interactive Commands

You can create interactive commands that ask for user input or confirmation. Here's an example:

InteractiveCommand.php
protected function execute(InputInterface $input, OutputInterface $output)
{
    $helper = $this->getHelper('question');
    $question = new Question('Please enter your name: ', 'User');
    $name = $helper->ask($input, $output, $question);

    $question = new ConfirmationQuestion('Do you want to continue? (y/n) ', false);
    if (!$helper->ask($input, $output, $question)) {
        return Command::SUCCESS;
    }

    $output->writeln("Hello, $name! You chose to continue.");
    return Command::SUCCESS;
}

9. Help and Documentation

Yabasi automatically generates help documentation for your commands based on the descriptions and configurations you provide. You can view help for a command by running:

php yabasi command:name --help

To provide more detailed help for your custom commands, you can override the configure() method:

CustomCommand.php
protected function configure()
{
    $this
        ->setName('app:custom-command')
        ->setDescription('A custom command description')
        ->setHelp('This command allows you to...')
        ->addArgument('name', InputArgument::REQUIRED, 'Name description')
        ->addOption('option', null, InputOption::VALUE_NONE, 'Option description')
    ;
}

10. Best Practices

When writing CLI commands for Yabasi, consider the following best practices:

  • Keep commands focused on a single task
  • Use meaningful names for your commands, arguments, and options
  • Provide clear and concise descriptions for your commands and their parameters
  • Use input validation to prevent errors
  • Implement proper error handling and provide informative error messages
  • Use output formatting to improve readability
  • For long-running commands, consider adding progress indicators
  • Write unit tests for your commands to ensure they work as expected

Example: Progress Bar

For long-running tasks, you can use a progress bar to keep the user informed:

LongRunningCommand.php
use Symfony\Component\Console\Helper\ProgressBar;

protected function execute(InputInterface $input, OutputInterface $output)
{
    $progressBar = new ProgressBar($output, 100);
    $progressBar->start();

    for ($i = 0; $i < 100; $i++) {
        // ... do some work here
        $progressBar->advance();
    }

    $progressBar->finish();
    return Command::SUCCESS;
}

By following these best practices and utilizing the features provided by Yabasi's CLI tools, you can create powerful, user-friendly command-line interfaces for your application. These tools can significantly improve your development workflow and provide valuable utilities for managing your Yabasi projects.

Testing

Yabasi framework provides a robust testing infrastructure to ensure the reliability and stability of your applications. It uses PHPUnit as the testing framework, allowing you to write unit tests, integration tests, and feature tests with ease.

Setting Up the Testing Environment

Yabasi comes with a pre-configured phpunit.xml file that defines test suites and environment variables for testing.

phpunit.xml
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="../vendor/autoload.php"
         colors="true"
         verbose="true"
         stopOnFailure="false">
    <testsuites>
        <testsuite name="Unit">
            <directory suffix="Test.php">./Unit</directory>
        </testsuite>
        <testsuite name="Integration">
            <directory suffix="Test.php">./Integration</directory>
        </testsuite>
    </testsuites>
    <php>
        <env name="APP_ENV" value="testing"/>
    </php>
</phpunit>

Base Test Case

Yabasi provides a base test case class that sets up the testing environment and offers helpful utility methods for your tests.

YabasiTestCase.php
namespace Yabasi\Tests;

use PHPUnit\Framework\TestCase;
use Yabasi\Application;
use Yabasi\Container\Container;

class YabasiTestCase extends TestCase
{
    protected $app;
    protected $container;

    protected function setUp(): void
    {
        parent::setUp();
        $this->container = new Container();
        $this->app = new Application($this->container);
    }

    protected function tearDown(): void
    {
        $this->app = null;
        $this->container = null;
        parent::tearDown();
    }
}

Writing Unit Tests

Unit tests are used to test the smallest parts of your application in isolation. Here's an example of a simple unit test:

ExampleTest.php
namespace Yabasi\Tests\Unit;

use Yabasi\Application;
use Yabasi\Tests\YabasiTestCase;

class ExampleTest extends YabasiTestCase
{
    public function testExample()
    {
        $this->assertTrue(true);
    }

    public function testApplicationInstance()
    {
        $this->assertInstanceOf(Application::class, $this->app);
    }
}

Integration Tests

Integration tests are used to test how different components of your application work together. Here's an example of a router integration test:

RouterTest.php
namespace Yabasi\Tests\Integration;

use Yabasi\Http\Request;
use Yabasi\Routing\Router;
use Yabasi\Tests\YabasiTestCase;

class RouterTest extends YabasiTestCase
{
    public function testBasicRouting()
    {
        $router = $this->app->make(Router::class);
        $router->get('/test', function() {
            return 'Hello Test';
        });

        $request = $this->createRequest('/test', 'GET');
        $response = $router->dispatch($request);

        $this->assertEquals('Hello Test', $response->getContent());
    }

    private function createRequest($uri, $method, $parameters = [], $cookies = [], $files = [], $server = [])
    {
        // Implementation of createRequest method
    }
}

Running Tests

To run your tests, use the PHPUnit command from your project root:

./vendor/bin/phpunit

You can also run specific test suites or individual test files:

./vendor/bin/phpunit --testsuite Unit
./vendor/bin/phpunit tests/Unit/ExampleTest.php

Best Practices

  • Write tests for all new features and bug fixes
  • Aim for high test coverage, but focus on critical paths
  • Keep tests fast and independent of each other
  • Use descriptive test method names
  • Follow the Arrange-Act-Assert (AAA) pattern in your tests
  • Use data providers for testing multiple scenarios
  • Mock external dependencies to isolate the code being tested

By following these testing practices and utilizing Yabasi's testing infrastructure, you can ensure the reliability and maintainability of your applications.

Events & Listeners

Yabasi framework provides a robust event system that allows you to easily implement and manage application events. This system helps in decoupling various aspects of your application, making it more maintainable and extensible.

Event Dispatcher

The core of Yabasi's event system is the EventDispatcher class. It manages event registration and dispatching.

EventDispatcher.php
namespace Yabasi\Events;

use Closure;

class EventDispatcher
{
    protected array $listeners = [];

    public function listen(string $eventName, $listener): void
    {
        $this->listeners[$eventName][] = $listener;
    }

    public function dispatch(Event $event): void
    {
        $eventName = $event->getName();
        if (isset($this->listeners[$eventName])) {
            foreach ($this->listeners[$eventName] as $listener) {
                if ($listener instanceof Closure) {
                    $listener($event);
                } elseif (is_array($listener) && count($listener) == 2) {
                    [$class, $method] = $listener;
                    if (is_string($class)) {
                        $class = new $class();
                    }
                    $class->$method($event);
                }
            }
        }
    }
}

Creating Events

Events in Yabasi are simple classes that extend the base Event class. They typically contain data relevant to the event.

UserRegisteredEvent.php
namespace App\Events;

use Yabasi\Events\Event;
use App\Models\User;

class UserRegisteredEvent extends Event
{
    public function __construct(public User $user)
    {
        parent::__construct('user.registered');
    }
}

Creating Listeners

Listeners are classes or closures that respond to specific events. They perform actions based on the event data.

SendWelcomeEmail.php
namespace App\Listeners;

use App\Events\UserRegisteredEvent;

class SendWelcomeEmail
{
    public function handle(UserRegisteredEvent $event)
    {
        // Send welcome email to $event->user
    }
}

Registering Events and Listeners

You can register events and listeners in your service providers or anywhere you have access to the EventDispatcher.

EventServiceProvider.php
namespace App\Providers;

use Yabasi\Events\EventDispatcher;
use Yabasi\ServiceProvider\ServiceProvider;
use App\Events\UserRegisteredEvent;
use App\Listeners\SendWelcomeEmail;

class EventServiceProvider extends ServiceProvider
{
    public function boot(): void
    {
        $this->container->get(EventDispatcher::class)->listen(UserRegisteredEvent::class, [SendWelcomeEmail::class, 'handle']);
    }
}

Dispatching Events

To dispatch an event, you can use the EventDispatcher's dispatch method.

UserController.php
use App\Events\UserRegisteredEvent;
use Yabasi\Events\EventDispatcher;

class UserController
{
    public function register(Request $request, EventDispatcher $eventDispatcher)
    {
        // User registration logic
        $user = User::create($request->all());

        // Dispatch the event
        $eventDispatcher->dispatch(new UserRegisteredEvent($user));

        return response()->json(['message' => 'User registered successfully']);
    }
}

Event Subscribers

Event subscribers are classes that can listen to multiple events. They provide a more organized way to handle related events.

UserEventSubscriber.php
namespace App\Listeners;

use Yabasi\Events\EventDispatcher;

class UserEventSubscriber
{
    public function subscribe(EventDispatcher $events): void
    {
        $events->listen(
            'user.registered',
            [$this, 'handleUserRegistered']
        );

        $events->listen(
            'user.login',
            [$this, 'handleUserLogin']
        );
    }

    public function handleUserRegistered($event) { /* ... */ }
    public function handleUserLogin($event) { /* ... */ }
}

Best Practices

  • Keep events and listeners small and focused on a single responsibility.
  • Use event names that clearly describe what happened (e.g., 'user.registered', 'order.shipped').
  • Consider using event subscribers for closely related events.
  • Avoid performing time-consuming tasks directly in listeners. Instead, dispatch jobs to be processed in the background.
  • Use type-hinting in your listener methods to ensure you're working with the correct event type.

By leveraging Yabasi's event system, you can create more modular and maintainable applications. Events allow you to decouple various parts of your application, making it easier to add new functionality without modifying existing code.

Queues & Jobs

Yabasi provides a robust queue system for handling time-consuming tasks asynchronously. The queue system supports multiple drivers (with Redis as the default), job retries, batch processing, and event handling.

Creating Jobs

To create a job, extend the base Job class:

ProcessVideoJob.php
namespace App\Jobs;

use Yabasi\Queue\Job;

class ProcessVideoJob extends Job
{
    protected $maxAttempts = 3;
    protected $delay = 60;

    public function handle()
    {
        // Process video logic here
        $this->setProgress(50);
        // More processing...
    }
}

Dispatching Jobs

You can dispatch jobs to the queue in several ways:

use App\Jobs\ProcessVideoJob;

// Dispatch immediately
app()->get('queue')->push(new ProcessVideoJob($data));

// Dispatch with delay
app()->get('queue')->later(60, new ProcessVideoJob($data));

Job Configuration

Jobs can be configured with several options:

  • $maxAttempts: Maximum number of retry attempts
  • $delay: Delay between retry attempts in seconds
  • $progress: Track job progress

Running the Queue Worker

To process jobs, you need to run the queue worker:

php yabasi queue:work

Handling Failed Jobs

You can implement custom failure handling in your jobs:

public function failed(Exception $exception)
{
    // Log the failure
    $this->logger->error("Job failed: " . $exception->getMessage());

    // Notify or perform cleanup
}

Monitoring Progress

Jobs can report their progress during execution:

public function handle()
{
    $this->setProgress(25);
    // Process first stage...

    $this->setProgress(50);
    // Process second stage...

    $this->setProgress(100);
}

Queue Events

The queue system dispatches various events that you can listen to:

  • Job started
  • Job processed
  • Job failed
  • Job retrying

API Development

Yabasi provides a robust set of tools for building RESTful APIs, including versioning, rate limiting, CORS support, and standardized response formatting. The framework makes it easy to create secure and scalable APIs while following REST best practices.

API Routes

Define API routes using the ApiRouter with automatic prefix and versioning:

routes/api.php
use Yabasi\Routing\ApiRouter;

$apiRouter = new ApiRouter($router);

$apiRouter->setVersion('v1')->group([], function($router) {
    $router->resource('users', 'UserApiController');
    $router->get('posts', 'PostApiController@index');
    $router->post('posts', 'PostApiController@store');
});

API Controllers

Extend the ApiController base class to get standardized response methods:

UserApiController.php
namespace App\Controllers;

use Yabasi\Http\Controllers\ApiController;
use Yabasi\Http\Request;

class UserApiController extends ApiController
{
    public function index()
    {
        $users = User::all();
        return $this->respondWithData($users);
    }

    public function store(Request $request)
    {
        // Validation and creation logic
        return $this->respondWithSuccess('User created successfully', 201);
    }
}

Rate Limiting

Protect your API endpoints with built-in rate limiting:

$apiRouter->group([
    'middleware' => [
        RateLimitMiddleware::class
    ]
], function($router) {
    // Your rate-limited routes here
});

API Versioning

API versioning is handled automatically through the URL or Accept header:

  • URL-based: /api/v1/users
  • Header-based: Accept-Version: v1

CORS Configuration

Configure CORS for your API in the config/config.php file:

'cors' => [
    'allowed_origins'   => ['*'],
    'allowed_methods'   => ['*'],
    'allowed_headers'   => ['*'],
    'allow_credentials' => false,
    'max_age'          => 0,
],

Standardized API Responses

ApiController provides methods for consistent response formatting:

  • respondWithData($data, $statusCode = 200)
  • respondWithError($message, $statusCode)
  • respondWithSuccess($message, $statusCode = 200)
  • respondWithValidationError($errors)
  • respondWithPaginatedData($data, $page, $perPage, $total)

Response Examples

Example of standardized JSON responses:

{
    "data": {
        "id": 1,
        "name": "John Doe",
        "email": "john@example.com"
    },
    "meta": {
        "version": "v1"
    }
}

WebSockets

Yabasi provides real-time communication capabilities through WebSockets using the Ratchet WebSocket server. This enables you to build real-time features like chat applications, live notifications, and real-time dashboards.

Creating a WebSocket Server

Create a WebSocket server by extending the BaseWebSocketServer class:

NotificationServer.php
namespace App\WebSocket;

use Ratchet\ConnectionInterface;
use Yabasi\WebSocket\BaseWebSocketServer;

class NotificationServer extends BaseWebSocketServer
{
    public function onMessage(ConnectionInterface $from, $msg)
    {
        $data = json_decode($msg, true);

        // Broadcast message to all connected clients
        foreach ($this->clients as $client) {
            $client->send(json_encode([
                'type' => 'notification',
                'data' => $data
            ]));
        }
    }
}

Running the WebSocket Server

Run your WebSocket server using the command line:

php yabasi websocket:serve

Client-Side Connection

Connect to your WebSocket server from the client side:

script.js
const socket = new WebSocket('ws://localhost:8080');

socket.onopen = function() {
    console.log('Connected to WebSocket server');
};

socket.onmessage = function(event) {
    const data = JSON.parse(event.data);

    if (data.type === 'notification') {
        console.log('New notification:', data.data);
    }
};

Handling Events

The BaseWebSocketServer provides several events you can handle:

class GameServer extends BaseWebSocketServer
{
    public function onOpen(ConnectionInterface $conn)
    {
        // New connection established
        parent::onOpen($conn);
    }

    public function onClose(ConnectionInterface $conn)
    {
        // Connection closed
        parent::onClose($conn);
    }

    public function onError(ConnectionInterface $conn, \Exception $e)
    {
        // Handle error
        parent::onError($conn, $e);
    }
}

Broadcasting Messages

Send messages to specific clients or broadcast to all connected clients:

// Broadcast to all clients except sender
foreach ($this->clients as $client) {
    if ($from !== $client) {
        $client->send($msg);
    }
}

// Send to specific client
$targetClient->send(json_encode([
    'type' => 'private',
    'message' => 'Private message'
]));

Localization

Yabasi provides a powerful and flexible localization system for creating multilingual applications. The framework uses JSON-based language files and offers an intuitive API for managing translations.

Configuration

First, set your application's default and fallback locales in your configuration file:

config/config.php
return [
    'app' => [
        'locale' => 'en',
        'fallback_locale' => 'en',
    ],
];

Language Files

Create JSON language files in the storage/lang directory. Each language should have its own file:

storage/lang/en.json
{
    "welcome": "Welcome to our application",
    "auth.failed": "These credentials do not match our records",
    "users.greeting": "Hello, :name!",
    "items.count": "You have :count items"
}

Basic Usage

You can use the translation helper function __() or the Translator class directly:

Example Usage
// Using helper function
echo __('welcome');

// Using with parameters
echo __('users.greeting', ['name' => 'John']);

// Using Translator class
$translator = $container->get(Translator::class);
echo $translator->get('welcome');

Using in Twig Templates

The translation function is also available in Twig templates:

example.twig
<h1>{{ __('welcome') }}</h1>

<p>{{ __('users.greeting', {'name': user.name}) }}</p>

Switching Locales

You can change the application's locale at runtime:

$translator = $container->get(Translator::class);

// Switch to Spanish
$translator->setLocale('es');

Pluralization

Handle pluralization in your translations using the count parameter:

storage/lang/en.json
{
    "items.zero": "No items found",
    "items.one": "One item found",
    "items.many": ":count items found"
}

Best Practices

  • Use dot notation to organize translations hierarchically
  • Always provide a fallback locale for missing translations
  • Keep translation keys lowercase and use dots for namespacing
  • Use meaningful key names that describe the content
  • Group related translations together

Remember to create language files for all supported locales before deploying your application. Missing translations will fall back to the default locale.