APIQL 0.3 - Скрипт обработки команд языка запросов
Вход Регистрация

APIQL 0.3 - Скрипт обработки команд языка запросов

Скрипт нужен для определения и выполнения команд языка запросов. Он может определять собственные команды заданного пользователем языка запросов, с помощью определения синтаксиса этих команд. Скрипт компилирует вызовы команд путем создания PHP-кода, который выполняется после отправки возможных аргументов команды.

APIQL является инструментом для достижения простого и легкого способа использования интерфейса для ваших программ.

С APIQL можно создавать запросы, которые взаимодействуют с возложенных на них функциями, использование дополнительных аргументов и выполнения операций, запросов и т.д., соблюдая определённый синтаксис. с APIQL структура данных сохраняется, и выбирается JavaScript синтаксис для каждого типа информации.

Таким образом, вы можете использовать JSON объекты, массивы, логические значения или нулевые, числа и строки. Будет просто, например, создать базу данных в текстовом файле, а также набор запросов для управления ей.

И не только это, вы также можете создать API систему, которая отражает форму классических реляционных запросов базы данных и управлять результатами в условиях полной свободы.

Вы можете определять части запроса простым и интуитивно понятным способом, необходимые и дополнительное параметры запроса тоже. Ознакомьтесь с документацией, чтобы лучше понять, как APIQL может Вам помочь!

Лицензия BSD.

Системные требования скрипта:

PHP не младше 5.0 версии.

Исходник скрипта


/*
APIQL v. 0.3

Name        :   APIQL
Author      :   Temperini Mirko
Description :   a custom api builder based on js notation,
                to semplify you development application.
                With this tool you can build your query with your custom
                syntax/command
Version     :   0.3
Date        :   2011-07-17
Email       :   dottwatson@gmail.com
Licence     :   GPL




APIQL   gives you the possibility to build your own queries with data,personal syntax and commands.
        It is based on a model where you can define in order:
        -if the command in required or optional
        -the command name
        -the command data accepted. The command data can be:
            -string
            -int
            -float
            -boolean
            -null
            -array   a javascript array notation e.g. ["bar","foo",24]
            -json   a json string e.g. {bar:foo,"surname":doe,age:32}
            -php code

APIQL supports subqueries

APIQL supports events as 'beforeQuery' , 'afterQuery' and 'error'

APIQL gives you a nice tool for convert not well formed json strings into a valid PHP JSON strings


How it works?

step 1: declare a model
step 2: register model and bind it to function
step 3: call your query

e.g.

apiql::register('!set/!new friend[json]','new_friend');

apiql::query('set new friend {name:bar,surname:foo}',25);

function new_friend($sql,$age){
    echo 'you have requested to set a new friend as<br />';
    var_dump($sql['new friend']);
    echo "<br />the age of {$sql['new friend']['name']} is $age<br />";
    }


See examples how to configure and use APIQL
*/



class apiql{
    public static $syntax       =   array();
    public static $callback     =   '';
    public static $isValid      =   false;
    public static $data         =   null;
    public static $error        =   '';
    public static $events       =   array(
        'afterQuery'    =>array(),
        'beforeQuery'   =>array(),
        'error'         =>array(),
        );

    private static $config=array(
        'check_func_exists'=>false,
        'display_errors'=>false,
        'error_level'=>E_USER_WARNING
        );


    /*
    * access:       public
    * description:  sets your class configuration to prevent
    *               or not function exixtence,display errors
    * vars:         what    [string]    the configuration param name
    *               val     [bool/int]  the value of the param
    *
    *returns:      null
    */
    public static function set($what='',$val=false){
        $what=(string)$what;
        if(isset(self::$config[$what])){
            self::$config[$what] = $val;
            }
        }

    /*
    * access:       public
    *
    * description:  get your class configuration param value
    *
    * vars:         what    [string]    the configuration param name
    *
    *returns:      the value on success, null on faailure
    */
    public static function get($what=''){
        $what=(string)$what;
        if(isset(self::$config[$what])){
            return self::$config[$what];
            }
        return null;
        }


