Norte /
Norte Upgrade System Documentation
Norte version 0.2.0
Overview
The upgrade system has been enhanced to support both traditional AJAX-style controllers (like upgrade_1.php and upgrade_2.php) and new HTML-interactive controllers (like upgrade_3.php) that can display forms and custom content.
Key Features
- Backward Compatible: Existing upgrade_1.php and upgrade_2.php work without modification
- Dynamic Content: Controllers can now return HTML to update the card header and body
- Form Support: Controllers can display forms for user input (e.g., login, confirmation)
- Error Display: var_dump(), errors, and exceptions are automatically displayed
- Unified Progress: Single progress bar for all upgrade steps
Architecture
Main Controller (upgrade.php)
The main controller provides a new step() method that acts as a proxy:
index.php?route=upgrade/upgrade/step&step=3&admin=admin
This method:
- Calls the appropriate upgrade_X controller
- Detects response type (JSON, HTML, or buffered output)
- Formats response appropriately
- Extracts card-header and card-body from HTML responses
Response Types
1. JSON Response (upgrade_1, upgrade_2, etc)
$json['text'] = 'Step description';
$json['success'] = 'Success message';
$json['error'] = 'Error message';
$json['next'] = $this->url->link('upgrade/upgrade_X', '', true);
$this->response->addHeader('Content-Type: application/json');
$this->response->setOutput(json_encode($json));
2. HTML Response
Option A: Return complete HTML
public function index() {
if ($this->request->server['REQUEST_METHOD'] !== 'POST') {
return $this->getLoginForm();
}
// Process POST...
}
private function getLoginForm(): string {
$html = '<div class="card-header"><i class="fa fa-lock"></i> Login Required</div>';
$html .= '<div class="card-body">';
$html .= '<form>...</form>';
$html .= '</div>';
return $html;
}
Option B: Echo HTML (will be captured)
public function index(): void {
echo '<div class="card-header">Custom Header</div>';
echo '<div class="card-body">Custom Content</div>';
}
Option C: Let errors/dumps be captured
public function index(): void {
var_dump($some_data); // Will be displayed in card-body
// or
throw new \Exception('Something went wrong'); // Will be formatted nicely
}
3. Mixed Response (HTML form → JSON processing)
public function index() {
// GET request: show form
if ($this->request->server['REQUEST_METHOD'] !== 'POST') {
return $this->getForm();
}
// POST request: process and return JSON
$json = [];
// Validate...
if ($valid) {
$json['success'] = 'Processing complete';
$json['proceed'] = true; // Continue to next step
} else {
$json['error']['field'] = 'Error message';
}
$this->response->addHeader('Content-Type: application/json');
$this->response->setOutput(json_encode($json));
}
Frontend Behavior
upgrade.twig
The template now:
- Has id="card-header" and id="card-body" for dynamic updates
- Stores original HTML for restoration after forms
- Handles both JSON and HTML responses
- Automatically binds form submissions
- Shows progress for JSON responses
- Hides progress for HTML responses
JavaScript Flow
1. Button click → Start upgrade chain 2. For each step:
a. Call upgrade/upgrade/step&step=N
b. Check response type:
- If json['html_update']:
* Update card-header
* Update card-body
* Hide progress section
* Bind form handlers if form present
* Stop chain (wait for user interaction)
- If traditional JSON:
* Update progress bar
* Show messages
* Continue to next step
c. On form submit:
- POST to same step URL
- Handle validation errors
- If json['proceed'], continue chain
3. Complete → Show success message
Example Implementations
Example 1: Simple AJAX Step
(like upgrade_1, upgrade_2)
class Upgrade5 extends \Opencart\System\Engine\Controller {
public function index(): void {
$json = [];
// Do work...
$this->doSomething();
$json['text'] = 'Step 5 complete';
$json['next'] = $this->url->link('upgrade/upgrade_6', '', true);
$this->response->addHeader('Content-Type: application/json');
$this->response->setOutput(json_encode($json));
}
}
Example 2: Form with Validation
class Upgrade6 extends \Opencart\System\Engine\Controller {
public function index() {
if ($this->request->server['REQUEST_METHOD'] !== 'POST') {
return $this->getForm();
}
$json = [];
if (empty($this->request->post['confirm'])) {
$json['error']['confirm'] = 'You must confirm';
}
if (!$json) {
// Process...
$json['success'] = 'Confirmed!';
$json['proceed'] = true;
}
$this->response->addHeader('Content-Type: application/json');
$this->response->setOutput(json_encode($json));
}
private function getForm(): string {
return '<div class="card-body"><form>...</form></div>';
}
}
Example 3: Debug Output
class Upgrade7 extends \Opencart\System\Engine\Controller {
public function index(): void {
// This will be captured and displayed nicely
var_dump([
'tables' => $this->getTables(),
'status' => 'checking'
]);
}
}
Technical Notes
- HTML detection uses strip_tags() comparison
- Card content extraction uses regex: /<div[^>]*class=["']card-(header|body)["'][^>]*>(.*?)<\/div>/is
- Buffered output (var_dump, errors) is wrapped in <pre> tags
- Form submissions automatically POST to same step URL
- Original card-body HTML is stored in jQuery data for restoration
- Progress bar shows percentage: (current_step / total_steps) * 100
Security Considerations
- All user inputs should be validated and escaped
- POST data should be verified before processing
- Database operations should use prepared statements
- File operations should validate paths
- Error messages should not expose sensitive information
