PHP code example of flexagon / framework

1. Go to this page and download the library: Download flexagon/framework library. Choose the download type require.

2. Extract the ZIP file and open the index.php.

3. Add this code to the index.php.
    
        
<?php
require_once('vendor/autoload.php');

/* Start to develop here. Best regards https://php-download.com/ */

    

flexagon / framework example snippets



use _Flexagon\Models\DataSourceModel;

_Global::$DATA_SOURCES['default'] = new DataSourceModel(
    'localhost',   // host
    3306,          // port
    'username',
    'password',
    'dbname'
);


// public/hello.php
_Global::$SITE_TITLE = 'Hello';

TemplateLoader::show('head');
echo '<h1>Hello, Flexagon</h1>';
TemplateLoader::show('tail');

_Global::$URL_PARAM->filePath;       // 'user/profile'
_Global::$URL_PARAM->filePathArray;  // ['user', 'profile']
_Global::$URL_PARAM->filePathEnd;    // 'profile'
_Global::$URL_PARAM->params;         // '?id=3'


// public/_router.php
$path = _Global::$URL_PARAM->filePath;

if (str_starts_with($path, 'api/')) {
    header('Content-Type: application/json');
    


// application/_Global.php
use _Flexagon\Base\BaseGlobal;

class _Global extends BaseGlobal {
    // Add application-specific globals here
    public static ?\Session\SessionUserModel $SESSION_USER_MODEL = null;
}

new DataSourceModel(
    string $host,
    int    $port,
    string $username,
    string $password,
    string $dbName,
    ?string $charset = 'utf8mb4',
    ?bool   $usePrepareStatement = true
);

_Global::$DATA_SOURCES['default']   = new DataSourceModel('db-master', 3306, 'app', '****', 'service');
_Global::$DATA_SOURCES['analytics'] = new DataSourceModel('db-replica', 3306, 'ro',  '****', 'stats');


namespace ExampleUser;

use _Flexagon\Base\BaseModel;

class UserModel extends BaseModel {
    private ?int    $id       = null;
    private string  $name;
    private ?string $address  = null;

    public function getId(): ?int          { return $this->id; }
    public function setId(?int $id): void  { $this->id = $id; }

    public function getName(): string             { return $this->name; }
    public function setName(string $name): void   { $this->name = $name; }

    public function getAddress(): ?string             { return $this->address; }
    public function setAddress(?string $a): void      { $this->address = $a; }
}


namespace ExampleUser;

use _Flexagon\Base\BaseMySqlDAO;

class UserDAO extends BaseMySqlDAO {
    protected string $tableName = 'users';

    public function insert(UserModel $user): int|false { return $this->_insert($user); }
    public function update(UserModel $user): bool      { return $this->_update($user); }
    public function delete(UserModel $user): bool      { return $this->_delete($user); }

    public function findById(int $id): ?UserModel {
        return $this->_select(['id' => $id], new UserModel());
    }

    /** @return UserModel[] */
    public function findByCity(string $city, int $page = 1, int $perPage = 20): array {
        return $this->_selectList(
            new UserModel(), $page, $perPage,
            '`address` = :CITY', ['CITY' => $city],
            '`created_at` DESC'
        );
    }

    public function countByCity(string $city): int {
        return $this->_selectTotalCount('`address` = :CITY', ['CITY' => $city]);
    }
}

public function findTopSpenders(int $limit): array {
    $this->db->executeQuery(
        'SELECT u.* FROM users u JOIN orders o ON o.user_id = u.id
         GROUP BY u.id ORDER BY SUM(o.amount) DESC LIMIT :LIMIT',
        ['LIMIT' => $limit]
    );
    return $this->db->getAllResultAsObject(new UserModel());
}

$this->_selectList(new UserModel(), 1, 20,
    '`name` LIKE :KEYWORD OR `address` LIKE :KEYWORD',   // may appear more than once
    ['KEYWORD' => "%{$keyword}%"]
);

echo $userDAO->debugQuery();   // actual SQL with parameters substituted
echo $userDAO->getError();     // last error message
$userDAO->debugDumpParams();   // PDOStatement::debugDumpParams()

/** @encrypt */
/** @db_auto_timestamp insert|update */
/** @exclude_from_get_array */

@db_auto_timestamp    @DbAutoTimestamp    @DB_AUTO_TIMESTAMP    @dbautotimestamp

/**
 * @var int|null
 * @db_auto_timestamp insert
 */
protected ?int $createdAt = null;

/**
 * @var int|null
 * @db_auto_timestamp insert|update
 */
protected ?int $updatedAt = null;

/**
 * @var string
 * @encrypt
 */
private string $residentNumber = '';

/**
 * @exclude_from_get_array
 */
public function getPasswordHash(): string { return $this->passwordHash; }

$userDAO->startTransaction();
try {
    $userDAO->insert($user);
    $userDAO->commit();
} catch (Throwable $e) {
    $userDAO->rollback();
    throw $e;
}

use _Flexagon\Libs\DataSourceManager;

DataSourceManager::startTransaction();
try {
    $userDAO->insert($user);
    $orderDAO->insert($order);
    $pointDAO->update($point);
    DataSourceManager::commit();
} catch (Throwable $e) {
    DataSourceManager::rollback();
    throw $e;
}

class StatsDAO extends BaseMySqlDAO {
    const DATA_SOURCE_ID = 'analytics';   // _Global::$DATA_SOURCES['analytics']
    protected string $tableName = 'daily_stats';
}

// application/_Config.php
_Global::$SESSION_AUTO_START      = true;
_Global::$SESSION_ENCRYPTION_STRING = 'change-this-to-a-long-random-string';
_Global::$SESSION_DOMAIN          = '.example.com';
_Global::$SESSION_TIMEOUT_SECONDS = 86400;

// Cookie security attributes — the defaults are already secure and usually do not need to be changed.
_Global::$SESSION_COOKIE_SECURE   = null;    // null = automatically enabled for HTTPS requests
_Global::$SESSION_COOKIE_HTTPONLY = true;    // prevent JavaScript from accessing the session cookie
_Global::$SESSION_COOKIE_SAMESITE = 'Lax';


namespace Session;

use _Flexagon\Base\BaseModel;

class SessionUserModel extends BaseModel {
    private string  $role     = 'USER';
    private ?string $username = '';
    private ?string $email    = '';
    // 게터 / 세터 ...
}


namespace Session;

use _Flexagon\Base\BaseSessionDAO;

class SessionDAO extends BaseSessionDAO {}

// 로그인
$sessionUser = new SessionUserModel();
$sessionUser->setUsername($user->getUsername());
$sessionUser->setRole('ADMIN');

$sessionDAO = new SessionDAO();
$sessionDAO->makeSession($sessionUser);

// 로그아웃
$sessionDAO->cleanSession();

_Global::$SESSION_MODEL;        // always available here
_Global::$SESSION_USER_MODEL;   // class-name-based global (see below)

class _Global extends BaseGlobal {
    public static ?\Session\SessionUserModel $SESSION_USER_MODEL = null;
}


// public/_prepare.php
if (str_starts_with(_Global::$URL_PARAM->filePath, 'admin/')) {
    if (_Global::$SESSION_USER_MODEL?->getRole() !== 'ADMIN') {
        \_Flexagon\Libs\HtmlUtil::redirectPage('/login');
    }
}

// CSRF — no token mechanism is provided. Validate state-changing requests yourself.
// Output escaping — templates do not provide automatic escaping.
echo htmlspecialchars($user->getName(), ENT_QUOTES, 'UTF-8');

// Mass assignment — passing $_POST directly may overwrite fields such as id and role.
$user->setByArray(array_intersect_key($_POST, array_flip(['name', 'email'])));

// Serialization — getArray()/getJson() 

TemplateLoader::show('head', ['title' => 'Product List']);   // public/_Template/head.php
TemplateLoader::content();                                   // execute the page mapped to the URL
TemplateLoader::entryDir('_layout');                         // _layout.php in the current URL directory
TemplateLoader::entryRoot('_footer');                        // public/_footer.php

<!-- public/_Template/head.php -->
<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="utf-8">
    <title><?= htmlspecialchars($title ?? _Global::$SITE_TITLE) 

use _Flexagon\Libs\AssetLoader;

AssetLoader::setVersion('3.4.13');          // append ?_=3.4.13 to all asset URLs
AssetLoader::setAssetRootPath('/assets/');

AssetLoader::setCss('main.css');                        // /assets/css/main.css (Loader::getAssetUrl('fonts/pretendard.woff2');

_echo('Hello, {name}', ['name' => $user->getName()]);   // substitute and output
$msg = _t('{count} results found', ['count' => 42]);    // substitute and return

use _Flexagon\Supporters\EnumSupporter;

enum UserRole: string {
    use EnumSupporter;

    case ADMIN = 'ADMIN';
    case USER  = 'USER';
}

UserRole::keys();            // ['ADMIN', 'USER']
UserRole::values();          // ['ADMIN', 'USER']
UserRole::toArray();         // ['ADMIN' => 'ADMIN', 'USER' => 'USER']
UserRole::toCommaString();   // 'ADMIN,USER'

UserRole::toQuotedCommaString();      // "'ADMIN','USER'"
UserRole::toQuotedCommaString('"');   // '"ADMIN","USER"'

// Safe even when values contain quotes or commas
// case A = "it's";  case B = 'a,b';
//   toCommaString()        → it's,a,b          (breaks DDL)
//   toQuotedCommaString()  → 'it''s','a,b'


// script/cleanup.php
er\UserDAO())->deleteExpired();
echo "Deleted: {$deleted} rows\n";