    /*
    * access:   public
    * vars: model   [string]    the query model to parse
    *       fn      [string]    the function name to bind the query
    *
    * return:   true on success or false on failure
    */
    public static function register($model='',$fn=''){
        $elements=explode('/',$model);
        foreach($elements as $el){
            $tmp=array(
                'model'     =>trim($el),
                'required'  =>false,
                'data_type' =>array(),
                'callback'  =>''
                );

            preg_match('/^
                (?P<required>!|\?)
                (?P<name>[a-z0-9_-\s]+)
                (?P<data_type>(\[([a-z\s]+,?)+\])|$)
                /xi',$el,$blocks);


            if(empty($blocks)){
                self::trigger_error("apiql query => invalid block `{$el}`");
                return self::reset();
                }

            $tmp['required']=($blocks['required'] == '!')?true:false;
            if(trim($blocks['data_type']) != ''){
                $data=explode(',',substr($blocks['data_type'],1,-1));
                foreach($data as $type){
                    $type=trim($type);
                    if(preg_match('/^(string|int|float|null|boolean|json|array|php)$/i',$type)){
                        $tmp['data_type'][]=strtolower($type);
                        }
                    else{
                        self::trigger_error("apiql query => invalid data type `{$type}`");
                        return self::reset(true);
                        }
                    }
                }
            self::$syntax[$blocks['name']]=$tmp;
            }

        if(!function_exists($fn) && self::$config['check_func_exists'] == true){
            self::trigger_error("apiql query => undefined function `{$fn}` as callback");
            return self::reset();
            }
        else{
            self::$callback = $fn;
            }
        self::compile();
        }


    /*
    * access:       private
    * description:  try to compile the query ad register it
    * vars:         none
    *
    *returns:      true on success or false on failure
    */

    private static function compile(){
        $const=array();
        foreach(self::$syntax as $el){
            $const[]=$el['model'];
            }

        $const  =md5(implode('/',$const));
        $const  ='apiql_'.$const;
        $value  =array('query'=>self::$syntax,'callback'=>self::$callback);
        $value  =serialize($value);
        if(!defined($const)){
            self::reset();
            return define($const,$value,true);
            }
        else{
            self::trigger_error("unable to register query: query is already defined");
            return self::reset(true);
            }
        }


    /*
    * access:   public
    *
    * description:  execute your query and bind its results on your binded function
    *
    * vars: req     [string]    the query to be executed
    *               [,opt1,op2,opt3...] all extra arguments will be
    *               passed to the binded function 'as is'
    *
    * return:   your query results on success or false on failure
    */
    public static function query($req=''){
        $extra_data=func_get_args();
        $not_extra=array_shift($extra_data);

        $requested_reg='(?<requested>)';
        $constants=get_defined_constants(true);
        $constants=(isset($constants['user']))?$constants['user']:array();
        foreach($constants as $ckey=>$const){
            if(preg_match('/^apiql_[a-f0-9]{32}$/i',$ckey)){
                //extrasc infos on constant name
                $qry_data=unserialize($const);
                //var_dump($qry_data);
                $reg=array();
                $cnt=0;
                foreach($qry_data['query'] as $name=>$el){
                    $data_type='';
                    if(!empty($el['data_type'])){
                        $data_type=array();
                        foreach($el['data_type'] as $data_value){
                                if($data_value=='string')   $data_type[]    ='\'[^\']*\'';
                            elseif($data_value=='int')      $data_type[]    ='((\'\-?\d+\')|\-?(\d+))';
                            elseif($data_value=='float')    $data_type[]    ='((\'\-?(\d+)?\.\d+\')|\-?(\d+)?\.\d+)';
                            elseif($data_value=='null')     $data_type[]    ='(null)';
                            elseif($data_value=='boolean')  $data_type[]    ='(true|false)';
                            elseif($data_value=='json')     $data_type[]    ='(\{[^\}]+\})';
                            elseif($data_value=='array')    $data_type[]    ='(\[[^\]]+\])';
                            elseif($data_value=='php')      $data_type[]    ='(\(.+\))';
                            }

                        $data_type[]='apiql::query\([[:space:]]*("[^"]*"|\'[^\']*\')[[:space:]]*\)';
                        $data_type='[[:space:]]+(?P<data_'.$cnt.'>'.implode($data_type,'|').')';
                        }

                    $name=preg_quote($name,'/');
                    $name=preg_replace('/[[:space:]]+/','[[:space:]]+',$name);
                    if($cnt > 0) $name='[[:space:]]+'.$name;
                    $reg_el="(?P<name_{$cnt}>{$name}{$data_type})";

                    if($el['required'] == false) $reg_el.='?';
                    $reg[]=$reg_el;
                    $cnt++;
                    }

                $reg    ="/^[[:space:]]*\n".implode("\n",$reg)."\n[[:space:]]*$/smix";


                preg_match($reg,$req,$check);
                if(!empty($check)){
                    //check if the query contains subqueries.
                    //in this case we execute subqueries and
                    //each query is replaced with its result
                    preg_match_all('/
                        (?P<query_block>
                            apiql::query\(
                                [[:space:]]*
                                (?P<query>
                                    ("[^"]*"|\'[^\']*\')
                                    )
                                [[:space:]]*
                                \)
                        )/Usmix',$req,$sub_queries);

                    if(isset($sub_queries['query_block']) && !empty($sub_queries['query_block'])){
                        foreach($sub_queries['query_block'] as $sq_i=>$sq_str){
                            $sq_query   =substr($sub_queries['query'][$sq_i],1,-1);
                            $sq_res     =apiql::query($sq_query);
                            $sq_res     =(is_string($sq_res))
                                ?"'".str_replace("'","\\'",$sq_res)."'"
                                :apiql::string($sq_res);
                            $req=str_replace($sq_str,$sq_res,$req);
                            }
                        }
                    }

                preg_match($reg,$req,$check);
                if(!empty($check)){
                    preg_match($reg,$req,$check);
                    $fn_data=array();
                    foreach($check as $ck_key=>$ck_val){
                        if(strpos($ck_key,'name_') === 0){
                            $fn_data[$ck_key]   =$ck_val;
                            $data_index         =substr($ck_key,5);
                            if(isset($check['data_'.$data_index])){
                                $fn_data[$ck_key]               =str_replace($check['data_'.$data_index],'',$fn_data[$ck_key]);
                                $fn_data[$ck_key]               =trim($fn_data[$ck_key]);
                                $fn_data['data_'.$data_index]   =$check['data_'.$data_index];
                                }
                            }
                        }

                    $fn_args=array('names'=>array(),'data'=>array());
                    foreach($fn_data as $f_key=>$f_value){
                        if(strpos($f_key,'name_') === 0){
                            $f_cnt=str_replace('name_','',$f_key);
                            $fn_args['names'][$f_cnt]=trim($f_value);
                            if(isset($fn_data['data_'.$f_cnt])){
                                $test_data=trim($fn_data['data_'.$f_cnt]);
                                if(preg_match('#^({.*}|\[.*\])$#',$test_data)){
                                    $test_data=self::JSONdecode($test_data,true);
                                    }
                                else{
                                    $test_data=self::checkStr($test_data);
                                    }

                                $fn_args['data'][$f_cnt]=$test_data;
                                }
                            }
                        }

                    //var_dump($fn_args);

                    self::$data=array();
                    foreach($fn_args['names'] as $fk=>$name){
                        //array_key_exists is better then isset,
                        //it is a good solution for not make confusion with null values
                        $to_name=(array_key_exists($fk, $fn_args['data']) )
                            ?$fn_args['data'][$fk]
                            :false;
                        self::$data[$name]=$to_name;
                        }

                    //beforeQuery events
                    self::fireEvents('beforeQuery');

                    $send_to_fn=$extra_data;
                    array_unshift($send_to_fn,self::$data);

                    $out=call_user_func_array($qry_data['callback'],$send_to_fn);

                    //afterQuery events
                    self::fireEvents('afterQuery');

                    return $out;
                    }
                }
            }

        self::trigger_error("apiql query => undefined query");
        return self::reset(true);
        }

    /*
    * access:   private
    *
    * description:  convert a string rappresentation of a boolean,number or null
    *               value in its effective value
    *
    * vars: str     [string]    the string to be checked
    *
    * return:       its real value and type
    */
    private static function checkStr($str){
        if(preg_match('#^\'.*\'$#',$str)) $str=substr($str,1,-1);

        if(is_numeric($str)){
            eval('$check = '.$str.';');
            return $check;
            }
        if(strtolower($str) == 'true')  return true;
        if(strtolower($str) == 'false') return false;
        if(strtolower($str) == 'null')  return null;
        return $str;
        }


    /*
    * access:   public
    *
    * description:  bind an event function on before or after a query
    *
    * vars: ev      [string]    the event to register
    *                           can be 'beforeQuery','afterQuery' or 'error'
    *
    * returns:      null
    */
    public static function addEvent($ev,$fn_name){
        $ev     =strtolower((string)$ev);
        $ev     =str_replace('query','Query',trim($ev));
        $fn_name=strtolower(trim((string)$fn_name));
        if(isset(self::$events[$ev])){
            self::$events[$ev][]=$fn_name;
            }
        }

    /*
    * access:   public
    *
    * description:  remove a specific function from the event specified
    *
    * vars: ev      [string]    the event from where the function will be deleterd
    *       fn_name [string]    the function to be removed from.
    *
    * returns:      null
    */
    public static function removeEvent($ev,$fn_name){
        $ev     =strtolower((string)$ev);
        $ev     =str_replace('query','Query',trim($ev));
        $fn_name=strtolower(trim((string)$ev));
        $key    =array_search($fn_name,self::$events[$ev]);
        if($key !== false){
            unset(self::$events[$ev][$key]);
            }
        }

    /*
    * access:   public
    *
    * description:  remove all function from the events specified
    *
    * vars: [ev1,ev2,ev3] [string]    the events from where the functions will be removed
    *
    * returns:      null
    */
    public static function removeEvents(){
        $evs=func_get_args();
        if(!empty($evs))    $evs=array_keys(self::$events);

        foreach($evs as $ev){
            $ev=strtolower((string)$ev);
            $ev=str_replace('query','Query',trim($ev));
            if(isset(self::$events[$ev]) && !empty(self::$events[$ev])){
                self::$events[$ev]=array();
                }
            }
        return true;
        }


    /*
    * access:   public
    *
    * description:  fires all functions from the events specified
    *
    * vars: [ev1,ev2,ev3] [string]    the events from where the functions will be fired
    *
    * returns:      null
    */
    public static function fireEvents(){
        $evs=func_get_args();
        if(empty($evs))    $evs=array_keys(self::$events);


        foreach($evs as $ev){
            $ev=strtolower((string)$ev);
            $ev=str_replace('query','Query',trim($ev));
            if(isset(self::$events[$ev]) && !empty(self::$events[$ev])){
                foreach(self::$events[$ev] as $fn){
                    if(function_exists($fn))
                        $ev_data=call_user_func($fn,self::$data);
                    }
                }
            }
        }


    /*
    * access:   private
    *
    * description:  reset the internal data except the configuration
    *
    * vars: asError [bool]  if true, fires the 'error' event
    *
    * returns:      false if is called as actiot to execute after an error, or true
    */
    private static function reset($asError=false){
        self::$syntax       =   array();
        self::$callback     =   '';
        self::$isValid      =   false;
        self::$data         =   null;
        self::$error        =   '';

        if($asError) {
            self::fireEvents('error');
            return false;
            }
        return true;
        }


    /*
    * access:   private
    *
    * description:  internal error trigger
    *
    * vars: msg [string]  the string to be triggered
    *
    * returns:      null
    */
    private static function trigger_error($msg){
        self::$error=$msg;
        if(self::$config['display_errors'] == true){
            trigger_error($msg,self::$config['error_level']);
            }
        }



    /*
    * access:   public
    *
    * description:  convert a not well formed json string in valid php json object
    *
    * vars: json    [string]    the json string to be analyzed
    *       assoc   [bool]      if true, force as  object
    * returns:      a well formed json string, valid for PHP
    */
    public static function JSONdecode($json, $assoc = false){
        $json = str_replace(array("\n","\r"),"",$json);

        //remove trailing commas and encode in utf8
        $json=preg_replace('/,\s*([\]}])/m', '$1', $json);

        $json = preg_replace('/([{,])(\s*)([^"]+?)\s*:/','$1"$3":',$json);
        $json = preg_replace('/([{,])"\'([^"]+?)\'":/','$1"$2":',$json);

        $json = preg_replace('/:(\s*)([^"]+?)\s*([,}])/',':"$2"$3',$json);
        $json = preg_replace('/:"\'([^"]+?)\'"([,}])/',':"$1"$2',$json);

        $json = preg_replace('/:"(null|true|false|\d+\.\d+|\d+|\.\d+)"([,}])/',':$1$2',$json);

        return json_decode($json,$assoc);
        }

    /*
    * access:   public
    *
    * description:  convert the passed argument as json string
    *
    * vars: obj     the value to be converted
    *
    * returns:      converted value
    */
    public static function string($obj=null){
        if(is_object($obj)){
            $out=get_object_vars($obj);
            $out=json_encode($out);
            }
        elseif(is_array($obj))  {$out=json_encode($obj);}
        elseif(is_bool($obj))   {$out=($obj == true)?'true':'false';}
        elseif(is_null($obj))   {$out= 'null';}
        else                    {$out=(string)$obj;}
        return $out;
        }
    }

Скачать архивы


Комментировать

captcha

Вход

Зарегистрируйтесь, если нет учетной записи

Напомнить пароль
Регистрация
Напомнить пароль
Войти в личный кабинет