Files
centrumcopy.com.pl/.paul/codebase/architecture.md
2026-04-30 21:31:32 +02:00

352 lines
15 KiB
Markdown

# Architecture & Structure
**Analysis Date:** 2026-04-30
---
## Directory Layout
```
centrumcopy.com.pl/ # Docroot / front controller
├── index.php # Front controller (entry point)
├── robots.txt
├── application/ # Application code (APPPATH)
│ ├── cache/ # Kohana internal cache (file-based)
│ ├── config/ # All configuration files
│ ├── controllers/ # MVC Controllers
│ │ ├── base_admin.php # Abstract base for admin controllers
│ │ ├── base_front.php # Abstract base for front controllers
│ │ ├── install.php # Installation controller
│ │ ├── admin/ # Admin panel controllers
│ │ └── front/ # Public-facing controllers
│ ├── helpers/ # (empty — helpers live in libraries/drivers)
│ ├── i18n/pl_PL/ # Polish locale strings
│ ├── libraries/ # Extended/custom libraries
│ │ └── drivers/ # Driver extensions
│ ├── logs/ # Error/application logs
│ ├── models/ # ORM models
│ └── views/ # PHP view templates
│ ├── admin/ # Admin panel partial views
│ ├── front/ # Public partial views
│ ├── gmaps/ # Google Maps JS view
│ ├── pagination/ # Pagination style templates
│ ├── admin_layout.php # Admin full-page layout
│ ├── admin_login.php # Admin login page
│ └── default_layout.php # Public full-page layout
├── modules/ # Kohana modules (MODPATH)
│ ├── gmaps/ # Google Maps integration module
│ └── debug_toolbar/ # Debug toolbar module
├── system/ # Kohana framework core (SYSPATH)
│ └── core/ # Bootstrap, Event, Kohana, Benchmark
├── css/ # Public stylesheets
├── js/ # Public JavaScript (jQuery, TinyMCE, etc.)
├── images/ # Public images
├── flash/ # Flash banner assets
├── uploads/ # User-uploaded files
└── stara/ # Legacy static HTML site (archived)
```
---
## MVC Structure
### Controllers
**Location:** `application/controllers/`
Controllers use Kohana 2.x naming: `{Name}_Controller` extends a base class. File name is lowercase, class name is `PascalCase_Controller`.
**Base classes (abstract):**
| File | Class | Extends | Role |
|------|-------|---------|------|
| `application/controllers/base_front.php` | `Base_Front_Controller` | `Controller` | Sets up front layout (`default_layout`), session, menu, SEO metadata |
| `application/controllers/base_admin.php` | `Base_Admin_Controller` | `Controller` | Sets up admin layout (`admin_layout`), enforces auth guard, manages flash messages |
**Front (public) controllers**`application/controllers/front/`:
| File | Class | Handles |
|------|-------|---------|
| `front/page.php` | `Page_Controller` | Static CMS pages, homepage redirect, contact page with Google Maps |
| `front/welcome.php` | `Welcome_Controller` | (unused/fallback) |
**Admin controllers**`application/controllers/admin/`:
| File | Class | Handles |
|------|-------|---------|
| `admin/page.php` | `Page_Controller` | Edit CMS page content via TinyMCE |
| `admin/user.php` | `User_Controller` | Login, logout, password change |
| `admin/welcome.php` | `Welcome_Controller` | Admin dashboard index |
Note: Both `front/page.php` and `admin/page.php` define `Page_Controller` — they are isolated by directory scoping during routing.
**Auth guard pattern in `Base_Admin_Controller`:**
```php
if (!$this->session->get('admin') && Router::$method != 'login' && Router::$method != 'logout') {
url::redirect('admin/login');
}
```
**`__call` magic method** is used in `Page_Controller` (front) to route any unknown URL segment to `show($name)`, enabling slug-based page lookup.
### Models
**Location:** `application/models/`
All models extend `ORM` (Kohana's ActiveRecord-style ORM). Model file name is lowercase; class name is `{Name}_Model`.
| File | Class | Table | Notes |
|------|-------|-------|-------|
| `models/page.php` | `Page_Model` | `page` | Singular table name; supports lookup by `name` slug |
| `models/user.php` | `User_Model` | `user` | Primary val = `username`; SHA1+salt password hashing |
| `models/news.php` | `News_Model` | `news` | Singular; sorted by `created_at DESC` |
| `models/gallery.php` | `Gallery_Model` | `gallery` | Has many `gallery_images`; sorted `created_at ASC` |
| `models/gallery_image.php` | `Gallery_Image_Model` | `gallery_image` | Belongs to `gallery`; sorted by `id ASC` |
**ORM lookup pattern:**
```php
ORM::factory('page')->where('name', $slug)->find();
if (!$page->loaded) { return $this->error404(); }
```
### Views
**Location:** `application/views/`
Views are plain PHP templates. Layout views are full HTML documents; partial views are HTML fragments assigned to `$content`.
**Layout views (full pages):**
| File | Used by |
|------|---------|
| `views/default_layout.php` | All front controllers via `Base_Front_Controller` |
| `views/admin_layout.php` | All admin controllers via `Base_Admin_Controller` |
| `views/admin_login.php` | `User_Controller::login()` |
**Partial views — front:** `views/front/`
| File | Rendered by |
|------|-------------|
| `front/page_show.php` | `Page_Controller::show()` |
| `front/page_contact.php` | `Page_Controller::contact()` |
| `front/error404.php` | `Base_Front_Controller::error404()` |
**Partial views — admin:** `views/admin/`
| File | Rendered by |
|------|-------------|
| `admin/page_edit.php` | `admin/Page_Controller::edit()` |
| `admin/password.php` | `User_Controller::password()` |
| `admin/welcome.php` | `admin/Welcome_Controller::index()` |
| `admin/error404.php` | `Base_Admin_Controller::error404()` |
**View rendering pattern:**
```php
$page_view = new View('front/page_show');
$page_view->page = $page; // assign data to partial
$this->view->content = $page_view; // embed partial in layout
$this->view->render(true); // output full layout
```
---
## Routing
**Config file:** `application/config/routes.php`
Kohana 2.x routing maps URL patterns (regex) to `directory/controller/method` targets. Routes are evaluated top-to-bottom; first match wins.
```php
$config['_default'] = 'front/page/homepage'; // / → Front\Page::homepage()
// Admin routes
$config['admin'] = 'admin/welcome/'; // /admin
$config['admin/login'] = 'admin/user/login'; // /admin/login
$config['admin/logout'] = 'admin/user/logout'; // /admin/logout
$config['admin/password'] = 'admin/user/password'; // /admin/password
$config['admin/page/(.*)'] = 'admin/page/edit/$1'; // /admin/page/{slug}
$config['admin/(.*)'] = 'admin/$1'; // /admin/...
// Front routes
$config['kontakt'] = 'front/page/contact'; // /kontakt
$config['galeria/?(.*)'] = 'front/gallery/$1'; // /galeria/...
$config['aktualnosci/?(.*)'] = 'front/news/$1'; // /aktualnosci/...
$config['(.+)'] = 'front/page/$1'; // /{any-slug} → Page::show()
```
**Slug routing:** The catch-all `(.+)` route passes the URL slug to `front/page/`. `Page_Controller::show($name)` then queries the database for a page with `name = $slug`. This means all CMS pages live in a flat namespace matched against the `page.name` column.
**URL rewriting:** `index_page` is commented out in `application/config/config.php`, meaning clean URLs (no `index.php` in path) require Apache `mod_rewrite` or equivalent.
---
## Module System
**Module path:** `modules/` (MODPATH)
Modules are configured in `application/config/config.php` under `$config['modules']`. Kohana merges module paths into the file search cascade (controllers, views, libraries, etc. from a module are auto-discoverable).
**Active modules:**
| Module | Path | Purpose |
|--------|------|---------|
| `gmaps` | `modules/gmaps/` | Google Maps v2 API wrapper — `Gmap` library, marker helpers, JS view |
**Available but disabled modules** (commented out in config):
- `auth`, `forge`, `kodoc`, `media`, `archive`, `payment`, `unit_test`, `object_db`
**`debug_toolbar` module** exists at `modules/debug_toolbar/` but is **not loaded** in config.
**Module internal structure** (gmaps example):
```
modules/gmaps/
├── config/ # Module config
├── controllers/ # Module controllers (if any)
├── i18n/
├── libraries/ # Gmap, Gmap_Marker libraries
├── models/
└── views/ # gmaps/javascript.php
```
**Custom application-level extensions** (not modules — override framework classes):
| File | Purpose |
|------|---------|
| `application/libraries/MY_Database.php` | Extends `Database_Core` — fixes `COUNT()` column escaping with table prefix |
| `application/libraries/MY_Gmap_Marker.php` | Extends Gmap marker from the gmaps module |
| `application/libraries/drivers/Database.php` | Custom database driver wrapper |
| `application/libraries/drivers/MY_form.php` | Extended form helper |
| `application/libraries/drivers/MY_html.php` | Extended html helper (adds `span_class()`, etc.) |
| `application/libraries/drivers/MY_valid.php` | Extended validation rules |
| `application/libraries/drivers/categories.php` | Category tree helper |
| `application/libraries/drivers/javascript.php` | JavaScript generation helper |
---
## Business Domains
This is a **B2B product catalogue + CMS** for a photocopier/office equipment distributor (Centrum Copy Rzeszów).
### CMS / Static Pages
- **Primary domain.** All content pages are rows in the `page` table, looked up by a URL `name` slug.
- Pages have: `title`, `header`, `content` (HTML via TinyMCE), `meta_description`, `meta_keywords`.
- Admin edits pages via WYSIWYG at `/admin/page/{slug}`.
- Menu structure is **hardcoded** in `application/config/application.php` under `$config['menu_nav']` — changing the menu requires a code deploy.
- Content domains visible in admin menu: O firmie, Powielacze cyfrowe RISO, Pełnokolorowe urządzenia Inkjet RISO ComColor, Urządzenia biurowe (kolorowe/monochromatyczne A4/A3), Plotery i skanery, Finansowanie, Serwis, Usługi, Kontakt, Szybki kontakt.
### Gallery
- Model: `Gallery_Model` (has_many `Gallery_Image_Model`)
- Route: `/galeria/...``front/gallery` controller
- Note: `application/controllers/front/gallery.php` does not exist as a file — gallery controller is **missing or not committed**.
### News / Aktualności
- Model: `News_Model`
- Route: `/aktualnosci/...``front/news` controller
- Note: `application/controllers/front/news.php` does not exist — news controller is **missing or not committed**.
### Contact Page
- Route `/kontakt``Page_Controller::contact()`
- Renders Google Maps v2 marker at configured lat/lon (`application/config/application.php``$config['gmaps']`).
- Google Maps centre: `50.0491231, 21.9869502` (Rzeszów, ul. Okulickiego 9).
### Admin Panel
- Session-based authentication. Credentials: SHA1(salt + password) stored in `user` table.
- Single-user admin — no roles enforced beyond session presence.
- Admin navigates to hardcoded page slugs from the sidebar in `admin_layout.php`.
- Features: edit page content, change admin password, logout.
---
## Request Lifecycle
```
Browser Request
|
v
index.php (front controller)
- defines DOCROOT, APPPATH, MODPATH, SYSPATH
- sets IN_PRODUCTION = false
- requires system/core/Bootstrap.php
|
v
system/core/Bootstrap.php
- loads Benchmark, utf8, Event, Kohana
- Kohana::setup() (loads config, modules, sets error handlers)
|
v
Event::run('system.ready') (hooks, if enabled — currently disabled)
|
v
Event::run('system.routing')
- Router matches URI against application/config/routes.php
- Determines: directory, controller, method, arguments
|
v
Event::run('system.execute')
- Instantiates controller: new {Name}_Controller()
- __construct() runs:
- parent::__construct() (Kohana base Controller)
- Base_Front/Admin_Controller::__construct()
- Creates View object for layout
- Starts Session
- Loads config (title, meta, menu_nav, etc.)
- [Admin only] Auth guard → redirect to login if not authed
- Calls controller method (e.g., show(), edit(), login())
- Method queries ORM models
- Creates partial View, assigns data
- Assigns partial to $this->view->content
- $this->view->render(true) → outputs full HTML
|
v
Event::run('system.shutdown') (cleanup)
|
v
Response sent to browser
```
**Session:** Native PHP sessions, 30-minute expiration, validated by `user_agent`. Session name: `Frisson_session`.
**Database:** MySQLi driver, single `default` connection, no table prefix, UTF-8 charset, query benchmarking enabled.
**Output compression:** gzip enabled (`$config['output_compression'] = TRUE`).
**Error handling:** Errors logged to `application/logs/` at threshold 1 (errors + exceptions). `display_errors` is off in production.
---
## Configuration Files
| File | Purpose |
|------|---------|
| `application/config/application.php` | Site title, email, Google Maps coords, navigation menu, Google Analytics |
| `application/config/config.php` | Kohana core settings: domain, modules list, cache, compression, hooks |
| `application/config/database.php` | MySQLi connection credentials |
| `application/config/routes.php` | URL routing rules |
| `application/config/session.php` | Session driver, name, expiration |
| `application/config/pagination.php` | Pagination defaults (5 items/page, segment 3) |
| `application/config/email.php` | Email settings |
| `application/config/cookie.php` | Cookie settings |
| `application/config/tiny_mce.php` | TinyMCE upload paths for admin editor |
| `application/config/upload.php` | File upload settings |
| `application/config/locale.php` | Locale/timezone |
| `application/config/gmaps.php` | Google Maps module config |
| `application/config/debug_toolbar.php` | Debug toolbar settings |
---
## Key Observations & Gaps
1. **Missing controllers:** `application/controllers/front/gallery.php` and `application/controllers/front/news.php` are referenced in routes but absent. Routes for `/galeria/` and `/aktualnosci/` will 404.
2. **Hardcoded navigation:** `$config['menu_nav']` in `application/config/application.php` defines the entire site menu statically. Adding/removing menu items requires editing this config file and redeploying.
3. **Admin menu also hardcoded:** `application/views/admin_layout.php` contains inline HTML listing every editable page slug. Must be manually updated to match `page` table contents.
4. **IN_PRODUCTION = false:** Set in `index.php`. Must be changed to `true` before deploying to live server to enable Google Analytics and suppress demo controllers.
5. **Kohana version:** 2.3.4 (codename "buteo regalis") — very old, unmaintained framework. No Composer, no autoloading beyond Kohana's own file cascade.
6. **Auth security:** `User_Controller::login()` contains `print_r($_POST)` debug statement (line 29). This leaks credentials in the HTTP response. Remove before any production use.
7. **No test runner configured.** No test files detected.