Your browser's JavaScript is currently disabled!

  Please enable JavaScript on your browser to use all features of this site or upgrade to a Javascript-capable browser.

Quick Demo

This website is built in EB Web Framework and in this demo, we will give you quick insight on how route mapping works in connection to SPA of this page. In an example here, indicated below is the Route Configuration of Route Map file for this demo page https://spafw.ebhub.net/demo, which indicates this page's protocol[0], subdomain[1], domain directory[2], index file[3], port[4], path[5], request method[6], back-end response process[7], rootlink type [8], optional front-end response render[9], syslink type[10], encryption method [11], short link switch[12], anonymous link switch[13], theme[14], link's children[15] and the optional general options [16]. For a complete guide, please check our documentation Documentation::Route Configuration.

Every link, whether for the Web or an API, will pass through the Route Map file. On each link may contain children, in which each link can optionally have their own distinct header, SPA links and validation. For example, if you have only static page, you can have an empty children or if you have an API link, it can have its distinct response header and Public-encrypted-random password Encrypted content while your own server will Private Decrypt the random password-encrypted content sent by the 3rd Party Server. Possibilities are endless.


return [

  ['http/s', $subdom, $alias, '', -1,
      'APIDEMO/req:version/opt:optional',
      'any:any', // get+post+delete+put+patch
      'class:demo_mainroute/endpoint',
      'api',
      'none', 'syslink:yes', 'encrypt:none', false, false, 'routehub',
    []
  ],

  ['http/s', $subdom, $alias, '', -1,
      'TESTAPI/req:type/req:method/req:package',
      'get:np', // for Browser viewing
      'class:demo_mainroute/test_api',
      'static',
      'none', 'syslink:yes', 'encrypt:none', false, false, 'routehub',
    []
  ]

  ['http/s', 'spafw', '', '', -1,
      'DEMO/opt:path_optionalentry',
      'any:any',
      'class:demo_mainroute/process_demopage',
      'static',
      'none', 'syslink:yes', 'encrypt:none', false, false, 'routehub',
    [

      ['header:X-Header-for-this-Link/This is a Demo only', true],

      ['ajaxhash:ajaxhash_id', 'class:demo_mainroute/process_ajaxhash', 60, 0, false, 0],

      ['ajaxmark:ajaxmark_id', 'class:demo_mainroute/process_ajaxmark', 60, 0, false, 0],

      ['ajaxpost:ajaxpost_id', 'class:demo_mainroute/process_ajaxpost', 60, 0, false, 0,
        [  // Title Name, Validation Type, Required, MinLen, MaxLen, Attributes, Hint, Value, Tooltip
         ['ob:text/ajaxpost_field1', 'AjaxPost Field1', 'none',  'required', 5, 80, '',  'Text', '', 'tooltip1'],
         ['ob:text/ajaxpost_field2', 'AjaxPost Field2', 'email', 'required', 0,  0, '', 'Email', '', 'tooltip2'],
         ['ob:file/ajaxpost_field3', 'AjaxPost Field3', 'none',  'required', 0,  0, '',      '', '', 'tooltip3'],
         ['ob:file/ajaxpost_field4', 'AjaxPost Field4', 'none',  'required', 0,  0, '',      '', '', 'tooltip4']
        ]
      ],

      ['syncpost:syncpost_id', 'class:demo_mainroute/process_syncpost', 60, 0, false, 0, 'none', 'syslink:yes',
        [
         ['ob:text/syncpost_field1', 'SyncPost Field1', 'none',  'required', 5, 80, '',  'Text', '', 'tooltip1'],
         ['ob:text/syncpost_field2', 'SyncPost Field2', 'email', 'required', 0,  0, '', 'Email', '', 'tooltip2'],
         ['ob:file/syncpost_field3', 'SyncPost Field3', 'none',  'required', 5, 80, '',      '', '', 'tooltip3'],
         ['ob:file/syncpost_field4', 'SyncPost Field4', 'none',  'required', 0,  0, '',      '', '', 'tooltip4']
        ]
      ]
    ]

  ]

];
                

