vnbase/vnbiz

My simple library

Maintainers

Details

github.com/vnbase/vnbiz

Source

Issues

Installs: 10

Dependents: 0

Suggesters: 0

Security: 0

Stars: 0

Watchers: 1

Forks: 0

Open Issues: 0

pkg:composer/vnbase/vnbiz

1.0.1 2024-10-11 15:50 UTC

This package is auto-updated.

Last update: 2026-02-11 14:48:31 UTC


README

A PHP framework for building RESTful APIs with built-in authentication, permissions, file uploads, caching, and multi-tenancy support.

Requirements

  • PHP >= 7.0
  • MySQL
  • Redis (optional, for caching and editing locks)
  • Imagick PHP extension (optional, for image processing)

Installation

composer require vnbase/vnbiz

Quick Start

require 'vendor/autoload.php';

// Initialize
vnbiz()->init_app('my_app', 'my_jwt_secret');
vnbiz()->init_db_mysql('localhost', 'user', 'pass', 'database');

// Define models
vnbiz_model_add('project')
    ->string('name', 'code')
    ->text('description')
    ->enum('status', ['active', 'archived'], 'active')
    ->ref('owner_id', 'user')
    ->require('name')
    ->author()
    ->text_search('name', 'description');

// Start the framework
vnbiz()->start();

// Run migrations
vnbiz_sql_alter_tables();

// Handle API requests
vnbiz()->handle_restful();

Architecture

Project Structure

src/
  vnbiz.php              # Bootstrap entry point
  base/
    rb.php               # RedBeanPHP ORM
    jwt.php              # JWT token implementation (HS256)
    logger.php           # Monolog logger setup
    div.php              # Div template engine
    vndb.php             # Lightweight DB layer (alternative)
    hashids/             # Hashids library for ID encryption
  core/
    VnBiz.php            # Main singleton class
    vnbiz_functions.php  # Global utility functions
    Model.php            # Model definition with fluent API
    Model_event.php      # Event hook trait
    Model_permission.php # Permission control trait
    Schema.php           # Schema definition class
    Actions.php          # Action/event dispatcher
    VnBiz_restful.php    # RESTful API handler trait
    VnBiz_sql.php        # SQL/database operations trait
    VnBizError.php       # Custom exception class
    VnbizImage.php       # Image manipulation (Imagick)
  modules/
    user.php             # User authentication & authorization
    oauth.php            # Google OAuth integration
    email.php            # Email sending & templating
    comment.php          # Comment system
    history.php          # Audit trail
    notification.php     # User notifications
    redis.php            # Redis integration & request tracking
    s3.php               # AWS S3 file uploads
    tag.php              # Tagging system
    review.php           # Rating/review system
    monitor.php          # System monitoring
    datascope.php        # Row-level access control
    editing_by.php       # Concurrent editing locks
    namespace.php        # Multi-tenancy support
    jsonschema.php       # JSON Schema generation
    typescriptschema.php # TypeScript interface generation
    template.php         # Template rendering (Div engine)
    sql.php              # SQL schema migration
    systemconfig.php     # Key-value config storage
    useractivity.php     # User activity logging
    usermark.php         # User bookmarks/likes

Request Lifecycle

HTTP Request
  -> handle_restful()
    -> Parse action (model_create, model_find, service_*, etc.)
    -> web_before_{action}_{model_name}
      -> Permission checks
      -> model_{action}
        -> db_before_{action}
          -> BEGIN TRANSACTION
            -> db_begin_{action}
            -> [DATABASE OPERATION]
            -> db_before_commit_{action}
            -> COMMIT
            -> db_after_commit_{action}
          -> [ROLLBACK on error]
            -> db_rollback_{action}
          -> db_end_{action}
        -> db_after_{action}
    -> web_after_{action}_{model_name}
  -> JSON Response

Initialization

Database (MySQL)

vnbiz()->init_db_mysql('host', 'user', 'password', 'database');

Redis (optional)

vnbiz()->init_redis('127.0.0.1', 6379, 'password');

Enables single-record query caching, editing locks, and request counters.

AWS S3 (optional)

vnbiz()->init_aws('region', 'bucket', 'access_key', 'secret_key');

Email / SMTP (optional)

vnbiz()->init_mailer('smtp.example.com', 465, 'user@example.com', 'password');

Falls back to PHP mail() if not configured.

Google OAuth (optional)

vnbiz()->init_oauth_google('client_id', 'client_secret', 'redirect_uri');

Modules

