### Database Interaction Example Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/data-flow-and-interactions.md Demonstrates creating a user record via the userRepository and the expected result. ```javascript // Database interaction const user = await userRepository.create({ name: 'John', email: 'john@example.com', password: 'hashed_password' }); // Result: User object with id, timestamps, relationships ``` -------------------------------- ### Include Code Examples in Documentation Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/best-practices-and-guidelines.md Provide clear and concise code examples within your documentation to illustrate usage. This helps users understand how to integrate and utilize your code effectively. ```javascript /** * Example usage: * * const order = await placeOrderAction.run({ * customerId: 123, * items: [{productId: 1, qty: 2}], * paymentMethod: 'credit_card' * }); */ ``` -------------------------------- ### Logical File Organization Example Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/architecture-patterns.md Example of organizing files within directories by feature or domain for better code management and modularity. ```plaintext Repositories/ ├── UserRepository.js ├── ProductRepository.js ├── OrderRepository.js Actions/ ├── RegisterUserAction.js ├── DeleteUserAction.js ├── UpdateUserAction.js Tasks/ ├── ValidateEmailTask.js ├── HashPasswordTask.js ├── CreateUserTask.js ``` -------------------------------- ### Initial Project Structure Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/best-practices-and-guidelines.md A basic project structure with all features in a single Container. This is the recommended starting point. ```tree app/ ├── Containers/ │ └── (All features in single Container) └── Ship/ ├── Bay/ ├── Deck/ ├── Ballast/ └── Engine/ ``` -------------------------------- ### HTTP Response Example Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/data-flow-and-interactions.md Example of a JSON HTTP response sent to the client, including status, data, and metadata. ```http // HTTP Response HTTP/1.1 201 Created Content-Type: application/json { "status": 201, "data": { "id": 1, "name": "John Doe", "email": "john@example.com", "createdAt": "2024-01-15T10:30:00Z" }, "meta": { "message": "User registered successfully", "timestamp": "2024-01-15T10:30:00Z" } } ``` -------------------------------- ### Web Route Example Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/api-reference/main-components.md Defines a web endpoint to display a user profile. It maps a GET request to '/users/:id' to the profileController's show function, with web.auth middleware applied. ```javascript router.get('/users/:id', [web.auth, profileController.show]); ``` -------------------------------- ### Web Controller Example Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/api-reference/main-components.md Illustrates a basic web controller that handles product editing. It receives request data, calls an action, and renders a view. ```javascript class EditProductController { constructor(editProductAction) { this.editProductAction = editProductAction; } async handle(request) { // Validate authorization (done by Request class) // Read request data const productData = { id: request.params.id, name: request.body.name, price: request.body.price }; // Call Action const product = await this.editProductAction.run(productData); // Render View return view('products.edit', { product }); } } ``` -------------------------------- ### CLI Route Example Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/api-reference/main-components.md Defines a command-line interface command for database seeding. It maps the 'seed:users' command to the seedController's run function. ```javascript command('seed:users', seedController.run); ``` -------------------------------- ### Define API Route and Request Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/data-flow-and-interactions.md Defines a POST route for creating users and shows an example incoming request with headers and body. ```javascript // routes/api.js router.post('/users', userController.create); // request POST /users HTTP/1.1 Content-Type: application/json Authorization: Bearer token123 { "name": "John Doe", "email": "john@example.com", "password": "secret123" } ``` -------------------------------- ### API Controller Example Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/api-reference/main-components.md Demonstrates an API Controller for listing products. It reads query parameters for filtering, calls a listProductsAction, and transforms the results using a productTransformer before returning a JSON response. ```javascript class ListProductsController { constructor(listProductsAction, productTransformer) { this.listProductsAction = listProductsAction; this.productTransformer = productTransformer; } async handle(request) { // Read query parameters const filters = { category: request.query.category, minPrice: request.query.minPrice, maxPrice: request.query.maxPrice }; // Call Action const products = await this.listProductsAction.run(filters); // Transform and return response return { status: 200, data: products.map(p => this.productTransformer.transform(p)) }; } } ``` -------------------------------- ### Post Policy Interface Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/types.md Example of a specific policy interface for 'Post' resources. ```typescript interface PostPolicy extends Policy { view(user: User, post: Post): Promise; edit(user: User, post: Post): Promise; delete(user: User, post: Post): Promise; publish(user: User, post: Post): Promise; } ``` -------------------------------- ### Observer/Event Pattern Example Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/architecture-patterns.md Shows the Observer/Event pattern for decoupling event publishers and subscribers. Use for asynchronous communication and event-driven architectures. ```javascript // Event Publisher notifies Subscribers eventDispatcher.subscribe('user.registered', handler); eventDispatcher.dispatch({ name: 'user.registered' }); ``` -------------------------------- ### Action-Task Pipeline Example Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/architecture-patterns.md Illustrates how an Action orchestrates a series of Tasks in a pipeline. Each Task processes data from the previous one, suitable for sequential business logic execution. ```javascript class PlaceOrderAction { async run(orderData) { let data = orderData; // Pipeline: data flows through each Task data = await task1.run(data); // Validate data = await task2.run(data); // Calculate data = await task3.run(data); // Process data = await task4.run(data); // Persist return data; } } ``` -------------------------------- ### Focused Controller Structure Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/best-practices-and-guidelines.md Controllers should be responsible for three things: getting request data, calling an action, and building the response. This example demonstrates a well-structured controller. ```javascript class CreateProductController { constructor(createProductRequest, createProductAction, productTransformer) { this.createProductRequest = createProductRequest; this.createProductAction = createProductAction; this.productTransformer = productTransformer; } async handle(createProductRequest) { // 1. Get request data const productData = createProductRequest.all(); // 2. Call Action const product = await this.createProductAction.run(productData); // 3. Build response return { status: 201, data: await this.productTransformer.transform(product) }; } } ``` -------------------------------- ### Facade Pattern Example Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/architecture-patterns.md Implements the Facade pattern to provide a simplified interface to a complex subsystem. Useful for abstracting intricate operations like order placement. ```javascript class OrderServiceFacade { async place(orderData) { // Coordinates multiple Services return await placeOrderAction.run(orderData); } } ``` -------------------------------- ### HTTP Route Example (API) Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/api-reference/main-components.md Defines an API endpoint for user registration. It maps a POST request to '/auth/register' to the authController's register function. Middleware can be included for validation or authentication. ```javascript router.post('/auth/register', [authController.register]); ``` -------------------------------- ### Action with Sequential Tasks Source: https://github.com/mahmoudz/porto/blob/master/docs/docs/Components/Main Components Principles/Actions.md An example of an Action class that defines a 'run' method returning an array of Tasks to be executed sequentially. This follows the pipeline design pattern. ```javascript class MyAction { public function run() { return [MyTask1, MyTask2, MyTask3]]; } } ``` -------------------------------- ### Advanced Action Example for Product Listing Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/api-reference/main-components.md An advanced action demonstrating how to chain multiple tasks for filtering, sorting, and paginating products based on request parameters. Includes error handling for the entire operation. ```javascript class ListProductsAction { constructor( getProductsTask, filterProductsTask, sortProductsTask, paginateProductsTask ) { this.getProductsTask = getProductsTask; this.filterProductsTask = filterProductsTask; this.sortProductsTask = sortProductsTask; this.paginateProductsTask = paginateProductsTask; } async run(filterRequest) { try { // Get all products let products = await this.getProductsTask.run(); // Apply filters if (filterRequest.filters) { products = await this.filterProductsTask.run({ products, filters: filterRequest.filters }); } // Apply sorting if (filterRequest.sort) { products = await this.sortProductsTask.run({ products, sortBy: filterRequest.sort }); } // Apply pagination const result = await this.paginateProductsTask.run({ products, page: filterRequest.page, limit: filterRequest.limit }); return result; } catch (exception) { throw new ListProductsFailedException(exception.message); } } } ``` -------------------------------- ### Authentication Middleware Example Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/data-flow-and-interactions.md An example of an authentication middleware that extracts and validates a JWT token from the Authorization header. It attaches the validated user to the request object. ```javascript // Authentication Middleware async function authMiddleware(request, next) { const token = request.headers.authorization?.split(' ')[1]; if (!token) { throw new UnauthorizedException('No token provided'); } const user = await tokenValidator.validate(token); request.user = user; return next(request); } ``` -------------------------------- ### Test Factory Usage Example Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/architecture-patterns.md Demonstrates using test factories to create consistent test data for integration or functional tests, such as creating users and products before testing an action. ```javascript describe('CreateOrderAction', () => { async test() { const user = await userFactory.create(); const products = await productFactory.createMany(3); const order = await createOrderAction.run({ customerId: user.id, items: products }); expect(order.customerId).toBe(user.id); } }); ``` -------------------------------- ### Builder Pattern Example Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/architecture-patterns.md Illustrates the Builder pattern for constructing complex objects like Orders. Use when object creation involves many steps or optional parameters. ```javascript class OrderBuilder { addItem(product, quantity) { ... } setShippingAddress(address) { ... } setBillingAddress(address) { ... } build() { return new Order(...) } } ``` -------------------------------- ### Template Method Pattern Example Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/architecture-patterns.md Illustrates the Template Method pattern for defining a standard workflow with abstract steps. Use to enforce a skeleton algorithm while allowing subclasses to customize specific steps. ```javascript abstract class BaseAction { async run(data) { this.validate(data); const result = this.execute(data); this.log(result); return result; } abstract execute(data); } ``` -------------------------------- ### Standard Command Structure for CLI Tasks Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/api-reference/optional-components.md Defines the structure for a command-line interface command, including signature, description, and a handle method for execution. This example seeds users into the database. ```javascript class SeedUsersCommand { constructor(createUserTask) { this.createUserTask = createUserTask; } // Command signature get signature() { return 'seed:users {--count=100}'; } // Command description get description() { return 'Seed database with sample users'; } async handle() { const count = this.option('count'); for (let i = 1; i <= count; i++) { const user = await this.createUserTask.run({ name: `User ${i}`, email: `user${i}@example.com`, password: 'password123' }); this.info(`User ${user.id} created`); } this.info(`Seeded ${count} users successfully`); } } ``` -------------------------------- ### Event-Driven Communication: Publisher Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/architecture-patterns.md An example of a Publisher Container dispatching an event when a specific action occurs, such as user registration. This facilitates asynchronous communication. ```javascript // Publisher Container class UserRegisteredPublisher { async publish(user) { await eventDispatcher.dispatch({ name: 'user.registered', data: user }); } } ``` -------------------------------- ### View Template Data Binding Examples Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/api-reference/main-components.md Illustrates common data binding directives used in view templates for variable rendering, conditional logic, loops, and layout inheritance. ```html {{ variableName }} @if(condition)