PHP Code to launch this page:
Note: The name of responents are not system name, which means you can change them to your liking.


public static function process_demopage ($coreponents) {

  // Set Response Component, which will be transferred to Sub-Page 'rv-demopage.php' below
  eb_setresponents('path_optionalentry', $coreponents['caller']['pathvars']['path_optionalentry']);

  // Fetch process render file /ebhub/app/projects/[APPCODE]/kernel/core/response/render/view/rv-demopage.php
  $response_content = eb_openfile('response/render/view', 'rv-demopage');

  // Set Page Response Component, which will be transferred to main page
  eb_setresponents('title_name', 'This is a Demo Page');

  // Set Main Page Response Component=>Response Content
  eb_setresponents('response-content', $response_content);

  return;
}
                

Route Entry Optional Value:
If you change the URL from spafw.ebhub.net/demo to spafw.ebhub.net/demo/testing123, then the value at the bottom will be 'testing123'. This value can be fetched from $coreponents['caller']['pathvars']['path_optionalentry'], where 'path_optionalentry' is the user-defined name indicated in the Route Map.

API Request Demo

Verifying hCaptcha's User Response:


    $coreponents = EB::$coreponents;  // Fetch Coreponents
    $structure = [
      'destination'   =>  'https://hcaptcha.com/siteverify',
      'request_type'  =>  'post-text',
      'response_type' =>  'json',
      'method'        =>  'POST',
      'headers'       =>  [
        // NOT allowed here are: Accept, Content-Type, Content-Length, Date, User-Agent
        "Accept-Charset: utf-8",  // Optional
      ],
      'user_agent'    =>  'EB Web Framework v1.03 / APIHub', // Optional
      'body'   =>  [
        'response'  =>  1234567,  // Verification Token emitted
        'remoteip'  =>  $coreponents['caller']['ip_address'],
        'secret'    =>  $coreponents['config']['local']['app']['keys']['hCaptcha']['secret'] // from Secondary Application Configuration
      ]
    ];
    $ebhubapi = eb_autoload('apihub');
    $response = $ebhubapi->Send($structure);
    $content = $response['Response']['_Body']; // this now contain the hCaptcha JSON Response
                

APIHub Response:


Array
(
    [Response] => Array
        (
            [Code] => 200
            [Header] => Array
                (
                    [Date] => Tue, 09 Jun 2020 21:07:52 GMT
                    [Content-Type] => application/json
                    [Content-Length] => 80
                    [Connection] => keep-alive
                    [Set-Cookie] => INGRESSCOOKIE=1234567; Path=/; HttpOnly
                    [CF-Ray] => 1234567-MNL
                    [Accept-Ranges] => bytes
                    [Strict-Transport-Security] => max-age=2592000; includeSubDomains; preload
                    [CF-Cache-Status] => DYNAMIC
                    [cf-request-id] => 1234567
                    [Expect-CT] => max-age=604800, report-uri="https://report-uri.cloudflare.com/cdn-cgi/beacon/expect-ct"
                    [X-Content-Type-Options] => nosniff
                    [X-ESID] => 1234567
                    [Server] => cloudflare
                    [alt-svc] => h3-1234567=":1234567"; ma=1234567
                )

            [_Body] => Array
                (
                    [success] => 1
                    [challenge_ts] => 2020-06-09T21:07:48
                    [hostname] => example.com
                )

        )

    [Request] => Array
        (
            [Destination] => https://hcaptcha.com/siteverify
            [Method] => POST
            [Header] => Array
                (
                    [Accept-Charset] => utf-8
                    [Accept] => application/json
                    [Content-Type] => application/x-www-form-urlencoded
                    [Date] => Thu, 11 June 2020 02:42:08 GMT
                    [Content-Length] => 2950
                )

            [Body] => Array
                (
                    [response] => 1234567-VerificationToken
                    [remoteip] => 127.0.0.1
                    [secret] => SecretKey
                )

        )

)
                

