16 KiB
DevQMS Developer Get Started Guide
Table of Contents
- Project Overview
- Architecture Overview
- Core Components
- Module System
- DevExtreme Integration
- Admin-AJAX System
- Save Trigger System
- Batch Excel Operations
- Development Workflow
- Common Patterns
- Troubleshooting
Project Overview
DevQMS is a Quality Management System (QMS) built on Laravel framework with advanced features including:
- Modular Architecture: Each module (WeldLog, TestPackage, etc.) has its own Model, Controller, and View
- DevExtreme Integration: Advanced UI components for data grids, forms, and charts
- Dynamic Form System: Forms are generated dynamically based on database schema
- Excel Import/Export: Batch operations for data management
- Role-based Access Control: User permission system with different levels
- Real-time Data Processing: Save triggers for automatic data synchronization
Architecture Overview
Directory Structure
app/
├── Http/Controllers/
│ ├── AdminController.php # Main CRUD controller
│ ├── AdminAjaxController.php # AJAX request handler
│ └── SaveTrigger/ # Automatic data processing
├── DevExtreme/ # DevExtreme integration classes
├── Models/ # Eloquent models
└── Functions/ # Helper functions
resources/views/
├── admin/ # Admin panel views
│ └── type/ # Module views
├── admin-ajax/ # AJAX response views
├── components/ # Reusable components
│ ├── blocks/ # Module blocks
│ └── table/ # DataGrid components
└── guide/ # Documentation
routes/
└── web.php # Route definitions
Core Technologies
- Backend: Laravel 8+ with PHP 8+
- Frontend: DevExtreme DataGrid, jQuery, Bootstrap
- Database: MySQL with InnoDB
- File Storage: Laravel Storage with local/cloud options
- Excel Processing: Maatwebsite Excel package
Core Components
1. AdminController.php
The central controller handling all CRUD operations for modules. Key methods:
// Read operations
public function tableToJson(Request $request, string $tableName)
public function getDetail(Request $request, string $tableName, string $columnName, string $value)
// Write operations
public function insertJson(Request $request, string $tableName)
public function saveJson(Request $request, string $tableName)
public function removeJson(Request $request, string $tableName)
// Excel operations
public function importExcel(Request $request, string $tableName)
public function exportExcel(Request $request, string $tableName, string $fileName)
Important: All modules use this centralized controller - no need to create individual controllers for basic CRUD operations.
2. AdminAjaxController.php
Handles AJAX requests through view-based routing:
public function index(Request $request, string $var) {
$url = "admin-ajax.$var";
return view($url, array("request" => $request));
}
AJAX views are located in resources/views/admin-ajax/ and follow the naming pattern {action}.blade.php.
3. DevExtreme Integration
DbSet.php
Custom query builder for DevExtreme DataGrid:
$dbSet = new DbSet($mySQL, 'table_name');
$result = $dbSet->Select(['id', 'name'])
->Filter(['status' => 'active'])
->OrderBy('name')
->SkipTake(0, 10)
->AsArray();
Utils.php
Helper functions for data processing and SQL escaping.
Module System
Creating a New Module
- Create Model and Migration:
// app/Models/NewModule.php
class NewModule extends Model {
protected $table = 'new_modules';
protected $primaryKey = 'id';
public $timestamps = true;
}
- Create View Template:
// resources/views/admin/type/new-module.blade.php
<?php
use App\Models\NewModule;
$title = "New Module";
$tableName = "new_modules";
$listDatas = NewModule::orderBy("id","DESC")->paginate(setting('row_count'));
$blockGroup = [
'General Info' => [
'name',
'description',
],
'Details' => [
'status',
'created_at',
],
];
$relationDatas = [
'status' => [
'type' => 'select',
'datas' => [
'active' => 'Active',
'inactive' => 'Inactive'
]
],
];
$firstUploadFolder = 'NewModule/';
$firstUploadTitle = 'Upload Files';
?>
<div class="content">
<div class="row">
@include("admin.type.document.upload")
@include("components.blocks.module-block")
</div>
</div>
- Add to Types Table: Register the module in the admin panel's Types section with:
- Title: "New Module"
- Slug: "new-module"
- Fields: "name,description,status,created_at"
Module Template Structure
sablon4.blade.php
Base template for modules with these key variables:
$title = "Module Title"; // Page title
$tableName = "table_name"; // Database table name
$listDatas = Model::paginate(50); // Data source
$blockGroup = []; // Field grouping
$relationDatas = []; // Field type definitions
$firstUploadFolder = 'ModuleName/'; // File upload folder
$firstUploadTitle = 'Upload Title'; // Upload section title
module-block.blade.php
Handles the DataGrid integration and includes:
- Column selection
- Excel import/export
- DataGrid component
- Field type mapping
DevExtreme Integration
DataGrid Configuration
The DataGrid is configured in resources/views/components/table/datagrid.blade.php with:
var dataGrid = $("#dataGrid").dxDataGrid({
dataSource: dataSource,
keyExpr: "{{$tableName}}",
allowColumnResizing: true,
allowColumnReordering: true,
showBorders: true,
filterRow: {
visible: true
},
searchPanel: {
visible: true
},
paging: {
pageSize: 20
},
pager: {
showPageSizeSelector: true,
allowedPageSizes: [10, 20, 50, 100]
},
editing: {
mode: "popup",
allowUpdating: true,
allowAdding: true,
allowDeleting: true
}
});
Field Types
Supported field types in relationDatas:
$relationDatas = [
'text_field' => ['type' => 'text'],
'date_field' => ['type' => 'date'],
'number_field' => ['type' => 'number'],
'select_field' => [
'type' => 'select',
'datas' => ['option1' => 'Label 1', 'option2' => 'Label 2']
],
'link_field' => [
'type' => 'link-search',
'html' => '<i class="fa fa-link"></i>'
],
'decimal_field' => ['type' => 'decimal'],
'checkbox_field' => ['type' => 'checkbox']
];
Custom Validation
Add custom validation in components/table/datagrid/validation-callback/{module}/{field}.blade.php:
function validationCallback_fieldName(e) {
// Custom validation logic
if (e.value && e.value.length < 3) {
return false;
}
return true;
}
Admin-AJAX System
Creating AJAX Endpoints
- Create AJAX View:
// resources/views/admin-ajax/custom-action.blade.php
@php
$data = db('table_name')->where('condition', $request->input('value'))->get();
echo json_encode([
'status' => 'success',
'data' => $data
]);
@endphp
- Call from JavaScript:
$.ajax({
url: '/admin-ajax/custom-action',
type: 'POST',
data: {
value: 'search_value',
_token: csrf_token
},
success: function(response) {
// Handle response
}
});
Common AJAX Patterns
Batch Operations
// admin-ajax/batch-operation.blade.php
@php
$ids = $request->input('ids', []);
$operation = $request->input('operation');
foreach($ids as $id) {
db('table_name')->where('id', $id)->update(['status' => $operation]);
}
echo json_encode(['status' => 'success', 'processed' => count($ids)]);
@endphp
Data Export
// admin-ajax/export-data.blade.php
@php
$query = $request->input('query');
$data = DB::select($query);
$filename = 'export_' . date('Y-m-d_H-i-s') . '.xlsx';
Excel::store(new ExportExcel($data), $filename);
echo json_encode(['status' => 'success', 'file' => $filename]);
@endphp
Save Trigger System
Overview
Save triggers automatically process data changes and maintain data consistency across related tables.
Trigger Structure
// app/Http/Controllers/SaveTrigger/{table_name}.php
<?php
use App\Models\RelatedModel;
$id = $request['key'];
$data = db($tableName)->where("id", $id)->first();
// Detect changed fields
$changedFields = [];
foreach ($data as $key => $value) {
if (isset($beforeData->$key) && $beforeData->$key != $value) {
$changedFields[] = $key;
}
}
// Execute related updates
if (in_array('status', $changedFields)) {
// Update related records
RelatedModel::where('parent_id', $id)
->update(['status' => $data->status]);
}
Common Trigger Patterns
Status Synchronization
// Update related records when status changes
if (in_array('status', $changedFields)) {
$newStatus = $data->status;
// Update child records
db('child_table')->where('parent_id', $id)
->update(['status' => $newStatus]);
// Update summary tables
$summary = db('summary_table')->where('parent_id', $id)->first();
if ($summary) {
$summary->update(['last_status' => $newStatus]);
}
}
Calculated Fields
// Recalculate totals when related fields change
if (array_intersect(['quantity', 'unit_price'], $changedFields)) {
$total = $data->quantity * $data->unit_price;
db($tableName)->where('id', $id)
->update(['total' => $total]);
}
Cross-Table Updates
// Update related tables when key fields change
if (in_array('project_id', $changedFields)) {
$newProjectId = $data->project_id;
// Update all related records
db('related_table')->where('parent_id', $id)
->update(['project_id' => $newProjectId]);
}
Batch Excel Operations
Import Process
- File Upload: Users upload Excel files through the interface
- Validation: System validates data format and required fields
- Processing: Data is processed in batches to handle large files
- Save Triggers: Each row triggers the appropriate save triggers
- Progress Tracking: Real-time progress updates via AJAX
Export Process
- Query Building: Dynamic SQL query based on filters
- Data Retrieval: Fetch data with pagination for large datasets
- Formatting: Apply formatting and styling
- File Generation: Create Excel file with multiple sheets if needed
- Download: Provide download link to user
Implementation Example
// Batch Excel Import
public function importExcel(Request $request, string $tableName) {
$file = $request->file('file');
$import = new ImportExcel($tableName);
Excel::import($import, $file);
return response()->json([
'status' => 'success',
'imported' => $import->getRowCount()
]);
}
// Batch Excel Export
public function exportExcel(Request $request, string $tableName, string $fileName = "") {
$query = $request->input('query');
$data = DB::select($query);
$fileName = $fileName ?: $tableName . '_' . date('Y-m-d_H-i-s');
return Excel::download(new ExportExcel($data), $fileName . '.xlsx');
}
Development Workflow
1. Environment Setup
# Clone repository
git clone [repository-url]
cd dev
# Install dependencies
composer install
npm install
# Configure environment
cp .env.example .env
php artisan key:generate
# Run migrations
php artisan migrate
# Start development server
php artisan serve
2. Creating New Features
-
Database Changes:
php artisan make:migration create_new_table php artisan migrate -
Model Creation:
php artisan make:model NewModel -
View Template:
- Copy
sablon4.blade.phpas base - Customize variables and field groups
- Add to Types table
- Copy
-
Save Triggers (if needed):
- Create trigger file in
SaveTrigger/ - Define change detection logic
- Implement cross-table updates
- Create trigger file in
3. Testing
# Run tests
php artisan test
# Test specific module
php artisan test --filter=NewModuleTest
4. Deployment
# Production deployment
composer install --optimize-autoloader --no-dev
php artisan config:cache
php artisan route:cache
php artisan view:cache
Common Patterns
1. Dynamic Field Handling
// Get field types from database
$fieldTypes = [];
foreach($columns as $column) {
$fieldTypes[$column] = table_column_type($tableName, $column);
}
// Apply custom field types
$relationDatas = [
'status' => ['type' => 'select', 'datas' => $statusOptions],
'date_field' => ['type' => 'date'],
];
2. Permission Checking
// Check user permissions
if (!isAuth($tableName, 'write')) {
return response()->json(['error' => 'Permission denied'], 403);
}
// Role-based access
if (!isAdmin()) {
// Limited access logic
}
3. Data Validation
// Custom validation in save triggers
$requiredFields = ['name', 'email', 'status'];
foreach($requiredFields as $field) {
if (empty($data->$field)) {
throw new Exception("Field $field is required");
}
}
4. Error Handling
try {
// Database operation
DB::transaction(function() use ($data) {
// Complex operations
});
} catch (Exception $e) {
Log::error('Operation failed', [
'error' => $e->getMessage(),
'data' => $data
]);
return response()->json(['error' => 'Operation failed'], 500);
}
Troubleshooting
Common Issues
-
DataGrid Not Loading:
- Check browser console for JavaScript errors
- Verify AJAX endpoint returns valid JSON
- Check network tab for failed requests
-
Save Triggers Not Working:
- Verify trigger file exists in
SaveTrigger/ - Check database permissions
- Review error logs
- Verify trigger file exists in
-
Excel Import Failures:
- Validate Excel file format
- Check column mappings
- Verify required fields are present
-
Permission Errors:
- Check user level in database
- Verify module permissions
- Review middleware configuration
Debug Tools
-
Laravel Telescope (if enabled):
/telescope -
Database Logging:
DB::enableQueryLog(); // ... operations dd(DB::getQueryLog()); -
DevExtreme Debug:
// Enable DevExtreme debug mode DevExpress.config({ debug: true });
Performance Optimization
-
Database Indexing:
CREATE INDEX idx_table_column ON table_name(column_name); -
Query Optimization:
// Use eager loading for relationships $data = Model::with('relation')->get(); -
Caching:
// Cache frequently accessed data $data = Cache::remember('key', 3600, function() { return Model::all(); });
This guide provides a comprehensive overview of the DevQMS system. For specific module documentation, refer to the individual guide files in the guide/ directory. Always test changes in a development environment before deploying to production.