create   flexagon.php
create   application/_Global.php
...
keep     public/index.php        ← keep existing file

ExampleUser\UserDAO  →  application/ExampleUser/UserDAO.php
bash
php script/flexagon.php check     # works with any installation type
php vendor/bin/flexagon check     # also available with Composer installations

Browser
  │
  ├─ .htaccess          rewrites all .php requests to __flexagon.php
  │
  ├─ __flexagon.php ──► flexagon.php ──► Bootstrap.php
  │                                        │
  │                                        ├─ defines constants (PROJECT_ROOT, PUBLIC_ROOT, _FLEXAGON_ROOT ...)
  │                                        ├─ registers the autoloader
  │                                        ├─ loads _Const.php / _Global.php / _Config.php
  │                                        └─ parses the URL → _Global::$URL_PARAM
  │
  ├─ public/_entry.php      ① request-start hook (site title, shared headers, etc.)
  ├─ [automatic session start] ② when $SESSION_AUTO_START is true
  ├─ public/_prepare.php    ③ post-session hook (authorization checks, etc.)
  └─ public/_router.php     ④ dispatch — default implementation uses TemplateLoader::content()
                                 → executes public/<URL path>.php
bash
php script/batch.php runtimeStage=production
bash
php script/cleanup.php runtimeStage=production days=30
bash
php script/flexagon.php init [--path=DIR] [--force]
php script/flexagon.php check [--path=DIR]

create   script/flexagon.php
keep     public/index.php
1 created, 17 kept, 0 failed