API Response Demo

Tic-Tac-Toe is a game for two players, X and O , who take turns marking the spaces in a 3x3 grid. The player who succeeds in placing three of their marks in a horizontal, vertical, or diagonal row wins the game. Joining the battle only needs your name and you need to finish the game before joining or starting a new one. Of course, unless you create a new game using a different name. Only the player (Player1) who started the game or the Initiator is allowed to make the first move after the game is matched or when Player2 joined the game. Player1 will have the X-marker while Player2 will have the O-marker. The board marker is represented as A1=Top Left, A2=Top Center, A3=Top Right, B1=Middle Left, B2=Middle Center, B3=Middle Right, C1=Bottom Left, C2=Bottom Center, C3=Bottom Right. An API Test Link has been provided below to quickly play the game. It is advisable to use Firefox to view the response properly.

Joining a Battle or Create a New One:


PUT | POST https://spafw.ebhub.net/apidemo/v1

Header:
  "Accept: application/json",
  "Authorization: Bearer 1234567890",
  "Content-Type: application/json",
  "User-Agent: EBHub-API_Identifier"

Body:
{
  "type"  : "joinbattle",
  "player": "Bernard"
}
                
API Browser Test:

https://webframework.ebhub.net/testapi/json/post/type=joinbattle+player=bernard
https://webframework.ebhub.net/testapi/json/put/type=joinbattle+player=sheila


Show Game Details:


GET      https://spafw.ebhub.net/apidemo/v1

Header:
  "Accept: application/json",
  "Authorization: Bearer 1234567890",
  "Content-Type: application/json",
  "User-Agent: EBHub-API_Identifier"

Body:
{
  "type"  : "showdetails",
  "gameid": 1234567890
}
                
API Browser Test:

https://webframework.ebhub.net/testapi/json/get/type=showdetails+gameid=1234567890


Place Game Marker:


PATCH    https://spafw.ebhub.net/apidemo/v1

Header:
  "Accept: application/json",
  "Authorization: Bearer 1234567890",
  "Content-Type: application/json",
  "User-Agent: EBHub-API_Identifier"

Body:
{
  "type"  : "placemarker",
  "gameid": 1234567890,
  "player": "bernard",
  "mark"  : "a1"
}
                
API Browser Test:

https://webframework.ebhub.net/testapi/json/patch/type=placemarker+gameid=1234567890+player=bernard+mark=a1


Delete a Game:


DELETE   https://spafw.ebhub.net/apidemo/v1

Header:
  "Accept: application/json",
  "Authorization: Bearer 1234567890",
  "Content-Type: application/json",
  "User-Agent: EBHub-API_Identifier"

Body:
{
  "type"  : "purgegame",
  "gameid": 1234567890
}
                
API Browser Test:

https://webframework.ebhub.net/testapi/json/delete/type=purgegame+gameid=1234567890


API Route:


