Thank you for considering contributing to the PHP Inventory Management System! This guide will help you understand the codebase structure and development workflow.
CREATE DATABASE bd_inventario CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;USE bd_inventario;-- Create tables (see Database Schema docs for full SQL)CREATE TABLE usuarios ( id INT AUTO_INCREMENT PRIMARY KEY, nombre VARCHAR(100) NOT NULL, correo VARCHAR(100) UNIQUE NOT NULL, contraseña VARCHAR(255) NOT NULL, rol ENUM('admin', 'usuario') DEFAULT 'usuario', fecha_registro TIMESTAMP DEFAULT CURRENT_TIMESTAMP);CREATE TABLE productos ( id INT AUTO_INCREMENT PRIMARY KEY, nombre VARCHAR(200) NOT NULL, codigo VARCHAR(50) UNIQUE NOT NULL, precio DECIMAL(10,2) NOT NULL DEFAULT 0.00, stock INT NOT NULL DEFAULT 0, fecha_creacion TIMESTAMP DEFAULT CURRENT_TIMESTAMP);CREATE TABLE movimientos ( id INT AUTO_INCREMENT PRIMARY KEY, producto_id INT NOT NULL, tipo ENUM('entrada', 'salida') NOT NULL, cantidad INT NOT NULL, fecha TIMESTAMP DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (producto_id) REFERENCES productos(id) ON DELETE CASCADE);-- Create test userINSERT INTO usuarios (nombre, correo, contraseña, rol) VALUES ('Admin', '[email protected]', 'admin123', 'admin');
Functions: camelCase() or snake_case() (be consistent)
Constants: UPPER_CASE
Classes: PascalCase (if implementing OOP)
Indentation:
Use 4 spaces (not tabs)
Opening braces on same line for control structures
if (condition) { // code} else { // code}
Database Query Patterns
Current Pattern (to be improved):
$sql = "SELECT * FROM productos WHERE id=$id";$resultado = $conn->query($sql);
Recommended Pattern (use for new code):
// Prepared statements for security$stmt = $conn->prepare("SELECT * FROM productos WHERE id = ?");$stmt->bind_param("i", $id);$stmt->execute();$resultado = $stmt->get_result();
Fetching Results:
// Single row$row = $resultado->fetch_assoc();// Multiple rowswhile ($row = $resultado->fetch_assoc()) { // Process each row}
HTML/PHP Mixed Code
Good Practice:
<?php// Business logic at top$productos = $conn->query("SELECT * FROM productos");?><!-- HTML presentation below --><table><?php while ($p = $productos->fetch_assoc()) { ?> <tr> <td><?= htmlspecialchars($p['nombre']) ?></td> </tr><?php } ?></table>
-- Use meaningful column names-- Include timestamps for auditing-- Use appropriate data typesCREATE TABLE example ( id INT AUTO_INCREMENT PRIMARY KEY, name VARCHAR(200) NOT NULL, created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP);
Foreign Keys:
-- Always define relationships-- Use CASCADE carefullyFOREIGN KEY (producto_id) REFERENCES productos(id) ON DELETE CASCADE
Indexing:
-- Add indexes for frequently queried columnsCREATE INDEX idx_correo ON usuarios(correo);CREATE INDEX idx_codigo ON productos(codigo);CREATE INDEX idx_producto_fecha ON movimientos(producto_id, fecha);
// In HTML context<?= htmlspecialchars($user_input, ENT_QUOTES, 'UTF-8') ?>// In JavaScript context<script>var data = <?= json_encode($user_input, JSON_HEX_TAG | JSON_HEX_AMP) ?>;</script>// In URL context<a href="page.php?id=<?= urlencode($id) ?>">
Add this to the beginning of config/conexion.php or create a separate config/session.php:
// Secure session configurationini_set('session.cookie_httponly', 1);ini_set('session.cookie_secure', 1); // Only if using HTTPSini_set('session.cookie_samesite', 'Strict');ini_set('session.use_strict_mode', 1);session_start();// Regenerate session ID after login// Add this to auth/login.php after successful loginsession_regenerate_id(true);
Issue: Stock count doesn’t match movementsSolution: Recalculate stock from movements:
-- Audit querySELECT p.id, p.nombre, p.stock as current_stock, COALESCE(SUM(CASE WHEN m.tipo = 'entrada' THEN m.cantidad ELSE 0 END), 0) as total_entries, COALESCE(SUM(CASE WHEN m.tipo = 'salida' THEN m.cantidad ELSE 0 END), 0) as total_exits, COALESCE(SUM(CASE WHEN m.tipo = 'entrada' THEN m.cantidad ELSE -m.cantidad END), 0) as calculated_stockFROM productos pLEFT JOIN movimientos m ON p.id = m.producto_idGROUP BY p.id;-- Repair query (use cautiously)UPDATE productos pSET p.stock = ( SELECT COALESCE(SUM(CASE WHEN m.tipo = 'entrada' THEN m.cantidad ELSE -m.cantidad END), 0) FROM movimientos m WHERE m.producto_id = p.id);
## DescriptionBrief description of changes## Type of Change- [ ] Bug fix- [ ] New feature- [ ] Security improvement- [ ] Documentation update- [ ] Code refactoring## Changes Made- List specific changes- Include file names- Mention any database modifications## Testing- Describe how you tested the changes- List test cases covered## Screenshots (if applicable)## Checklist- [ ] Code follows project style guidelines- [ ] Used prepared statements for SQL queries- [ ] Escaped all user output- [ ] Tested thoroughly- [ ] Updated documentation- [ ] No security vulnerabilities introduced