Yours&Mine PHP Framework – Developer Guide v0.3
This document explains how the Yours&Mine PHP Framework is structured and
how a request like GET / becomes the dashboard you see in the browser –
under both the Material and Cork admin templates.
1. Project structure
Top-level folders (inside your project root):
app/
Controllers/
Views/
layouts/
material.php
cork.php
home/
index.php
about.php
bootstrap/
helpers.php
app.php
config/
config.php
brand.php
lang.php
core/
Bootstrap.php
Router.php
Lang.php
BaseController.php
public/
index.php
assets/
material/ ... (Material template files)
cork/ ... (Cork template files)
css/
ym-dashboard.css
readme_guide.html
vendor/
autoload.php
composer.json
Key concepts:
- app/ Application code: controllers and views.
- core/ Reusable framework classes: router, bootstrap, base controller, language helper.
- config/ Framework configuration: environment, UI layout, brand, languages.
- public/ Web root. All HTTP requests enter here via
index.php.
2. Request lifecycle overview
When you open the dashboard (e.g. http://localhost/ur-mine/):
- Front controller:
public/index.phpruns first. - It bootstraps Composer autoload + your own helpers.
- It instantiates
YoursMine\Core\Bootstrapand calls$app->run(). Bootstrap:- Loads configuration.
- Creates the
Router. - Registers application routes (e.g.
/,/about). - Calls
$router->dispatch().
Routermatches the current HTTP method + path and calls the handler, e.g.[HomeController::class, 'index'].HomeController::index()prepares some data and calls$this->view('home/index', $data).BaseController::view():- Resolves the view file:
app/Views/home/index.php. - Renders it into a
$contentvariable. - Chooses the current layout (Material or Cork) based on config.
- Includes the layout file; layout prints the full HTML shell and injects
$contentinside.
- Resolves the view file:
3. Configuration basics
3.1 Main config
config/config.php returns a PHP array:
<?php
return [
'app_name' => 'Yours&Mine PHP Framework',
'timezone' => 'Asia/Kathmandu',
// Current UI layout: 'material' or 'cork'
'ui' => [
'layout' => 'material',
],
// Default language for the UI (also used for translations)
'lang' => [
'default' => 'en',
'supported' => ['en', 'np'],
],
];
3.2 Brand configuration
config/brand.php centralises anything that feels like “branding”:
<?php
return [
'name' => 'Yours&Mine PHP Framework',
'logo' => 'assets/material/images/logo.svg', // or null to use text
'favicon' => 'assets/material/images/favicon.ico',
'footer_text' => '© ' . date('Y') . ' Yours&Mine PHP Framework',
'footer_link' => 'https://example.com', // or null
];
Layouts read these values using a helper such as config('brand.name').
3.3 UI layout selection
In config/config.php:
'ui' => [
'layout' => 'material', // options: 'material', 'cork'
],
In BaseController::view() you resolve that to a layout file:
$ui = config('ui.layout', 'material');
$layout = $ui === 'cork'
? 'layouts/cork'
: 'layouts/material';
$this->renderLayout($layout, $viewPath, $data);
Switching from Material to Cork is now just editing one config value.
4. Routing & the Bootstrap class
4.1 Router
core/Router.php is a small HTTP router that supports:
$router->get($path, $handler)$router->post($path, $handler)
$handler is a callable, typically: [HomeController::class, 'index'].
4.2 Bootstrap
core/Bootstrap.php wires everything together:
namespace YoursMine\Core;
use App\Controllers\HomeController;
class Bootstrap
{
protected array $config;
protected Router $router;
public function __construct()
{
$this->config = require YM_CONFIG_PATH . '/config.php';
date_default_timezone_set($this->config['timezone'] ?? 'UTC');
$this->router = new Router();
$this->registerRoutes();
}
protected function registerRoutes(): void
{
$this->router->get('/', [HomeController::class, 'index']);
$this->router->get('/about', [HomeController::class, 'about']);
}
public function run(): void
{
$this->router->dispatch();
}
}
5. Controllers & views
5.1 HomeController
The default controller at app/Controllers/HomeController.php might look like:
namespace App\Controllers;
use YoursMine\Core\BaseController;
class HomeController extends BaseController
{
public function index(): void
{
$data = [
'title' => __('nav.dashboard'),
];
$this->view('home/index', $data);
}
public function about(): void
{
$data = [
'title' => __('nav.about'),
];
$this->view('home/about', $data);
}
}
5.2 BaseController and view()
core/BaseController.php is responsible for rendering:
protected function view(string $view, array $data = []): void
{
$viewFile = YM_APP_PATH . '/Views/' . $view . '.php';
if (!file_exists($viewFile)) {
throw new \RuntimeException("View not found: {$viewFile}");
}
extract($data, EXTR_SKIP);
ob_start();
include $viewFile;
$content = ob_get_clean();
$ui = config('ui.layout', 'material');
$layout = $ui === 'cork'
? YM_APP_PATH . '/Views/layouts/cork.php'
: YM_APP_PATH . '/Views/layouts/material.php';
include $layout;
}
5.3 Dashboard view (home/index.php)
This view is template-agnostic. Both Material and Cork layouts render it by injecting $content into their main content area. The view uses the ym-* CSS classes that we control in public/assets/css/ym-dashboard.css.
Example structure:
<div class="row g-3 mb-4">
<div class="col-md-3">
<div class="ym-card">
<div class="ym-card-title">Framework Version</div>
<div class="ym-card-value">v0.3</div>
<div class="ym-card-meta">Routing + MVC + multi-theme layout.</div>
</div>
</div>
<div class="col-md-3">... controllers card ...</div>
<div class="col-md-3">... views card ...</div>
<div class="col-md-3">... projects / slots card ...</div>
</div>
<div class="ym-card">
<h5>How this page is rendered</h5>
<p class="ym-dashboard-intro">Route → Controller → View → Layout.</p>
<div class="ym-card-code">
<div class="ym-step">
<span class="ym-chip">1</span>
GET <code>/</code> is routed in <code>core/Bootstrap.php</code>
to <code>HomeController::index()</code>.
</div>
<div class="ym-step">
<span class="ym-chip">2</span>
Controller calls <code>$this->view('home/index', [...])</code>.
</div>
<div class="ym-step">
<span class="ym-chip">3</span>
Base controller renders <code>app/Views/home/index.php</code> into
<code>$content</code>.
</div>
<div class="ym-step">
<span class="ym-chip">4</span>
Layout (Material or Cork) injects <code>$content</code> and outputs
the final HTML.
</div>
</div>
</div>
6. Layouts: Material vs Cork
6.1 Material layout
app/Views/layouts/material.php wraps the Material HTML template. It:
- Prints the HTML
<head>with Material CSS/JS +ym-dashboard.css. - Shows the Material sidebar and topbar with:
- Brand name/logo from
brand.php. - Language selector (English / Nepali, with flags).
- Theme toggle (light/dark) – using Material’s JS.
- Brand name/logo from
- Renders
= $content ?>inside the content container. - Shows the footer based on
brand.footer_textandbrand.footer_link.
6.2 Cork layout
app/Views/layouts/cork.php integrates Cork’s index.html. It:
- Includes Cork’s own loader, CSS and JS exactly as in the template.
- Uses your branding in the sidebar:
- Logo:
config('brand.logo')or “YM” initials. - Brand name:
config('brand.name', __('app.name')).
- Logo:
- Provides:
- Language dropdown (English / Nepali) with US / NP flags.
- Theme toggle (moon/sun) – handled by Cork’s
app.js. - User dropdown demo.
- Renders
= $content ?>inside the Cork#contentarea. - Uses footer values from
brand.php.
6.3 Dashboard polishing & dark mode (Cork)
The shared dashboard uses ym-* classes. The look-and-feel is defined in:
public/assets/css/ym-dashboard.css
For Cork dark mode:
- Cork’s theme toggle button has class
.theme-toggle. - In
cork.phpa small script listens for clicks on that button and togglesbody.ym-dark. ym-dashboard.csscontains special rules forbody.ym-dark .ym-cardso cards and text look correct on dark background.
You can change the exact colors in ym-dashboard.css without touching either Material or Cork template files.
7. Language system (English & Nepali)
7.1 Language files
Language files live in app/Lang/{locale}.php. For example:
app/
Lang/
en.php
np.php
7.2 English file (en.php)
<?php
return [
'app' => [
'name' => 'Yours&Mine PHP Framework',
],
'nav' => [
'dashboard' => 'Dashboard',
'about' => 'About',
],
'dashboard' => [
'framework_version' => 'Framework Version',
'controllers' => 'Controllers',
'views' => 'Views',
'projects' => 'Projects (idea slots)',
'how_rendered_title' => 'How this page is rendered',
'how_rendered_intro' => 'Route → Controller → View → Layout.',
],
'about' => [
'title' => 'About this framework',
'body' => 'A lightweight custom PHP framework powered by your own MVC & HTML templates.',
],
];
7.3 Nepali file (np.php)
<?php
return [
'app' => [
'name' => 'तपाईको र मेरो PHP फ्रेमवर्क',
],
'nav' => [
'dashboard' => 'ड्यासबोर्ड',
'about' => 'बारेमा',
],
'dashboard' => [
'framework_version' => 'फ्रेमवर्क संस्करण',
'controllers' => 'कन्ट्रोलरहरू',
'views' => 'भ्यूहरू',
'projects' => 'प्रोजेक्ट (आइडिया स्लट)',
'how_rendered_title' => 'यो पेज कसरी रेंडर हुन्छ',
'how_rendered_intro' => 'रुट → कन्ट्रोलर → भ्यू → लेआउट।',
],
'about' => [
'title' => 'यो फ्रेमवर्कबारे',
'body' => 'तपाईंले आफैं बनाएको हल्का PHP फ्रेमवर्क, MVC र HTML टेम्पलेटहरूसँग।',
],
];
7.4 The Lang helper
core/Lang.php manages loading these arrays and provides a function __():
__('nav.dashboard'); // "Dashboard" or "ड्यासबोर्ड"
__('about.title'); // about page title in current language
Typical implementation:
function __(string $key, ?string $locale = null): string
{
return YoursMine\Core\Lang::get($key, $locale);
}
And Lang::get() splits the dot notation and walks the loaded array.
7.5 Switching language from the UI
Both layouts have a language dropdown with attributes such as data-ym-lang="en" or data-ym-lang="np".
Shared JS handler (included in layouts):
document.addEventListener('DOMContentLoaded', function () {
document.querySelectorAll('[data-ym-lang]').forEach(function (el) {
el.addEventListener('click', function (e) {
e.preventDefault();
var lang = this.getAttribute('data-ym-lang');
if (!lang) return;
var url = new URL(window.location.href);
url.searchParams.set('lang', lang);
window.location.href = url.toString();
});
});
});
In PHP (e.g. in a small bootstrap or middleware layer), you read the query parameter and store the selected language in the session or cookie:
$locale = $_GET['lang'] ?? ($_SESSION['ym_locale'] ?? config('lang.default', 'en'));
$_SESSION['ym_locale'] = $locale;
YoursMine\Core\Lang::setLocale($locale);
The current locale can be queried via Lang::locale() – used by layouts to decide which flag to show as active.
7.6 Adding new text to language files
Whenever you need to translate new UI text:
- Pick a logical key path, e.g.
settings.general.title. - Add that key in all language files (
en.php,np.php, etc.):
// en.php
'settings' => [
'general' => [
'title' => 'General Settings',
],
],
// np.php
'settings' => [
'general' => [
'title' => 'साधारण सेटिङ',
],
],
- Call
__('settings.general.title')in your controller or view.
"settings.general.title") or
to the default language.
8. Extending the framework
8.1 Adding a new page
- Create a controller method, e.g.
ReportsController::index(). - Register a route in
Bootstrap::registerRoutes():
$this->router->get('/reports', [ReportsController::class, 'index']);
- Create a view file:
app/Views/reports/index.php. - Add a menu item in the layout (Material and/or Cork) that links to
/reports.
8.2 Adding another admin template (future)
The pattern you used for Material and Cork can be repeated:
- Create a new layout file:
app/Views/layouts/{name}.php. - Copy HTML from the template’s main dashboard, then:
- Replace hardcoded brand name & logo with
config('brand.*'). - Replace content area with
= $content ?>. - Integrate language dropdown and your shared JS language handler.
- Replace hardcoded brand name & logo with
- Set
'ui.layout' => '{name}'inconfig/config.php.
9. Summary
- The framework is a lightweight MVC wrapper around beautiful HTML templates (Material, Cork).
- Routing, controllers and views are template-agnostic.
- Layouts handle the “chrome” (navbars, sidebars, footers); they use:
- Brand configuration (name, logo, favicon, footer text/link).
- Language configuration +
Langhelper. - Theme toggles (light/dark) provided by the templates.
ym-dashboard.csscontrols how your own dashboard cards look and ensures Cork dark mode looks correct.- Adding new features is usually:
- Add route → controller → view.
- Translate texts via language files.
- Wire into the chosen layout’s sidebar or header.