$class_api = eb_autoload('apihub');
// =========================
// Note:
// ALL Elements are OPTIONAL unless marked as Required
// Only Single Request Entry will manifest multiple errors (if indicated)
// Error will default to 404 & its default error message if no custom error is indicated
// Custom Error Status Codes are automatically limited to standard 4XX codes. Otherwise, it will revert to 404.
// While successful custom HTTP Codes are automatically limited to standard 2XX codes. Otherwise, it will revert to 200.
//
// If entry is successfully found:
// Client Content     = $coreponents['api']['client_content']
// API Elements       = $coreponents['api']['user_elements']
// Chosen Parameters  = $coreponents['api']['user_selected']
// =========================
$response = $class_api->sethub(
  [
      "request" => [  // this is REQUIRED
          [ // ======================== Entry #1: API_CREATE
              "process" =>  "class:Demo_MainRoute/api_create",  // this is REQUIRED

              "method"  =>  [  // this is REQUIRED
                  "value"   =>  ['put', 'post']
              ],

              "content"  =>  [
                  "params"  =>  [
                      "player",
                      "type"   =>  [
                          "value" =>  "joinbattle"
                      ]
                  ]
              ]
          ],
          [ // ======================== Entry #2: API_READ
              // this will run Demo_MainRoute::api_read($coreponents)
              // but you can also set it up to run:
              //  Individual File (kernel/core/process/main/route/api),
              //  Closure or Function
              "process" =>  "class:Demo_MainRoute/api_read",  // this is REQUIRED

              "method"  =>  [  // this is REQUIRED
                  "value"   =>  ['get'],  // All Unique Values will be included in the header: Access-Control-Allow-Methods
                  "errors"  =>  [415, 'Invalid API Endpoint Method'] // Optional
              ],

              "content"  =>  [ // Optional
                  "type"    =>  "json", // JSON is the only supported Type as of this time.
                  "params"  =>  [
                      "gameid", // no value means no specific value
                      "type"   =>  [
                          "value" =>  "showdetails"
                      ]
                  ],
                  "errors"  =>  [415, 'Invalid API Content Parameters'] // Optional
              ],

              "route"  =>  [ // Optional
                  [
                    "value"   =>  "apidemo/v1",
                    "errors"  =>  [415, 'Invalid API Endpoint Version'] // Optional for Route Key
                  ]
              ],

              "header"  =>  [ // Optional
                  "Accept" =>  [
                      [
                          "value"  =>  "application/json",
                          "attrib"  =>  ['exactly'],  // if absent, 'exactly' is the default
                          "errors"=>    [415] // Optional for Header Key
                      ],
                      [
                          "value"  =>  "application/json",
                          "attrib"  =>  ['contains'],
                          "errors"=>    [406]
                      ]
                  ]
              ],

              // =========================
              // to Override Global Settings (if exists) but this is Optional
              // If error occurred, some of the Individual and User Settings will not apply and
              // only Global Settings will take over if existing
              //
              // User's Response Process can also override this using ['_settings'] response
              // However, using User's Settings will only affect is_header, is_sandbox, charset, language, and currency
              // You can also set your customized settings that can be accessed on process
              // =========================
              "settings" =>  [
                  "is_header"     =>  false,   // if Global is true and this is false, this will be the chosen one
                  "is_lowercase"  =>  true,
                  "is_test"       =>  false,
                  "is_sandbox"    =>  false,
                  "charset"       =>  'utf-8',
                  "language"      =>  'en',
                  "currency"      =>  null,
              ],

              // =========================
              // to Override Global Payload (if exists) but this is Optional
              // User's Response Process can also override this using ['_payload'] response
              // =========================
              "payload" =>  [
                 // "TestPayLoad_Overriding"  =>  'Individual',
                 // "TestPayLoad_Individual"  =>  '1234'
              ]
          ],
          [ // ======================== Entry #3: API_UPDATE
              "process" =>  "class:Demo_MainRoute/api_update",  // this is REQUIRED

              "method"  =>  [  // this is REQUIRED
                  "value"   =>  ['patch']
              ],

              "content"  =>  [
                  "params"  =>  [
                      "gameid",
                      "player",
                      "mark",
                      "type"   =>  [
                          "value" =>  "placemarker"
                      ]
                  ],
              ]
          ],
          [ // ======================== Entry #4: API_DELETE
              "process" =>  "class:Demo_MainRoute/api_delete",  // this is REQUIRED

              "method"  =>  [  // this is REQUIRED
                  "value"   =>  ['delete']
              ],

              "content"  =>  [
                  "params"  =>  [
                      "gameid",
                      "type"   =>  [
                          "value" =>  "purgegame"
                      ]
                  ],
              ]
          ]
      ],

      // ========================= COMMON ATTRIBUTES
      // This would be the common attributes of the whole Request Entries such as route, header and content
      // However, no priorities are given to both Common and Individual Entry
      // =========================
      "common"  =>  [
          "route"  =>  [
              [
                "value"   =>  "apidemo/v1",
                "errors"  =>  [415, 'Invalid API Endpoint Version']
              ]
          ],

          "header"  =>  [
              "Authorization" =>  [
                  ["value"=>"Bearer", "attrib"=>['contains'], "errors"=>[406]]
              ]
          ],

          // =========================
          // If you wanted to individualized Request Entry with different settings,
          // you can put this array in every request with specific settings for particular entry
          // You can also set your customized settings that can be accessed on process
          // =========================
          "settings" =>  [
              "is_header"     =>  true,     // Include Default Header. Default: true
              "is_lowercase"  =>  true,     // All comparison will be Case-Insensitive. Default: true
              "is_test"       =>  false,    // Developer Test Mode. Default: false
              "is_sandbox"    =>  false,    // User Sandbox Mode. Default: false
              "charset"       =>  'utf-8',  // ISO/IEC 10646. Default: utf-8
              "language"      =>  'en',     // ISO 639-1 Language Code. Default: en
              "currency"      =>  null,     // ISO 4217 Currency Code. Default: null
              // =========================
              // Signature is based from Hash_HMAC sourced from the Shared Key from
              // Client Public Key (from the Header:EB-ClientSign-PubKey) and
              // Server's Private Key, wherein Client verification will be based from the Shared Key
              // created from Server's Public Key (Server_PubKey) and Client's stored Private Key
              // =========================
              "signature"     =>  [ // Removing all or part of this array will disable Signature generation
                  "hashalgo"      =>  'sha512'
              ],
              "verify"        =>  []  // Future feature that incorporates JWT and other authentication protocol
          ],

          // =========================
          // This will be the components that you wanted to attached to the response along with Content & Errors
          // This can also be individualized in every Request Entry
          // =========================
          "payload" =>  [
             // "TestPayLoad_Overriding"  =>  'Global',
             // "TestPayLoad_Global"  =>  '4567',
              "Header"  => [
                  "Application"  =>  [
                    "Name"        =>  "EB Web Framework",
                    "Version"     =>  1,
                    "Is_Latest"   =>  true
                  ]
              ]
          ],

          // =========================
          // These are completely Optional as they already have their own default error messages
          // =========================
          "errors"  =>  [
              "header_field_notfound"     =>  null, // 104
              "request_content_empty"     =>  null, // 106
              "request_content_invalid"   =>  null, // 112
              "response_user_invalid"     =>  null, // 116
              "client_credential_invalid" =>  null  // 118/120
          ]
      ]
  ]
);
return [$response['content-body'], $response['content-type'], $response['http-code']];  // API Output from the Class
                