vnbiz()->init_modules(['email', 'comment', 'history', 'notification', 's3', 'tag', 'review']);

Multi-Tenancy

vnbiz()->use_namespaces(['project', 'task']); // models that are namespace-scoped

Namespace ID is extracted from: X-Namespace header, ns GET param, or ns POST param.

Model Definition

Models are defined using a fluent API.

Field Types

vnbiz_model_add('product')
    ->string('name', 'sku')          // VARCHAR(255)
    ->text('description')             // LONGTEXT
    ->int('quantity')                  // BIGINT
    ->uint('price')                   // BIGINT UNSIGNED
    ->float('weight')                 // FLOAT
    ->bool('is_active')               // BOOLEAN
    ->date('release_date')            // DATE
    ->datetime('published_at')        // BIGINT UNSIGNED (ms timestamp)
    ->json('metadata')                // JSON stored as LONGTEXT
    ->email('contact_email')          // VARCHAR(255) with email validation
    ->slug('url_slug')                // Lowercase alphanumeric, hyphens, underscores
    ->password('secret');             // Hashed with bcrypt

Enums and Status

->enum('priority', ['low', 'medium', 'high'], 'medium')

// Status with state machine flow
->status('status', [
    'draft'     => ['review'],
    'review'    => ['approved', 'rejected'],
    'approved'  => ['published'],
    'rejected'  => ['draft'],
    'published' => []
], 'draft')

References (Foreign Keys)

->ref('category_id', 'category')        // Reference to another model
->ref('owner_id', 'user')
->model_name('target_model')             // Stores a model name string
->model_id('target_id')                  // Stores a model ID

Constraints

->require('name', 'sku')                 // Required fields
->default(['is_active' => true])         // Default values
->unique('idx_sku', ['sku'])             // Unique constraint
->index('idx_category', ['category_id']) // Database index
->no_create('computed_field')            // Cannot set on create
->no_update('sku')                       // Cannot update after creation
->no_delete()                            // Prevent deletion entirely

Built-in Features

->author()                // Adds created_by, updated_by (auto-populated from logged-in user)
->has_v()                 // Optimistic locking with version field
->has_trash()             // Soft delete (status: active/trash)
->has_tags()              // Tagging system
->has_comments(true)      // Comment system
->has_history()           // Audit trail (snapshots on update)
->has_reviews()           // Rating/review system (1-5 stars)
->has_usermarks('like', 'bookmark')  // User marks with auto-counters
->has_datascope()         // Row-level access control
->has_editing_by()        // Concurrent editing lock (via Redis)
->text_search('name', 'description') // Full-text search index

File Uploads (S3)

->s3_image('photo', 800, 400, 200)  // Image with multiple sizes (width)
->s3_file('attachment')              // Generic file upload

Denormalized Counters

->back_ref_count('task_count', 'task', 'project_id')
// Automatically maintains task_count when tasks are created/deleted

Permissions

->create_permission('admin', 'editor')
->read_permission('viewer', 'editor', 'admin')
->update_permission('editor', 'admin')
->delete_permission('admin')
->write_permission('admin')               // Shorthand for create + update + delete

// Owner-based: users can always read/write their own records
->read_permission_or_user_id('admin', 'created_by')
->write_permission_or_user_id('admin', 'created_by')

// Custom permission check
->update_permission_or(['editor'], function(&$context) {
    return $context['model']['owner_id'] === vnbiz_user_id();
})

// Field-level permissions
->read_field_permission(['salary', 'ssn'], 'hr', 'admin')
->write_field_permission(['role'], 'admin')

Users with the super permission bypass all permission checks.

Event Hooks

$model = vnbiz_model_add('order');

// Web layer hooks (before/after HTTP handling)
$model->web_before_create(function(&$context) { /* validate */ });
$model->web_after_create(function(&$context) { /* notify */ });
$model->web_before_update(function(&$context) { /* check */ });
$model->web_after_find(function(&$context) { /* transform */ });

// Database layer hooks (within transaction)
$model->db_before_create(function(&$context) { /* pre-insert logic */ });
$model->db_begin_create(function(&$context) { /* start of transaction */ });
$model->db_after_create(function(&$context) { /* post-insert logic */ });
$model->db_after_commit_create(function(&$context) { /* after commit */ });
$model->db_end_create(function(&$context) { /* cleanup */ });

// After fetch (for computed fields)
$model->db_after_fetch(function(&$context) {
    foreach ($context['models'] as &$m) {
        $m['display_name'] = $m['first_name'] . ' ' . $m['last_name'];
    }
});

