Contributing¶
We welcome contributions from the community. To contribute, follow these steps:
Fork the Repository: Fork the MultiFlexi repository to your GitHub account.
Create a Branch: Create a new branch for your feature or bugfix.
git checkout -b feature-nameMake Changes: Make your changes and commit them with a descriptive message.
git commit -m "Description of the feature or fix"Push Changes: Push your changes to your forked repository.
git push origin feature-nameCreate a Pull Request: Open a pull request on the original repository.
Thank you for contributing to MultiFlexi!
Development Workflow¶
Git Workflow
MultiFlexi uses a standard Git workflow with feature branches:
Create Feature Branch: Always create a new branch for features or fixes
git checkout -b feature/new-executor-type git checkout -b fix/job-timeout-issue
Commit Guidelines: Use conventional commit messages
git commit -m "feat: add Kubernetes executor support" git commit -m "fix: resolve infinite recursion in Docker executor" git commit -m "docs: update API documentation"
Testing Before Push: Always run tests before pushing
./vendor/bin/phpunit ./vendor/bin/phpstan analyse
CI/CD Pipeline
The project uses Jenkins for continuous integration:
Source Push: Code pushed to GitHub triggers Jenkins build
Package Build:
debian/Jenkinsfilecreates .deb packages (~10 minutes)Unstable Repository: Packages available at: -
http://repo.vitexsoftware.cz/-http://repo.vitexsoftware.com/Release Process: Manual Jenkins trigger using
debian/Jenkinsfile-releaseProduction Repository: Released packages at
https://repo.multiflexi.eu/
Deployment Environments
Development:
http://localhost/MultiFlexi/(source code)Local Package:
http://localhost/multiflexi/(installed .deb)Testing:
https://vyvojar.spoje.net/multiflexi/(CI packages)Demo:
https://demo.multiflexi.eu/(Ansible deployed)Production: -
https://multiflexi.vitexsoftware.com/-https://multiflexi.spojenet.cz/
Handling Multiple Database Types¶
MultiFlexi supports multiple database types including MySQL, SQLite, PostgreSQL, MSSQL, and almost every PDO-capable database engine. When writing queries, you need to ensure compatibility with these databases.
Here is an example method todaysCond that generates a condition to fetch records for the current day, compatible with different database types:
public function todaysCond(string $column = 'begin'): string {
$databaseType = $this->getPdo()->getAttribute(\PDO::ATTR_DRIVER_NAME);
switch ($databaseType) {
case 'mysql':
$cond = ('DATE(' . $column . ') = CURDATE()');
break;
case 'sqlite':
$cond = ("DATE(" . $column . ") = DATE('now')");
break;
case 'pgsql':
$cond = ('DATE(' . $column . ') = CURRENT_DATE');
break;
case 'sqlsrv':
$cond = ('CAST(' . $column . ' AS DATE) = CAST(GETDATE() AS DATE)');
break;
default:
throw new \Exception('Unsupported database type ' . $databaseType);
}
return $cond;
}
This method checks the database type and returns the appropriate condition for fetching records for the current day based on the specified column.
By following this approach, you can ensure that your queries are compatible with multiple database types, making your application more flexible and robust.
GDPR Compliance Development¶
When developing MultiFlexi features, developers must consider GDPR compliance requirements:
Data Processing Considerations
Implement privacy by design principles
Minimize data collection and processing
Ensure lawful basis for all processing activities
Document data flows and processing purposes
Security Requirements
Use encryption for sensitive data (AES-256)
Implement proper access controls and logging
Follow secure coding practices
Regular security assessments
Data Retention Implementation
// Example: Implementing retention-aware data processing
class DataProcessor {
public function processWithRetention($data, $retentionPeriod) {
// Set retention metadata
$data['retention_expires'] = date('Y-m-d', strtotime('+' . $retentionPeriod));
// Process data
$this->processData($data);
// Log for audit trail
$this->addStatusMessage('Data processed with retention: ' . $retentionPeriod, 'info');
}
}
GDPR-Compliant Logging
// Avoid logging personal data
$this->addStatusMessage('User login successful for ID: ' . $userId, 'info');
// Instead of: 'User ' . $email . ' logged in'
// Use structured logging for audit trails
$this->addStatusMessage([
'event' => 'data_access',
'user_id' => $userId,
'resource' => $resourceType,
'timestamp' => date('c')
], 'audit');
For complete GDPR compliance documentation, see GDPR Compliance.
Coding Standards and Best Practices¶
PHP Standards
MultiFlexi follows PSR-12 coding standards with additional project-specific conventions:
Classes: PascalCase (
RunTemplate,JobExecutor)Methods: camelCase (
executeJob,getCompanyList)Variables: camelCase (
$companyId,$jobResult)Constants: SCREAMING_SNAKE_CASE (
DB_HOST,DEFAULT_TIMEOUT)Database: snake_case (
run_template,company_id)
Documentation Requirements
All public methods must include PHPDoc comments:
/**
* Execute a job with the specified parameters
*
* @param int $jobId The job identifier
* @param array $params Execution parameters
* @return bool True on success, false on failure
* @throws \Exception When job cannot be found
*/
public function executeJob(int $jobId, array $params = []): bool
Environment Configuration
Use environment variables for configuration, with sensible defaults:
$logLevel = getenv('LOG_LEVEL') ?: 'info';
$dbHost = getenv('DB_HOST') ?: 'localhost';
Logging Best Practices
Use the Ease logging framework with appropriate log levels:
$this->addStatusMessage('Job started', 'info');
$this->addStatusMessage('Processing company: ' . $companyName, 'debug');
$this->addStatusMessage('Job failed: ' . $error, 'error');
Application JSON Schema Validation¶
MultiFlexi enforces JSON schema validation for application definitions to ensure consistency and prevent configuration errors.
Validation Command:
multiflexi-cli application validate-json --json path/to/app.json
Common Validation Errors:
Invalid type values: Environment variable types must be one of:
string,file-path,email,url,integer,float,bool,password,set,textArray vs Object: Fields like
topics,requirements, andartifactsmust be arrays, not objectsMissing required fields: All required fields in the schema must be present
Example of correct environment variable definition:
"environment": {
"FORCE_EXITCODE": {
"type": "integer",
"description": "Force specific exit code",
"defval": "0",
"required": false
}
}