API Process:


public static function api_read ($coreponents) {
  // ==================
  // Client Path        = $coreponents['caller']['pathonly']
  // Client Query       = $coreponents['caller']['parts']['query'];  or $coreponents['caller']['query'] for String
  // Client Header      = $coreponents['caller']['header'];
  // Client Content     = $coreponents['api']['client_content']
  // API Elements       = $coreponents['api']['user_elements']
  // Chosen Parameters  = $coreponents['api']['user_selected']
  // Response Headers   = eb_setheader('X-MyHeader', '1234');
  //                      eb_setheader('Expires', eb_getconst("DATETIME_YEARAHEAD"));
  //
  // API Test: /testapi/json/get/type=showdetails+gameid=1234567890
  // ==================
  $clientbody = [];
  $clientbody['gameid'] = $coreponents['api']['client_content']['gameid'];
  // ==================
  // Check if Game ID exists
  // ==================
  $retval = EB\Database\Root::Execute([
      "dbconn"  =>  $coreponents['app']['database']['connection']['demo_db'],

      "sql"     =>  "SELECT * "
                  . "FROM tictactoe "
                  . "WHERE game_idpk = :game_idpk;",

      "error"   =>  [602, 'Database', 'Unable to Query the Game'],  // PDO Exception API Response Error Message

      "bind"    =>  [
          ':game_idpk' =>  $clientbody['gameid']
      ]
  ]);
  //  ----------------
  //     Game Board
  //  ----------------
  //  | A1 | A2 | A3 |
  //  ----------------
  //  | B1 | B2 | B3 |
  //  ----------------
  //  | C1 | C2 | C3 |
  //  ----------------
  $matched_result = $retval['pdo_statobj']->fetchAll(PDO::FETCH_ASSOC);
  if (isset($matched_result[0]) AND count($matched_result) > 0) {
    // ==================
    // Show Game Details
    // ==================
    $gameboard = $matched_result[0]['game_board'];
    $boardgame = explode('+', $gameboard);
    $player1_movement = [];
    foreach ($boardgame as $boardkey=>$boardvalue) {
      if ($boardvalue == 'X') {
        $player1_movement[] = self::$markers[$boardkey];
      }
    }
    $player1_movement = implode(', ', $player1_movement);
    $player2_movement = [];
    foreach ($boardgame as $boardkey=>$boardvalue) {
      if ($boardvalue == 'O') {
        $player2_movement[] = self::$markers[$boardkey];
      }
    }
    $player2_movement = implode(', ', $player2_movement);
    $gameboard = [];
    foreach ($boardgame as $boardkey=>$boardvalue) {
      if ($boardvalue == 'B') {
        $gameboard[] = self::$markers[$boardkey];
      } else {
        $gameboard[] = $boardvalue;
      }
    }
    $gameboard = implode('+', $gameboard);
    if ($matched_result[0]['game_status'] == 'unmatched') {
      $game_status = '[Unmatched]::Waiting for Player2';
    } else {
      $game_status = $matched_result[0]['game_status'];
    }
    // returning any value will be futile as it needs an
    // EB\Response\API Exception to give a proper response
    throw new EB\Response\API([
        "Code"        =>  700,
        "Status"      =>  $game_status,
        "GameID"      =>  $clientbody['gameid'],
        "Board"       =>  $gameboard,
        "Player1"     =>  ucwords($matched_result[0]['player1']),
        "Player1Move" =>  $player1_movement,
        "Player2"     =>  ucwords($matched_result[0]['player2']),
        "Player2Move" =>  $player2_movement,
        "Last_Moved"  =>  $matched_result[0]['lastmoved'],
        "Winner"      =>  $matched_result[0]['winner']
    ]);
  } else {
    // ==================
    // Error Occurred
    // ==================
    throw new EB\Response\API([604, 'Game', 'Invalid Game ID or Unable to Query the Game']); // do not give a clue
  }
  return;
}
                