UI Metadata

->ui([
    'icon' => 'folder',
    'label' => 'Projects',
    'fields' => [
        'name' => ['label' => 'Project Name'],
    ]
])
->web_readonly('computed_score')    // Read-only in web API
->system_field('internal_flag')     // Marked as system field

RESTful API

Endpoint

All requests go through a single endpoint:

POST /api
Content-Type: application/json
Authorization: Bearer <access_token>

Actions

Create

{
    "action": "model_create",
    "model_name": "project",
    "model": {
        "name": "My Project",
        "description": "A new project"
    }
}

Find

{
    "action": "model_find",
    "model_name": "project",
    "filter": {
        "status": "active"
    },
    "meta": {
        "limit": 10,
        "offset": 0,
        "order": "-created_at",
        "count": true,
        "ref": true,
        "text_search": "keyword"
    }
}

Count

{
    "action": "model_count",
    "model_name": "project",
    "filter": {
        "status": "active"
    }
}

Update

{
    "action": "model_update",
    "model_name": "project",
    "filter": { "id": "abc123" },
    "model": {
        "name": "Updated Name"
    }
}

Delete

{
    "action": "model_delete",
    "model_name": "project",
    "filter": { "id": "abc123" }
}

Service Call

{
    "action": "service_user_login",
    "params": {
        "username": "admin",
        "password": "secret"
    }
}

Filter Operators

{
    "filter": {
        "price": { "$gt": 100 },
        "price": { "$gte": 100 },
        "price": { "$lt": 500 },
        "price": { "$lte": 500 },
        "status": ["active", "pending"],
        "category_id": "encrypted_id"
    }
}

Response Format

{
    "code": "ok",
    "models": [...],
    "count": 42
}

Error response:

{
    "code": "error",
    "error": "permission",
    "error_message": "Permission denied",
    "error_fields": {
        "name": "Name is required"
    }
}

Authentication

Built-in Models

The user module provides three models:

  • user - User accounts (alias, email, username, password, avatar, etc.)
  • usergroup - Permission groups (name, permissions, permissions_scope)
  • useringroup - User-to-group mapping (many-to-many)

Token System

  • Access Token (JWT, 15-minute expiry): Contains user ID, permissions, and permission scopes
  • Refresh Token (JWT): Used to obtain new access tokens

Services

Login

{
    "action": "service_user_login",
    "params": {
        "username": "admin",
        "password": "secret"
    }
}

Refresh Token

{
    "action": "service_user_login",
    "params": {
        "refresh_token": "<token>"
    }
}

Get Current User

{
    "action": "service_user_me"
}

Google OAuth

{ "action": "service_oauth_google_url" }
{ "action": "service_oauth_google_login", "params": { "code": "<oauth_code>" } }

Helper Functions

vnbiz_user()                              // Get current user (or null)
vnbiz_user_id()                           // Get current user ID (or null)
vnbiz_user_or_throw()                     // Require authentication
vnbiz_user_has_permissions('admin')        // Check permission
vnbiz_assure_user_has_permissions('admin') // Throw if missing
vnbiz_user_all_permissions($user_id)       // Get all permissions for a user

Default Admin

{ "action": "service_db_init_default" }

Creates a default superadmin user (superadmin / 1) if no users exist.

Modules

Comment

Nested comment system for any model with has_comments(true).

Fields: model_name, model_id, title, content, parent_comment_id, image, file.

History

Audit trail for models with has_history(). Stores full JSON snapshots on update. No update or delete allowed on history records.

Notification

User notification system.

vnbiz_notification_create($user_id, $title, $content, $payload);

Fields: user_id, title, content, payload (JSON), status (new/viewed).

Also provides notificationtoken model for push notification tokens (FCM/APNs).

Tag

Tagging system for models with has_tags().

vnbiz_model_set_tags('project', $id, ['php', 'api']);
vnbiz_model_get_tags('project', $id);
vnbiz_model_remove_tags('project', $id, ['old-tag']);

Review

Rating/review system for models with has_reviews(). Supports 1-5 star ratings. Automatically maintains review_count, review_count_1..review_count_5, and review_rate on the target model.

Usermark

Bookmark/like system for models with has_usermarks('like', 'bookmark'). Automatically maintains counter fields (number_of_like, number_of_bookmark) and per-user flags (@like_by_me, @bookmark_by_me).

Datascope

Hierarchical row-level access control for models with has_datascope().

