# 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.