AjaxPost Demo

PHP Code:


public static function process_ajaxpost ($coreponents) {
  $xml_message = self::process_syncpost($coreponents);  // please refer to SyncPost Demo for process_syncpost
  $xml_errorcode = 0;
  $xml_is_cache = false;
  return array($xml_message, $xml_errorcode, $xml_is_cache);
}
                

HTML Code:
Note: placeholder, value and title are optional. AjaxPost and SyncPost are basically the same with the only exception: AjaxPost has mandatory presence of onsubmit="return false;" on form's attribute. CSRF is already built-in in HTML ID. However, in certain circumstances such as implementing your own events, hidden CSRF is required.


<div id="ajaxpost_ajaxpost_id">
  <form id="ajaxpost_id"
  onsubmit="return false;"
  >

    <input type="text"
                  name="<?php echo eb_getresponents()['html_form']['ajaxpost_id']['ajaxpost_field1']['name']; ?>"
           placeholder="<?php echo eb_getresponents()['html_form']['ajaxpost_id']['ajaxpost_field1']['hint']; ?>"
                 value="<?php echo eb_getresponents()['html_form']['ajaxpost_id']['ajaxpost_field1']['value']; ?>"
                 title="<?php echo eb_getresponents()['html_form']['ajaxpost_id']['ajaxpost_field1']['tooltip']; ?>"
    />

    <input type="email"
                  name="<?php echo eb_getresponents()['html_form']['ajaxpost_id']['ajaxpost_field2']['name']; ?>"
           placeholder="<?php echo eb_getresponents()['html_form']['ajaxpost_id']['ajaxpost_field2']['hint']; ?>"
                 value="<?php echo eb_getresponents()['html_form']['ajaxpost_id']['ajaxpost_field2']['value']; ?>"
                 title="<?php echo eb_getresponents()['html_form']['ajaxpost_id']['ajaxpost_field2']['tooltip']; ?>"
    />

    <input type="file" multiple
            name="<?php echo eb_getresponents()['html_form']['ajaxpost_id']['ajaxpost_field3']['name']; ?>"
           title="<?php echo eb_getresponents()['html_form']['ajaxpost_id']['ajaxpost_field3']['tooltip']; ?>"
    />

    <input type="file" multiple
            name="<?php echo eb_getresponents()['html_form']['ajaxpost_id']['ajaxpost_field4']['name']; ?>"
           title="<?php echo eb_getresponents()['html_form']['ajaxpost_id']['ajaxpost_field4']['tooltip']; ?>"
    />

    <input type="submit" value="Send"/>
  </form>