Scope format: . (root), .1. (department 1), .1.2. (sub-department). A user with scope .1. can access all rows with scopes .1., .1.2., .1.3., etc. Scopes are stored in the user's permissions_scope.

Editing Lock

Concurrent editing prevention for models with has_editing_by(). Uses Redis with a 15-second TTL. Requires has_v() for optimistic locking.

{ "action": "service_editing_by_me", "params": { "model_name": "project", "model_id": "abc" } }

Namespace (Multi-Tenancy)

Adds a ns field to specified models. All queries are automatically filtered by namespace. Namespace ID comes from the X-Namespace header or ns parameter.

Email

Email sending with template support via the Div template engine.

vnbiz_mail_template_to_user($user_id, 'welcome_email', 'en', ['name' => 'John']);
vnbiz_mail_content_template($to_email, $to_name, $subject, $content, $data);

Template

Named templates stored in database with language support.

vnbiz_render('welcome_email', 'en', ['name' => 'John'], 'Hello {$name}');

S3

AWS S3 file uploads with automatic thumbnail generation.

// On model definition
->s3_image('avatar', 800, 200)  // Generates 800px and 200px versions
->s3_file('document')           // Generic file upload

Uploaded files get signed URLs with 24-hour expiry.

Redis

vnbiz_redis()                          // Get Redis connection
vnbiz_redis_get_array($key)            // Get JSON value
vnbiz_redis_set_array($key, $data, $ttl)  // Set JSON value (default 1hr TTL)
vnbiz_redis_del($key)                  // Delete key

Also tracks request counters per action/model for monitoring.

System Config

Key-value configuration stored in database.

vnbiz_systemconfig_set('site_name', 'My App');
vnbiz_systemconfig_get('site_name');  // 'My App'

Monitor

vnbiz_monitor();          // Display system stats (hostname, CPU, memory, load)
vnbiz_monitor_request();  // Display per-action request counters from Redis

Schema Generation

vnbiz_echo_jsonschema();          // Output JSON Schema (Draft 2020-12)
vnbiz_echo_typescript_schema();   // Output TypeScript interfaces

SQL Migrations

// Generate SQL without executing
$sql = vnbiz_sql_generate();

// Generate and execute migrations
vnbiz_sql_alter_tables();

// Generate, execute, and echo output
vnbiz_sql_alter_tables_echo();

Migrations automatically add/modify columns and indexes. Existing data is preserved.

Utility Functions

// Safe variable access
vnbiz_get_var($var, $default)
vnbiz_get_key($array, 'key', $default)

// ID encryption (Hashids)
vnbiz_encrypt_id(42)         // -> 'xYz123'
vnbiz_decrypt_id('xYz123')  // -> 42

// Action system
vnbiz_do_action('my_action', $context)
vnbiz_add_action('my_action', function(&$ctx) { /* ... */ })
vnbiz_do_service('my_service', ['param' => 'value'])

// Misc
vnbiz_now()                     // Current UTC datetime string
vnbiz_random_string(32)         // Random alphanumeric string
vnbiz_unique_text()             // Unique 32-char hex string
vnbiz_generate_thumbnail($src, $dst, $w, $h)  // Create thumbnail (Imagick)

Services

Built-in Services

Service Description
service_health_check Check MySQL and Redis connectivity
service_sys_schemas Return all model schemas
service_user_login Login with username/password or refresh token
service_user_me Get current authenticated user
service_user_logout Logout
service_db_init_default Create default superadmin user
service_oauth_google_url Get Google OAuth authorization URL
service_oauth_google_login Exchange OAuth code for tokens
service_editing_by_me Claim editing lock on a record

Custom Services

vnbiz_add_action('service_my_custom', function(&$context) {
    $params = $context['params'];
    // ... business logic ...
    $context['models'] = [$result];
});

Error Handling

Errors are thrown as VnBizError exceptions with structured information:

throw new VnBizError('Item not found', 'not_found');
throw new VnBizError('Validation failed', 'invalid', ['name' => 'Name is required']);
throw new VnBizError('Forbidden', 'permission');  // HTTP 403

The RESTful handler catches all exceptions and returns proper JSON error responses with appropriate HTTP status codes.

Logging

L()->debug('message');
L()->info('message');
L()->error('message');
L_withName('MyModule');        // Set logger context
vnbiz_debug_enabled();         // Check if debug mode is on

Debug mode is enabled via the VNBIZ_DEBUG environment variable or debug GET parameter.

License

Apache-2.0