Content shown if condition is true

@else

Content shown if condition is false

@endif @foreach(item in items)
  • {{ item.name }}
  • @endforeach @extends('layouts.app') @section('content') @endsection ``` -------------------------------- ### Chain of Responsibility Pattern Example Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/architecture-patterns.md Demonstrates the Chain of Responsibility pattern for sequential middleware processing. Suitable for handling requests through a pipeline of handlers. ```javascript class MiddlewareChain { async process(request) { for (const middleware of this.middlewares) { request = await middleware.handle(request); } return request; } } ``` -------------------------------- ### API Controller for Get Product Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/api-reference/main-components.md Handles requests to retrieve a single product, fetching it using an action and transforming it for the response. Ensure the GetProductAction and ProductTransformer are correctly injected. ```javascript class GetProductController { constructor(getProductAction, productTransformer) { this.getProductAction = getProductAction; this.productTransformer = productTransformer; } async handle(request) { const product = await this.getProductAction.run(request.params.id); return { status: 200, data: await this.productTransformer.transform(product) }; } } ``` -------------------------------- ### Avoid Storing Plaintext Passwords Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/best-practices-and-guidelines.md This example demonstrates an insecure practice of storing passwords in plaintext. It is crucial to avoid this to prevent security breaches. ```javascript class CreateUserTask { async run(userData) { return await User.create({ name: userData.name, email: userData.email, password: userData.password // INSECURE! }); } } ``` -------------------------------- ### Advanced Repository Example with Complex Filtering Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/api-reference/optional-components.md An advanced repository demonstrating complex filtering, bulk operations, aggregation, and relationship handling. Useful for intricate data retrieval and manipulation scenarios. ```javascript class ProductRepository { constructor(productModel) { this.model = productModel; } // Complex filtering async searchWithFilters(filters) { let query = this.model; if (filters.category) { query = query.where('category_id', filters.category); } if (filters.minPrice) { query = query.where('price', '>=', filters.minPrice); } if (filters.maxPrice) { query = query.where('price', '<=', filters.maxPrice); } if (filters.search) { query = query.where('name', 'like', `%${filters.search}%`) .orWhere('description', 'like', `%${filters.search}%`); } if (filters.inStock) { query = query.whereHas('inventory', (q) => { q.where('quantity', '>', 0); }); } return await query.with(['category', 'tags', 'images']).get(); } // Bulk operations async bulkCreate(products) { return await this.model.createMany(products); } // Aggregation queries async getAveragePriceByCategory() { return await this.model .groupBy('category_id') .select('category_id') .selectRaw('AVG(price) as average_price') .get(); } // Complex relationships async getTopProductsWithReviews(limit = 10) { return await this.model .with(['reviews', 'category']) .orderBy('reviews_count', 'desc') .limit(limit) .get(); } } ``` -------------------------------- ### Register User Action Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/data-flow-and-interactions.md Orchestrates tasks to register a new user, including email validation, password hashing, user creation, preference setup, and welcome email sending. Handles duplicate email exceptions. ```javascript class RegisterUserAction { constructor( validateEmailTask, hashPasswordTask, createUserTask, createUserPreferencesTask, sendWelcomeEmailTask ) { this.validateEmailTask = validateEmailTask; this.hashPasswordTask = hashPasswordTask; this.createUserTask = createUserTask; this.createUserPreferencesTask = createUserPreferencesTask; this.sendWelcomeEmailTask = sendWelcomeEmailTask; } async run(userData) { try { // Validate email not already registered await this.validateEmailTask.run(userData.email); // Hash password const hashedPassword = await this.hashPasswordTask.run( userData.password ); // Create user with hashed password const user = await this.createUserTask.run({ ...userData, password: hashedPassword }); // Create default preferences await this.createUserPreferencesTask.run(user); // Send welcome email await this.sendWelcomeEmailTask.run(user); return user; } catch (exception) { // Handle exceptions from Tasks if (exception instanceof DuplicateEmailException) { throw new RegistrationFailedException( 'Email already registered' ); } throw exception; } } } ``` -------------------------------- ### Event-Driven Communication: Subscriber Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/architecture-patterns.md An example of a Subscriber Container handling a specific event, like 'user.registered', and executing a corresponding task. This enables decoupled reactions to events. ```javascript // Subscriber Container class SendWelcomeEmailSubscriber { async handle(event) { if (event.name === 'user.registered') { await sendEmailTask.run(event.data); } } } ``` -------------------------------- ### Controller with Business Logic (Bad Practice) Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/best-practices-and-guidelines.md Controllers should not contain business logic or directly call tasks. This example shows a controller performing calculations and task execution, which should be handled by actions or tasks. ```javascript class CreateProductController { async handle(request) { const data = request.all(); // Should not have business logic const total = data.price * data.quantity; const tax = total * 0.1; const finalPrice = total + tax; // Should not call Task directly const product = await this.createProductTask.run({ ...data, finalPrice }); return { status: 201, data: product }; } } ``` -------------------------------- ### Document Complex Business Logic with Comments Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/best-practices-and-guidelines.md Provides an example of using code comments to explain non-obvious algorithms, business rules, or workarounds, enhancing code maintainability. ```javascript class CalculateShippingCostTask { async run(order) { // Free shipping only applies to orders over $100 // AND for customers in qualifying regions. // See business rule #BR-2024-001 for details. if (order.total > 100 && this.isQualifyingRegion(order)) { return 0; } return this.calculateStandardShipping(order); } } ``` -------------------------------- ### Standard Configuration Structure Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/api-reference/optional-components.md Illustrates a standard structure for configuration files, managing container-specific settings and environment-based configurations. ```javascript // Order/Configs/order.js module.exports = { // Order status constants statuses: { PENDING: 'pending', PROCESSING: 'processing', SHIPPED: 'shipped', DELIVERED: 'delivered', CANCELLED: 'cancelled' }, // Order settings maxRetryAttempts: 3, retryDelayMs: 5000, // Inventory reservations reservationTimeout: 3600, // 1 hour in seconds allowBackorders: false, // Notifications sendConfirmationEmail: true, sendShippingNotification: true, // Payment settings acceptedPaymentMethods: ['credit_card', 'paypal', 'bank_transfer'], requirePaymentUpfront: false }; ``` -------------------------------- ### Exception Hierarchy Example Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/architecture-patterns.md Defines a hierarchical structure for exceptions, categorizing errors from validation to system-level issues. ```plaintext Exception ├── ValidationException │ ├── DuplicateEmailException │ └── InvalidPasswordException ├── AuthorizationException │ └── UnauthorizedAccessException ├── BusinessLogicException │ ├── InsufficientInventoryException │ └── PaymentProcessingException └── SystemException ├── DatabaseException └── ExternalServiceException ``` -------------------------------- ### Configuration Usage in a Task Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/api-reference/optional-components.md Demonstrates how to inject and use configuration settings within a task class. The configuration is retrieved during initialization and used for validation and setting default values. ```javascript class PlaceOrderTask { constructor(configService) { this.config = configService.get('order'); } async run(orderData) { // Use configuration if (!this.config.acceptedPaymentMethods.includes(orderData.paymentMethod)) { throw new InvalidPaymentMethodException( `Payment method not supported` ); } // Create order with status from config return await Order.create({ ...orderData, status: this.config.statuses.PENDING }); } } ``` -------------------------------- ### Ignoring Exceptions in Actions (Anti-pattern) Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/best-practices-and-guidelines.md An example of an Action that swallows exceptions, which is an anti-pattern as it hides bugs. All exceptions should be handled or propagated. ```javascript class RegisterUserAction { async run(userData) { try { await this.validateEmailTask.run(userData.email); return await this.createUserTask.run(userData); } catch (exception) { // Swallowing exceptions hides bugs return null; } } } ``` -------------------------------- ### Implement Pagination for Lists Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/best-practices-and-guidelines.md Demonstrates implementing pagination to efficiently retrieve data, contrasting with loading all records which can lead to performance issues. ```javascript class ListProductsAction { async run(filters) { return await this.productRepository.paginate( filters.page || 1, filters.limit || 15 ); } } ``` ```javascript class ListProductsAction { async run(filters) { // Loads entire table into memory return await Product.all(); } } ``` -------------------------------- ### Single Responsibility Task Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/best-practices-and-guidelines.md A task should perform a single, well-defined operation. This example shows a task solely responsible for hashing a password. ```javascript class HashPasswordTask { async run(plainPassword) { if (!plainPassword) { throw new InvalidPasswordException('Password required'); } return await this.hashService.hash(plainPassword); } } ``` -------------------------------- ### Action with Complex Logic (Anti-pattern) Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/best-practices-and-guidelines.md An example of an Action containing too much complex logic, which is an anti-pattern. Business logic should be delegated to Tasks. ```javascript class PlaceOrderAction { async run(orderData) { // Too much logic in Action const inventory = await this.checkInventory(orderData.items); if (!inventory) throw new Error('Out of stock'); const total = orderData.items.reduce((sum, item) => { return sum + (item.price * item.quantity); }, 0); // Tax calculation const tax = total * 0.1; const finalTotal = total + tax; // ... and so on } } ``` -------------------------------- ### Controller Action Execution Logic Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/data-flow-and-interactions.md Demonstrates the 'create' action within a UserController, showing how to access validated request data, run a business logic action, and transform the result for the response. ```javascript async create(registerUserRequest) { try { // 1. Read request data const userData = registerUserRequest.all(); // 2. Call Action const user = await this.registerUserAction.run(userData); // 3. Build response return { status: 201, data: await userTransformer.transform(user) }; } catch (exception) { // Framework handles exception throw exception; } } ``` -------------------------------- ### JavaScript Actionable Exception Messages Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/best-practices-and-guidelines.md Provide helpful and actionable messages within exception constructors. This guides the user or developer on how to resolve the issue. ```javascript throw new InvalidPasswordException( 'Password must be at least 8 characters, ' + 'contain uppercase, lowercase, and numbers' ); ``` -------------------------------- ### Typical Container Directory Structure Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/api-reference/layers.md Illustrates the standard directory structure for a Container within the Porto framework, showing various subdirectories for different code types and functionalities. ```plaintext Section/ ├── ContainerA/ │ ├── Actions/ │ ├── Tasks/ │ ├── Models/ │ ├── Value-Objects/ │ ├── Events-Publisher/ │ ├── Events-Subscriber/ │ ├── Cron-Jobs/ │ ├── Exceptions/ │ ├── Policies/ │ ├── Contracts/ │ ├── Configs/ │ ├── Mails/ │ ├── Data/ │ │ ├── Migrations/ │ │ ├── Seeders/ │ │ ├── Factories/ │ │ ├── Criteria/ │ │ ├── Repositories/ │ │ ├── Validators/ │ │ ├── Transporters/ │ │ └── Rules/ │ ├── Tests/ │ │ ├── Unit/ │ │ ├── Integration/ │ │ ├── Performance/ │ │ └── Security/ │ └── UI/ │ ├── API/ │ │ ├── Routes/ │ │ ├── Controllers/ │ │ ├── Requests/ │ │ ├── Transformers/ │ │ └── Tests/ │ ├── WEB/ │ │ ├── Routes/ │ │ ├── Controllers/ │ │ ├── Requests/ │ │ ├── Views/ │ │ └── Tests/ │ └── CLI/ │ ├── Routes/ │ ├── Commands/ │ └── Tests/ └── ContainerB/ └── [same structure as ContainerA] ``` -------------------------------- ### Task Orchestration by Action Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/best-practices-and-guidelines.md Actions should orchestrate tasks, ensuring tasks remain independent. This example shows an action calling a validation task and a creation task. ```javascript class ValidatePaymentTask { async run(payment) { // Validate payment data return payment; } } class PlaceOrderAction { async run(orderData) { // Action orchestrates Tasks await this.validatePaymentTask.run(orderData.payment); return await this.createOrderTask.run(orderData); } } ``` -------------------------------- ### Create Products Table Migration with Indexes and Foreign Keys Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/api-reference/optional-components.md Defines the schema for the 'products' table, including indexes and a foreign key to the 'categories' table. Use this for complex table structures with relationships. ```javascript class CreateProductsTable { up() { return this.schema.createTable('products', (table) => { table.increments('id'); table.string('name').notNullable().index(); table.text('description').nullable(); table.decimal('price', 10, 2).notNullable(); table.string('sku').unique().notNullable(); // Foreign key table.integer('category_id').unsigned(); table.foreign('category_id') .references('id') .on('categories') .onDelete('cascade'); // Indexes table.index('category_id'); table.index('created_at'); table.timestamps(); }); } down() { return this.schema.dropTable('products'); } } ``` -------------------------------- ### Standard Action Structure Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/api-reference/main-components.md Illustrates a standard action class with a constructor and a run method that orchestrates multiple tasks sequentially. Handles expected exceptions like DuplicateEmailException. ```javascript class RegisterUserAction { constructor( validateEmailTask, createUserTask, sendWelcomeEmailTask, createUserPreferencesTask ) { this.validateEmailTask = validateEmailTask; this.createUserTask = createUserTask; this.sendWelcomeEmailTask = sendWelcomeEmailTask; this.createUserPreferencesTask = createUserPreferencesTask; } async run(userData) { try { // Validate email doesn't exist await this.validateEmailTask.run(userData.email); // Create user const user = await this.createUserTask.run(userData); // Send welcome email await this.sendWelcomeEmailTask.run(user); // Create user preferences await this.createUserPreferencesTask.run(user); return user; } catch (exception) { // Handle expected exceptions if (exception instanceof DuplicateEmailException) { throw new UserRegistrationFailedException( 'Email already registered' ); } // Re-throw unexpected exceptions throw exception; } } } ``` -------------------------------- ### Factory Usage in Tests Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/api-reference/optional-components.md Demonstrates how to use a UserFactory within a test case to create a user and then test a registration endpoint with an existing email. ```javascript class RegisterUserTest { async testRegistration() { const userFactory = new UserFactory(); const existingUser = await userFactory.create(); // Test with existing email const response = await this.post('/auth/register', { name: 'New User', email: existingUser.email, // Already exists password: 'password123' }); expect(response.status).toBe(409); } } ``` -------------------------------- ### Basic Task Structure Source: https://github.com/mahmoudz/porto/blob/master/docs/docs/Components/Main Components Principles/Tasks.md Illustrates the fundamental structure of a Task class with a 'run' method for business logic. ```javascript class MyTask { public function run() { // your business logic } } ``` -------------------------------- ### Create Database Indexes Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/best-practices-and-guidelines.md Illustrates how to add indexes to database columns to improve query performance, specifically for frequently queried or joined fields. ```javascript class CreateProductsTable { async up() { return this.schema.createTable('products', (table) => { table.increments('id'); table.string('name').notNullable().index(); table.integer('category_id').index(); table.timestamp('created_at').index(); }); } } ``` -------------------------------- ### Standard Contract Structure for Payment Gateway Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/api-reference/optional-components.md Defines a contract for payment gateways with methods for charging, refunding, and verifying payments. Includes an example of a StripeGateway implementation extending this contract. ```javascript // Contract/PaymentGatewayContract.js class PaymentGatewayContract { // Charge payment async charge(chargeData) { throw new Error('charge() must be implemented'); } // Refund payment async refund(transactionId, amount) { throw new Error('refund() must be implemented'); } // Verify payment status async verify(transactionId) { throw new Error('verify() must be implemented'); } } // PaymentGateways/StripeGateway.js class StripeGateway extends PaymentGatewayContract { constructor(stripeClient) { super(); this.client = stripeClient; } async charge(chargeData) { return await this.client.charges.create({ amount: chargeData.amount, currency: chargeData.currency, source: chargeData.source }); } // ... other methods } ``` -------------------------------- ### JavaScript Model with Business Logic (Anti-pattern) Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/best-practices-and-guidelines.md Avoid placing business logic, such as calculating discounts or applying promo codes, directly within model methods. This logic should be handled in separate service or task classes. ```javascript class Product { static tableName = 'products'; async calculateDiscount(discountPercent) { // Business logic should be in Task, not Model this.price = this.price * (1 - discountPercent / 100); await this.save(); } async applyPromoCode(code) { // Complex business logic should not be in Model const promo = await Promotion.find(code); if (!promo) throw new Error('Invalid promo'); if (promo.minAmount > this.price) throw new Error('Min amount not met'); this.promoDiscount = promo.discount; await this.save(); } } ``` -------------------------------- ### Asynchronous Task Execution (Sequential and Parallel) Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/data-flow-and-interactions.md Illustrates how to execute asynchronous tasks. Use `await` for sequential execution where one task depends on the previous one. Use `Promise.all` for parallel execution when tasks are independent. ```javascript // Tasks run sequentially (await each) const result1 = await task1.run(data); const result2 = await task2.run(result1); const result3 = await task3.run(result2); ``` ```javascript // If tasks are independent, run in parallel const [inventory, pricing, tax] = await Promise.all([ inventoryTask.run(items), pricingTask.run(items), taxTask.run(items) ]); ``` -------------------------------- ### Pipeline Pattern for Actions Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/best-practices-and-guidelines.md Demonstrates the pipeline pattern for organizing tasks within an Action. This approach keeps Actions clean and readable by chaining tasks sequentially. ```javascript class PlaceOrderAction { async run(orderData) { let data = orderData; data = await this.validateInventoryTask.run(data); data = await this.calculateTotalTask.run(data); data = await this.processPaymentTask.run(data); data = await this.createOrderTask.run(data); return data; } } ``` -------------------------------- ### Repository Injection in Task Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/api-reference/optional-components.md Demonstrates how to inject a repository into a task class for data retrieval. This pattern promotes dependency injection and testability. ```javascript class GetProductTask { constructor(productRepository) { this.repository = productRepository; } async run(productId) { const product = await this.repository.findWithRelations(productId, [ 'category', 'images', 'reviews' ]); if (!product) { throw new ProductNotFoundException( `Product ${productId} not found` ); } return product; } } ``` -------------------------------- ### Action Calling Multiple Tasks in Sequence Source: https://github.com/mahmoudz/porto/blob/master/docs/docs/Components/Main Components Principles/Tasks.md Demonstrates how an Action can orchestrate a sequence of Tasks to process data. ```javascript Action1 = [MyTask1, MyTask2, MyTask3] ``` -------------------------------- ### Standard Controller Structure Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/api-reference/main-components.md Illustrates a typical Controller class structure in Porto. It includes a constructor for dependency injection and a handle method that reads request data, calls an Action, and builds a response. ```javascript class RegisterUserController { // Constructor for dependency injection constructor(registerUserAction) { this.registerUserAction = registerUserAction; } // Handler method async handle(request) { // 1. Read request data const userData = { name: request.body.name, email: request.body.email, password: request.body.password }; // 2. Call Action const user = await this.registerUserAction.run(userData); // 3. Build response return { status: 201, message: 'User registered successfully', data: user }; } } ``` -------------------------------- ### Action with Sub-Action (JavaScript) Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/data-flow-and-interactions.md Demonstrates an Action that includes a Sub-Action to group related Tasks, followed by another Task. Use this for modularizing complex logic within an Action. ```javascript deletePostAction.run(deleteRequest) ├─→ authorizeUserSubAction.run(token, ['post:delete']) │ ├─→ validateTokenTask.run(token) │ ├─→ getUserTask.run(userId) │ └─→ checkPermissionsTask.run(user, permissions) └─→ deletePostTask.run(postId) ``` -------------------------------- ### Create User Task Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/data-flow-and-interactions.md Creates a new user record in the database using the provided user data. ```javascript // Task 3: Create User class CreateUserTask { constructor(userRepository) { this.userRepository = userRepository; } async run(userData) { const user = await this.userRepository.create({ name: userData.name, email: userData.email, password: userData.password }); return user; } } ``` -------------------------------- ### Use Factories for Test Data Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/best-practices-and-guidelines.md Demonstrates creating test data using factories for cleaner and more maintainable tests. This approach is preferred over inline data creation. ```javascript test('can create order', async () => { const user = await userFactory.create(); const products = await productFactory.createMany(3); const order = await createOrderAction.run({ userId: user.id, items: products }); expect(order.userId).toBe(user.id); }); ``` ```javascript test('can create order', async () => { // Too much setup code const user = await User.create({ name: 'Test', email: 'test@test.com', password: 'secret' }); const products = []; for (let i = 0; i < 3; i++) { products.push(await Product.create({ name: `Product ${i}`, price: 100, // ... more fields })); } // ... test logic }); ``` -------------------------------- ### Exception Handling in Action Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/api-reference/main-components.md Demonstrates how to handle specific exceptions within an action, catching known errors and re-throwing unexpected ones. Use `instanceof` to check for specific exception types. ```javascript class RegisterUserAction { constructor(validateEmailTask, createUserTask) { this.validateEmailTask = validateEmailTask; this.createUserTask = createUserTask; } async run(userData) { try { await this.validateEmailTask.run(userData.email); return await this.createUserTask.run(userData); } catch (exception) { if (exception instanceof DuplicateEmailException) { throw new UserRegistrationFailedException( exception.message ); } // Re-throw unexpected exceptions throw exception; } } } ``` -------------------------------- ### User Controller Structure Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/data-flow-and-interactions.md Shows the basic structure of a UserController, including dependency injection for request handling and action execution. ```javascript // Request arrives at Controller class UserController { constructor(registerUserRequest, registerUserAction) { this.registerUserRequest = registerUserRequest; this.registerUserAction = registerUserAction; } async create(request) { // Step 3a: Controller reads request data // ... } } ``` -------------------------------- ### Test Error Cases Effectively Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/best-practices-and-guidelines.md Illustrates how to properly test for exceptions and error conditions, contrasting it with only testing the happy path. ```javascript test('throws if email already exists', async () => { const user = await userFactory.create(); expect(() => registerUserAction.run({ name: 'Other User', email: user.email, password: 'secret123' }) ).rejects.toThrow(RegistrationFailedException); }); ``` ```javascript test('can register user', async () => { const user = await registerUserAction.run({ name: 'John', email: 'john@example.com', password: 'secret123' }); expect(user.id).toBeDefined(); // Only tests success case }); ``` -------------------------------- ### Value Object Usage in Models Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/api-reference/optional-components.md Demonstrates how to use Value Objects like Money and Address when defining model structures. This ensures data integrity and expressiveness. ```javascript class Order { constructor(data) { this.id = data.id; this.customerId = data.customerId; this.total = new Money(data.total, data.currency); this.shippingAddress = new Address( data.street, data.city, data.state, data.zipCode, data.country ); } } ``` -------------------------------- ### Comprehensive Exception Handling in Actions Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/best-practices-and-guidelines.md Shows how to handle expected exceptions within an Action, re-throwing specific business exceptions and letting the framework handle unexpected ones. ```javascript class RegisterUserAction { async run(userData) { try { await this.validateEmailTask.run(userData.email); return await this.createUserTask.run(userData); } catch (exception) { if (exception instanceof DuplicateEmailException) { throw new RegistrationFailedException('Email already registered'); } if (exception instanceof InvalidPasswordException) { throw new RegistrationFailedException(exception.message); } // Unexpected exception - let framework handle throw exception; } } } ``` -------------------------------- ### Standard Repository Structure Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/api-reference/optional-components.md A standard repository class demonstrating common CRUD operations and query methods. Use this as a template for abstracting data access logic. ```javascript class UserRepository { constructor(userModel) { this.model = userModel; } // Find by primary key async findById(id) { return await this.model.find(id); } // Find by email async findByEmail(email) { return await this.model.where('email', email).first(); } // Create new record async create(data) { return await this.model.create(data); } // Update record async update(id, data) { return await this.model.find(id).update(data); } // Delete record async delete(id) { return await this.model.find(id).delete(); } // Get paginated results async paginate(page = 1, limit = 15) { return await this.model .paginate(page, limit); } // Find with relationships async findWithRelations(id, relations = []) { let query = this.model; for (const relation of relations) { query = query.with(relation); } return await query.find(id); } // Custom query async findActive(limit = 10) { return await this.model .where('is_active', true) .limit(limit) .get(); } } ``` -------------------------------- ### User Repository Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/data-flow-and-interactions.md Abstracts database operations for the User model, including finding a user by email and creating a new user. ```javascript // Repository abstracts database access class UserRepository { async findByEmail(email) { return await User.where('email', email).first(); } async create(data) { return await User.create(data); } } ``` -------------------------------- ### Policy Usage in Controller for Authorization Checks Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/api-reference/optional-components.md Demonstrates how to integrate policy checks within a controller. Before executing an action, the controller verifies authorization using the policy's methods, throwing an exception if unauthorized. ```javascript class EditPostController { constructor(editPostAction, postPolicy) { this.editPostAction = editPostAction; this.postPolicy = postPolicy; } async handle(editPostRequest) { const post = await Post.find(editPostRequest.params.id); // Check authorization const canEdit = await this.postPolicy.edit(editPostRequest.user(), post); if (!canEdit) { throw new UnauthorizedException('You cannot edit this post'); } return await this.editPostAction.run(editPostRequest.all()); } } ``` -------------------------------- ### Application Configuration Types Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/types.md Defines interfaces for application, database, cache, and queue configurations. ```typescript interface AppConfig { name: string; environment: 'development' | 'staging' | 'production'; debug: boolean; timezone: string; charset: string; url: string; } interface DatabaseConfig { driver: 'mysql' | 'postgresql' | 'sqlite' | 'sqlserver'; host: string; port: number; database: string; username: string; password: string; charset: string; prefix?: string; } interface CacheConfig { driver: 'file' | 'redis' | 'memcached' | 'database'; prefix: string; ttl?: number; } interface QueueConfig { driver: 'sync' | 'database' | 'redis' | 'sqs'; connection?: string; queue?: string; } ``` -------------------------------- ### Dependency Injection in Action Constructor Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/architecture-patterns.md Demonstrates Dependency Injection where components receive their dependencies via constructor parameters. This promotes loose coupling and testability. ```javascript class CreateOrderAction { constructor( validateInventoryTask, processPaymentTask, createOrderTask, notifyCustomerTask ) { this.validateInventoryTask = validateInventoryTask; this.processPaymentTask = processPaymentTask; this.createOrderTask = createOrderTask; this.notifyCustomerTask = notifyCustomerTask; } } ``` -------------------------------- ### Create Users Table Migration Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/api-reference/optional-components.md Defines the schema for the 'users' table, including basic user information, timestamps, and soft deletes. Use this to set up the initial user data structure. ```javascript class CreateUsersTable { up() { return this.schema.createTable('users', (table) => { table.increments('id'); table.string('name').notNullable(); table.string('email').unique().notNullable(); table.string('password').notNullable(); table.string('phone').nullable(); table.text('bio').nullable(); table.boolean('is_active').defaultTo(true); table.string('remember_token').nullable(); table.timestamp('email_verified_at').nullable(); table.timestamps(); table.softDeletes(); }); } down() { return this.schema.dropTable('users'); } } ``` -------------------------------- ### Component Interaction Flow Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/README.md Illustrates the sequence of events and components involved in handling an HTTP request within the Porto framework. ```text HTTP Request ↓ Route → Middleware → Controller ↓ Request (validation & authorization) ↓ Action (orchestration) ↓ Tasks (business logic) ↓ Models & Repositories (data access) ↓ Controller builds response ↓ Transformer formats for API ↓ HTTP Response ``` -------------------------------- ### Container Directory Structure Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/architecture-patterns.md Standard directory structure for all Containers, ensuring consistency and easy navigation across different modules. ```plaintext Container/ ├── Actions/ ├── Tasks/ ├── Models/ ├── Exceptions/ ├── Data/ │ └── Repositories/ └── UI/ ├── API/ ├── WEB/ └── CLI/ ``` -------------------------------- ### Product Detail View Template Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/api-reference/main-components.md Renders a detailed view of a product, including its name, image, description, price, stock status, and customer reviews. Includes a form to add the product to the cart if it's in stock. ```html @extends('layouts.app') @section('content')

    {{ product.name }}

    {{ product.name }}

    {{ product.description }}

    ${{ product.formattedPrice }}

    @if(product.inStock)
    @else

    Out of Stock

    @endif
    @if(product.reviews.length > 0)

    Customer Reviews

    @foreach(review in product.reviews)

    {{ review.author }}

    {{ review.rating }}/5

    {{ review.text }}

    @endforeach
    @endif
    @endsection ``` -------------------------------- ### Implement Caching for Expensive Operations Source: https://github.com/mahmoudz/porto/blob/master/_autodocs/best-practices-and-guidelines.md Shows how to use caching to store the results of expensive operations, reducing redundant computations and improving performance. ```javascript class GetCategoriesTask { async run() { return await cache.remember('categories', 3600, async () => { return await this.categoryRepository.all(); }); } } ```