</div>
              

Javascript Code:


var ebhubjs = {
  ajaxpostprior: function ($identity, $post_query, $field_elements) {  // Client-side validation
    // return True if successful and False if failed
    // or return Array with values that will be sent to Server; e.g., ['mydata1', 'mydata2']
    return true;
  },

  ajaxpostcontent: function ($identity, $content, $is_nocontent) {
    ebhub.renderpage($identity, $content);
    return;
  }

  ajaxposterror: function ($identity, $error_code, $error_message) {
    // Errors coming from the Server
    alert($error_message);
    return;
  }
};
                

SyncPost Demo

PHP Code:


public static function process_syncpost ($coreponents) {
  if ($coreponents['caller']['post']['is_submit'] == true) {
    // ========================= POST SUBMITTED ALREADY
    // Note: you can clear this using EB\Session\Root::del($coreponents['app']['session']['tag']['post_submit']);

    // Set Response Component=>Page Title
    eb_setresponents('title_name', 'Test Validation Submitted Already');

    // Fetch process render file /ebhub/app/projects/[APPCODE]/kernel/core/response/render/view/rv-demosubmitted.php
    $response_content = eb_openfile('response/render/view', 'rv-demosubmitted');

    // Set Response Component=>Response Content
    eb_setresponents('response-content', $response_content);

    // hybrid return that serves both AjaxPost & SyncPost
    return $response_content;

  } else {

    // ========================= POST NOT YET SUBMITTED, NOW CHECK VALIDATION

    if ($coreponents['caller']['post']['input']['_success'] == true) {
      // ========================= VALIDATION SUCCESS

      // Set Response Component=>Page Title
      eb_setresponents('title_name', 'Test Validation Success');

      // Fetch process render file /ebhub/app/projects/[APPCODE]/kernel/core/response/render/view/rv-demosuccess.php
      $response_content = eb_openfile('response/render/view', 'rv-demosuccess');

      // Set Response Component=>Response Content
      eb_setresponents('response-content', $response_content);

      // hybrid return that serves both AjaxPost & SyncPost
      return $response_content;

    } else {
      // ========================= VALIDATION FAILED

      // Set Response Component=>Page Title
      eb_setresponents('title_name', 'Test Validation Failed');

      // Fetch process render file /ebhub/app/projects/[APPCODE]/kernel/core/response/render/view/rv-demofailed.php
      $response_content = eb_openfile('response/render/view', 'rv-demofailed');

      // Set Response Component=>Response Content
      eb_setresponents('response-content', $response_content);

      // hybrid return that serves both AjaxPost & SyncPost
      return $response_content;

    }
  }
}
                

HTML Code:
Note: placeholder, value and title are optional. AjaxPost and SyncPost are basically the same with the only exception: AjaxPost has mandatory presence of onsubmit="return false;" on form's attribute. CSRF is already built-in in HTML ID. However, in certain circumstances such as implementing your own events, hidden CSRF is required.


<form id="syncpost_id">

  <input type="text"
                name="<?php echo eb_getresponents()['html_form']['syncpost_id']['syncpost_field1']['name']; ?>"
         placeholder="<?php echo eb_getresponents()['html_form']['syncpost_id']['syncpost_field1']['hint']; ?>"
               value="<?php echo eb_getresponents()['html_form']['syncpost_id']['syncpost_field1']['value']; ?>"
               title="<?php echo eb_getresponents()['html_form']['syncpost_id']['syncpost_field1']['tooltip']; ?>"
  />

  <input type="email"
                name="<?php echo eb_getresponents()['html_form']['syncpost_id']['syncpost_field2']['name']; ?>"
         placeholder="<?php echo eb_getresponents()['html_form']['syncpost_id']['syncpost_field2']['hint']; ?>"
               value="<?php echo eb_getresponents()['html_form']['syncpost_id']['syncpost_field2']['value']; ?>"
               title="<?php echo eb_getresponents()['html_form']['syncpost_id']['syncpost_field2']['tooltip']; ?>"
  />

  <input type="file" multiple
          name="<?php echo eb_getresponents()['html_form']['syncpost_id']['syncpost_field3']['name']; ?>"
         title="<?php echo eb_getresponents()['html_form']['syncpost_id']['syncpost_field3']['tooltip']; ?>"
  />

  <input type="file" multiple
          name="<?php echo eb_getresponents()['html_form']['syncpost_id']['syncpost_field4']['name']; ?>"
         title="<?php echo eb_getresponents()['html_form']['syncpost_id']['syncpost_field4']['tooltip']; ?>"
  />

  <input type="submit" value="Send"/>
</form>
                

AjaxHash Demo

PHP Code:


public static function process_ajaxhash ($coreponents) {
  $xml_message = 'this is my test Hash message';
  $xml_errorcode = 0;
  $xml_is_cache = true;
  return array($xml_message, $xml_errorcode, $xml_is_cache);
}
                

HTML Code:


<a href="#ajaxhash_id">Click Me to show you the correct hash message from the server.</a>
<a href="#testwrong">This is Wrong Hash.</a>
                

Javascript Code:


var ebhubjs = {
  hashprior: function ($identity) {
    // return True if successful and False if failed
    // or return Array with values that will be sent to Server; e.g., ['mydata1', 'mydata2']
    return true;
  },

  hashcontent: function ($identity, $content, $is_nocontent) {
    alert($content);
    return;
  },

  hasherror: function ($identity, $error_code, $error_message) {
    // Errors coming from the Server
    return;
  }
};
                

AjaxMark Demo

Click Me to show you the correct Mark message from the server.

This is Wrong Mark

PHP Code:


public static function process_ajaxmark ($coreponents) {
  $xml_message = 'this is my test Mark message';
  $xml_errorcode = 0;
  $xml_is_cache = true;
  return array($xml_message, $xml_errorcode, $xml_is_cache);
}
                

HTML Code:


<p class="eb_ajaxmark" ebhub="ajaxmark_id">Click Me to show you the correct Mark message from the server.</p>
<p class="eb_ajaxmark" ebhub="testwrong">This is Wrong Mark</p>
                

Javascript Code:


var ebhubjs = {
  markprior: function ($identity) {
    // return True if successful and False if failed
    // or return Array with values that will be sent to Server; e.g., ['mydata1', 'mydata2']
    return true;
  },

  markcontent: function ($identity, $content, $is_nocontent) {
    alert($content);
    return;
  },

  markerror: function ($identity, $error_code, $error_message) {
    // Errors coming from the Server
    return;
  }
};
                

Javascript Code (Non-Event Initiation):


ebhub_ajaxmark.ajax('ajaxmark_id');