Run PHP-CS-FIXER to make sure
code is consisted with PSR-1 + PSR-2
This commit is contained in:
parent
c9d3448571
commit
35680bbae9
|
@ -9,17 +9,19 @@ abstract class Adapter
|
||||||
protected $namespace = '';
|
protected $namespace = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set Namespace
|
* Set Namespace.
|
||||||
*
|
*
|
||||||
* Set namespace to divide different scope of data sets
|
* Set namespace to divide different scope of data sets
|
||||||
*
|
*
|
||||||
* @param $namespace
|
* @param $namespace
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function setNamespace($namespace)
|
public function setNamespace($namespace)
|
||||||
{
|
{
|
||||||
if(empty($namespace)) {
|
if (empty($namespace)) {
|
||||||
throw new Exception('Missing namespace');
|
throw new Exception('Missing namespace');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,16 +31,17 @@ abstract class Adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Namespace
|
* Get Namespace.
|
||||||
*
|
*
|
||||||
* Get namespace of current set scope
|
* Get namespace of current set scope
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getNamespace()
|
public function getNamespace()
|
||||||
{
|
{
|
||||||
if(empty($this->namespace)) {
|
if (empty($this->namespace)) {
|
||||||
throw new Exception('Missing namespace');
|
throw new Exception('Missing namespace');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -46,41 +49,44 @@ abstract class Adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log
|
* Log.
|
||||||
*
|
*
|
||||||
* Add specific event log
|
* Add specific event log
|
||||||
*
|
*
|
||||||
* @param int $userId
|
* @param int $userId
|
||||||
* @param int $userType
|
* @param int $userType
|
||||||
* @param string $event
|
* @param string $event
|
||||||
* @param string $resource
|
* @param string $resource
|
||||||
* @param string $userAgent
|
* @param string $userAgent
|
||||||
* @param string $ip
|
* @param string $ip
|
||||||
* @param string $location
|
* @param string $location
|
||||||
* @param array $data
|
* @param array $data
|
||||||
|
*
|
||||||
* @return
|
* @return
|
||||||
*/
|
*/
|
||||||
abstract public function log($userId, $userType, $event, $resource, $userAgent, $ip, $location, $data);
|
abstract public function log($userId, $userType, $event, $resource, $userAgent, $ip, $location, $data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get All Logs By User
|
* Get All Logs By User.
|
||||||
*
|
*
|
||||||
* Get all user logs
|
* Get all user logs
|
||||||
*
|
*
|
||||||
* @param int $userId
|
* @param int $userId
|
||||||
* @param int $userType
|
* @param int $userType
|
||||||
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
abstract public function getLogsByUser($userId, $userType);
|
abstract public function getLogsByUser($userId, $userType);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get All Logs By User and Actions
|
* Get All Logs By User and Actions.
|
||||||
*
|
*
|
||||||
* Get all user logs by given action names
|
* Get all user logs by given action names
|
||||||
*
|
*
|
||||||
* @param int $userId
|
* @param int $userId
|
||||||
* @param int $userType
|
* @param int $userType
|
||||||
* @param array $actions
|
* @param array $actions
|
||||||
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
abstract public function getLogsByUserAndActions($userId, $userType, array $actions);
|
abstract public function getLogsByUserAndActions($userId, $userType, array $actions);
|
||||||
|
|
|
@ -21,25 +21,27 @@ class MySQL extends Adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log
|
* Log.
|
||||||
*
|
*
|
||||||
* Add specific event log
|
* Add specific event log
|
||||||
*
|
*
|
||||||
* @param int $userId
|
* @param int $userId
|
||||||
* @param int $userType
|
* @param int $userType
|
||||||
* @param string $event
|
* @param string $event
|
||||||
* @param string $resource
|
* @param string $resource
|
||||||
* @param string $userAgent
|
* @param string $userAgent
|
||||||
* @param string $ip
|
* @param string $ip
|
||||||
* @param string $location
|
* @param string $location
|
||||||
* @param array $data
|
* @param array $data
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
|
*
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
public function log($userId, $userType, $event, $resource, $userAgent, $ip, $location, $data)
|
public function log($userId, $userType, $event, $resource, $userAgent, $ip, $location, $data)
|
||||||
{
|
{
|
||||||
$st = $this->getPDO()->prepare('INSERT INTO `' . $this->getNamespace() . '.audit.audit`
|
$st = $this->getPDO()->prepare('INSERT INTO `'.$this->getNamespace().'.audit.audit`
|
||||||
SET userId = :userId, userType = :userType, event= :event, resource= :resource, userAgent = :userAgent, ip = :ip, location = :location, time = "' . date('Y-m-d H:i:s') . '", data = :data
|
SET userId = :userId, userType = :userType, event= :event, resource= :resource, userAgent = :userAgent, ip = :ip, location = :location, time = "'.date('Y-m-d H:i:s').'", data = :data
|
||||||
');
|
');
|
||||||
|
|
||||||
$data = mb_strcut(json_encode($data), 0, 64000, 'UTF-8'); // Limit data to MySQL 64kb limit
|
$data = mb_strcut(json_encode($data), 0, 64000, 'UTF-8'); // Limit data to MySQL 64kb limit
|
||||||
|
@ -61,7 +63,7 @@ class MySQL extends Adapter
|
||||||
public function getLogsByUser($userId, $userType)
|
public function getLogsByUser($userId, $userType)
|
||||||
{
|
{
|
||||||
$st = $this->getPDO()->prepare('SELECT *
|
$st = $this->getPDO()->prepare('SELECT *
|
||||||
FROM `' . $this->getNamespace() . '.audit.audit`
|
FROM `'.$this->getNamespace().'.audit.audit`
|
||||||
WHERE userId = :userId
|
WHERE userId = :userId
|
||||||
AND userType = :userType
|
AND userType = :userType
|
||||||
ORDER BY `time` DESC LIMIT 10
|
ORDER BY `time` DESC LIMIT 10
|
||||||
|
@ -79,14 +81,15 @@ class MySQL extends Adapter
|
||||||
{
|
{
|
||||||
$query = [];
|
$query = [];
|
||||||
|
|
||||||
foreach ($actions as $k => $id)
|
foreach ($actions as $k => $id) {
|
||||||
$query[] = ':action_' . $k;
|
$query[] = ':action_'.$k;
|
||||||
|
}
|
||||||
|
|
||||||
$query = implode(',', $query);
|
$query = implode(',', $query);
|
||||||
|
|
||||||
$st = $this->getPDO()->prepare('SELECT *
|
$st = $this->getPDO()->prepare('SELECT *
|
||||||
FROM `' . $this->getNamespace() . '.audit.audit`
|
FROM `'.$this->getNamespace().'.audit.audit`
|
||||||
WHERE `event` IN (' . $query . ')
|
WHERE `event` IN ('.$query.')
|
||||||
AND userId = :userId
|
AND userId = :userId
|
||||||
AND userType = :userType
|
AND userType = :userType
|
||||||
ORDER BY `time` DESC LIMIT 10
|
ORDER BY `time` DESC LIMIT 10
|
||||||
|
@ -95,8 +98,9 @@ class MySQL extends Adapter
|
||||||
$st->bindValue(':userId', $userId, PDO::PARAM_STR);
|
$st->bindValue(':userId', $userId, PDO::PARAM_STR);
|
||||||
$st->bindValue(':userType', $userType, PDO::PARAM_INT);
|
$st->bindValue(':userType', $userType, PDO::PARAM_INT);
|
||||||
|
|
||||||
foreach ($actions as $k => $id)
|
foreach ($actions as $k => $id) {
|
||||||
$st->bindValue(':action_' . $k, $id);
|
$st->bindValue(':action_'.$k, $id);
|
||||||
|
}
|
||||||
|
|
||||||
$st->execute();
|
$st->execute();
|
||||||
|
|
||||||
|
|
|
@ -36,30 +36,31 @@ class Audit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Adapter $adapter
|
* @param Adapter $adapter
|
||||||
* @param int $userId
|
* @param int $userId
|
||||||
* @param int $userType
|
* @param int $userType
|
||||||
* @param string $userAgent
|
* @param string $userAgent
|
||||||
* @param string $ip
|
* @param string $ip
|
||||||
* @param string $location
|
* @param string $location
|
||||||
*/
|
*/
|
||||||
public function __construct(Adapter $adapter, $userId, $userType, $userAgent, $ip, $location)
|
public function __construct(Adapter $adapter, $userId, $userType, $userAgent, $ip, $location)
|
||||||
{
|
{
|
||||||
$this->adapter = $adapter;
|
$this->adapter = $adapter;
|
||||||
$this->userId = $userId;
|
$this->userId = $userId;
|
||||||
$this->userType = $userType;
|
$this->userType = $userType;
|
||||||
$this->userAgent = $userAgent;
|
$this->userAgent = $userAgent;
|
||||||
$this->ip = $ip;
|
$this->ip = $ip;
|
||||||
$this->location = $location;
|
$this->location = $location;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Log
|
* Log.
|
||||||
*
|
*
|
||||||
* Add specific event log
|
* Add specific event log
|
||||||
*
|
*
|
||||||
* @param string $event
|
* @param string $event
|
||||||
* @param string $resource
|
* @param string $resource
|
||||||
* @param array $data
|
* @param array $data
|
||||||
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function log($event, $resource = '', array $data = [])
|
public function log($event, $resource = '', array $data = [])
|
||||||
|
@ -68,12 +69,13 @@ class Audit
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get All Logs By User and Actions
|
* Get All Logs By User and Actions.
|
||||||
*
|
*
|
||||||
* Get all user logs logs by given action names
|
* Get all user logs logs by given action names
|
||||||
*
|
*
|
||||||
* @param int $userId
|
* @param int $userId
|
||||||
* @param int $userType
|
* @param int $userType
|
||||||
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function getLogsByUser($userId, $userType)
|
public function getLogsByUser($userId, $userType)
|
||||||
|
@ -82,13 +84,14 @@ class Audit
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get All Logs By User and Actions
|
* Get All Logs By User and Actions.
|
||||||
*
|
*
|
||||||
* Get all user logs logs by given action names
|
* Get all user logs logs by given action names
|
||||||
*
|
*
|
||||||
* @param int $userId
|
* @param int $userId
|
||||||
* @param int $userType
|
* @param int $userType
|
||||||
* @param array $actions
|
* @param array $actions
|
||||||
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function getLogsByUserAndActions($userId, $userType, array $actions)
|
public function getLogsByUserAndActions($userId, $userType, array $actions)
|
||||||
|
|
|
@ -7,93 +7,95 @@ use Database\Document;
|
||||||
class Auth
|
class Auth
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* User Gender
|
* User Gender.
|
||||||
*/
|
*/
|
||||||
const USER_GENDER_TYPE_NOT_SET = 0;
|
const USER_GENDER_TYPE_NOT_SET = 0;
|
||||||
const USER_GENDER_TYPE_MALE = 1;
|
const USER_GENDER_TYPE_MALE = 1;
|
||||||
const USER_GENDER_TYPE_FEMALE = 2;
|
const USER_GENDER_TYPE_FEMALE = 2;
|
||||||
const USER_GENDER_TYPE_OTHER = 3;
|
const USER_GENDER_TYPE_OTHER = 3;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User Status
|
* User Status.
|
||||||
*/
|
*/
|
||||||
const USER_STATUS_UNACTIVATED = 0;
|
const USER_STATUS_UNACTIVATED = 0;
|
||||||
const USER_STATUS_ACTIVATED = 1;
|
const USER_STATUS_ACTIVATED = 1;
|
||||||
const USER_STATUS_BLOCKED = 2;
|
const USER_STATUS_BLOCKED = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User Types
|
* User Types.
|
||||||
*/
|
*/
|
||||||
const USER_TYPE_USER = 0;
|
const USER_TYPE_USER = 0;
|
||||||
const USER_TYPE_PARENT = 1;
|
const USER_TYPE_PARENT = 1;
|
||||||
const USER_TYPE_APP = 2;
|
const USER_TYPE_APP = 2;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User Roles
|
* User Roles.
|
||||||
*/
|
*/
|
||||||
const USER_ROLE_GUEST = 0;
|
const USER_ROLE_GUEST = 0;
|
||||||
const USER_ROLE_MEMBER = 1;
|
const USER_ROLE_MEMBER = 1;
|
||||||
const USER_ROLE_ADMIN = 2;
|
const USER_ROLE_ADMIN = 2;
|
||||||
const USER_ROLE_DEVELOPER = 3;
|
const USER_ROLE_DEVELOPER = 3;
|
||||||
const USER_ROLE_OWNER = 4;
|
const USER_ROLE_OWNER = 4;
|
||||||
const USER_ROLE_APP = 5;
|
const USER_ROLE_APP = 5;
|
||||||
const USER_ROLE_SYSTEM = 6;
|
const USER_ROLE_SYSTEM = 6;
|
||||||
const USER_ROLE_ALL = '*';
|
const USER_ROLE_ALL = '*';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Token Types
|
* Token Types.
|
||||||
*/
|
*/
|
||||||
const TOKEN_TYPE_LOGIN = 1;
|
const TOKEN_TYPE_LOGIN = 1;
|
||||||
const TOKEN_TYPE_CONFIRM = 2;
|
const TOKEN_TYPE_CONFIRM = 2;
|
||||||
const TOKEN_TYPE_RECOVERY = 3;
|
const TOKEN_TYPE_RECOVERY = 3;
|
||||||
const TOKEN_TYPE_INVITE = 4;
|
const TOKEN_TYPE_INVITE = 4;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Token Expiration times
|
* Token Expiration times.
|
||||||
*/
|
*/
|
||||||
const TOKEN_EXPIRATION_LOGIN_LONG = 31536000; /* 1 year */
|
const TOKEN_EXPIRATION_LOGIN_LONG = 31536000; /* 1 year */
|
||||||
const TOKEN_EXPIRATION_LOGIN_SHORT = 3600; /* 1 hour */
|
const TOKEN_EXPIRATION_LOGIN_SHORT = 3600; /* 1 hour */
|
||||||
const TOKEN_EXPIRATION_RECOVERY = 3600; /* 1 hour */
|
const TOKEN_EXPIRATION_RECOVERY = 3600; /* 1 hour */
|
||||||
const TOKEN_EXPIRATION_CONFIRM = 3600 * 24 * 7; /* 7 days */
|
const TOKEN_EXPIRATION_CONFIRM = 3600 * 24 * 7; /* 7 days */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
static public $cookieName = 'a-session';
|
public static $cookieName = 'a-session';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User Unique ID
|
* User Unique ID.
|
||||||
*
|
*
|
||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
static public $unique = 0;
|
public static $unique = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* User Secret Key
|
* User Secret Key.
|
||||||
*
|
*
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
static public $secret = '';
|
public static $secret = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set Cookie Name
|
* Set Cookie Name.
|
||||||
*
|
*
|
||||||
* @param $string
|
* @param $string
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
static public function setCookieName($string)
|
public static function setCookieName($string)
|
||||||
{
|
{
|
||||||
return self::$cookieName = $string;
|
return self::$cookieName = $string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encode Session
|
* Encode Session.
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @param string $secret
|
* @param string $secret
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
static public function encodeSession($id, $secret)
|
public static function encodeSession($id, $secret)
|
||||||
{
|
{
|
||||||
return base64_encode(json_encode([
|
return base64_encode(json_encode([
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
|
@ -102,18 +104,20 @@ class Auth
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decode Session
|
* Decode Session.
|
||||||
*
|
*
|
||||||
* @param string $session
|
* @param string $session
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
|
*
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
static public function decodeSession($session)
|
public static function decodeSession($session)
|
||||||
{
|
{
|
||||||
$session = json_decode(base64_decode($session), true);
|
$session = json_decode(base64_decode($session), true);
|
||||||
$default = ['id' => null, 'secret' => '',];
|
$default = ['id' => null, 'secret' => ''];
|
||||||
|
|
||||||
if(!is_array($session)) {
|
if (!is_array($session)) {
|
||||||
return $default;
|
return $default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,83 +125,91 @@ class Auth
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Encode
|
* Encode.
|
||||||
*
|
*
|
||||||
* One-way encryption
|
* One-way encryption
|
||||||
*
|
*
|
||||||
* @param $string
|
* @param $string
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
static public function hash($string)
|
public static function hash($string)
|
||||||
{
|
{
|
||||||
return hash('sha256',$string);
|
return hash('sha256', $string);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Password Hash
|
* Password Hash.
|
||||||
*
|
*
|
||||||
* One way string hashing for user passwords
|
* One way string hashing for user passwords
|
||||||
*
|
*
|
||||||
* @param $string
|
* @param $string
|
||||||
|
*
|
||||||
* @return bool|string
|
* @return bool|string
|
||||||
*/
|
*/
|
||||||
static public function passwordHash($string)
|
public static function passwordHash($string)
|
||||||
{
|
{
|
||||||
return password_hash($string, PASSWORD_BCRYPT, array('cost' => 8));
|
return password_hash($string, PASSWORD_BCRYPT, array('cost' => 8));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Password verify
|
* Password verify.
|
||||||
*
|
*
|
||||||
* @param $plain
|
* @param $plain
|
||||||
* @param $hash
|
* @param $hash
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
static public function passwordVerify($plain, $hash)
|
public static function passwordVerify($plain, $hash)
|
||||||
{
|
{
|
||||||
return password_verify($plain, $hash);
|
return password_verify($plain, $hash);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Password Generator
|
* Password Generator.
|
||||||
*
|
*
|
||||||
* Generate random password string
|
* Generate random password string
|
||||||
*
|
*
|
||||||
* @param int $length
|
* @param int $length
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
|
*
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
static public function passwordGenerator(int $length = 20):string
|
public static function passwordGenerator(int $length = 20):string
|
||||||
{
|
{
|
||||||
return bin2hex(random_bytes($length));
|
return bin2hex(random_bytes($length));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Token Generator
|
* Token Generator.
|
||||||
*
|
*
|
||||||
* Generate random password string
|
* Generate random password string
|
||||||
*
|
*
|
||||||
* @param int $length
|
* @param int $length
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
|
*
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
static public function tokenGenerator(int $length = 128):string
|
public static function tokenGenerator(int $length = 128):string
|
||||||
{
|
{
|
||||||
return bin2hex(random_bytes($length));
|
return bin2hex(random_bytes($length));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Verify token and check that its not expired
|
* Verify token and check that its not expired.
|
||||||
*
|
*
|
||||||
* @param array $tokens
|
* @param array $tokens
|
||||||
* @param int $type
|
* @param int $type
|
||||||
* @param string $secret
|
* @param string $secret
|
||||||
|
*
|
||||||
* @return bool|int
|
* @return bool|int
|
||||||
*/
|
*/
|
||||||
static public function tokenVerify(array $tokens, int $type, string $secret)
|
public static function tokenVerify(array $tokens, int $type, string $secret)
|
||||||
{
|
{
|
||||||
foreach ($tokens as $token) { /* @var $token Document */
|
foreach ($tokens as $token) { /* @var $token Document */
|
||||||
if(isset($token['type']) &&
|
if (isset($token['type']) &&
|
||||||
isset($token['secret']) &&
|
isset($token['secret']) &&
|
||||||
isset($token['expire']) &&
|
isset($token['expire']) &&
|
||||||
$token['type'] == $type &&
|
$token['type'] == $type &&
|
||||||
|
@ -209,4 +221,4 @@ class Auth
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,14 +30,14 @@ abstract class OAuth
|
||||||
* @param string $appId
|
* @param string $appId
|
||||||
* @param string $appSecret
|
* @param string $appSecret
|
||||||
* @param string $callback
|
* @param string $callback
|
||||||
* @param array $state
|
* @param array $state
|
||||||
*/
|
*/
|
||||||
public function __construct(string $appId, string $appSecret, string $callback, $state = [])
|
public function __construct(string $appId, string $appSecret, string $callback, $state = [])
|
||||||
{
|
{
|
||||||
$this->appID = $appId;
|
$this->appID = $appId;
|
||||||
$this->appSecret = $appSecret;
|
$this->appSecret = $appSecret;
|
||||||
$this->callback = $callback;
|
$this->callback = $callback;
|
||||||
$this->state = $state;
|
$this->state = $state;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -52,24 +52,28 @@ abstract class OAuth
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $code
|
* @param string $code
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
abstract public function getAccessToken(string $code):string;
|
abstract public function getAccessToken(string $code):string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $accessToken
|
* @param $accessToken
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
abstract public function getUserID(string $accessToken):string;
|
abstract public function getUserID(string $accessToken):string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $accessToken
|
* @param $accessToken
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
abstract public function getUserEmail(string $accessToken):string;
|
abstract public function getUserEmail(string $accessToken):string;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $accessToken
|
* @param $accessToken
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
abstract public function getUserName(string $accessToken):string;
|
abstract public function getUserName(string $accessToken):string;
|
||||||
|
@ -77,13 +81,14 @@ abstract class OAuth
|
||||||
/**
|
/**
|
||||||
* @param string $method
|
* @param string $method
|
||||||
* @param string $url
|
* @param string $url
|
||||||
* @param array $headers
|
* @param array $headers
|
||||||
* @param string $payload
|
* @param string $payload
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
protected function request(string $method, string $url = '', array $headers = [], string $payload = ''):string
|
protected function request(string $method, string $url = '', array $headers = [], string $payload = ''):string
|
||||||
{
|
{
|
||||||
$ch = curl_init($url);
|
$ch = curl_init($url);
|
||||||
|
|
||||||
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method);
|
||||||
curl_setopt($ch, CURLOPT_HEADER, 0);
|
curl_setopt($ch, CURLOPT_HEADER, 0);
|
||||||
|
@ -91,7 +96,7 @@ abstract class OAuth
|
||||||
curl_setopt($ch, CURLOPT_USERAGENT, 'Console_OAuth_Agent');
|
curl_setopt($ch, CURLOPT_USERAGENT, 'Console_OAuth_Agent');
|
||||||
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
|
||||||
|
|
||||||
if(!empty($payload)) {
|
if (!empty($payload)) {
|
||||||
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
|
curl_setopt($ch, CURLOPT_POSTFIELDS, $payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -102,4 +107,4 @@ abstract class OAuth
|
||||||
|
|
||||||
return $response;
|
return $response;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,25 +29,26 @@ class Facebook extends OAuth
|
||||||
*/
|
*/
|
||||||
public function getLoginURL():string
|
public function getLoginURL():string
|
||||||
{
|
{
|
||||||
return 'https://www.facebook.com/' . $this->version . '/dialog/oauth?client_id=' . urlencode($this->appID) . '&redirect_uri=' . urlencode($this->callback) . '&scope=email&state=' . urlencode(json_encode($this->state));
|
return 'https://www.facebook.com/'.$this->version.'/dialog/oauth?client_id='.urlencode($this->appID).'&redirect_uri='.urlencode($this->callback).'&scope=email&state='.urlencode(json_encode($this->state));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $code
|
* @param string $code
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getAccessToken(string $code):string
|
public function getAccessToken(string $code):string
|
||||||
{
|
{
|
||||||
$accessToken = $this->request('GET', 'https://graph.facebook.com/' . $this->version . '/oauth/access_token?' .
|
$accessToken = $this->request('GET', 'https://graph.facebook.com/'.$this->version.'/oauth/access_token?'.
|
||||||
'client_id=' . urlencode($this->appID) .
|
'client_id='.urlencode($this->appID).
|
||||||
'&redirect_uri=' . urlencode($this->callback) .
|
'&redirect_uri='.urlencode($this->callback).
|
||||||
'&client_secret=' . urlencode($this->appSecret) .
|
'&client_secret='.urlencode($this->appSecret).
|
||||||
'&code=' . urlencode($code)
|
'&code='.urlencode($code)
|
||||||
);
|
);
|
||||||
|
|
||||||
$accessToken = json_decode($accessToken, true); //
|
$accessToken = json_decode($accessToken, true); //
|
||||||
|
|
||||||
if(isset($accessToken['access_token'])) {
|
if (isset($accessToken['access_token'])) {
|
||||||
return $accessToken['access_token'];
|
return $accessToken['access_token'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,13 +57,14 @@ class Facebook extends OAuth
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $accessToken
|
* @param string $accessToken
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getUserID(string $accessToken):string
|
public function getUserID(string $accessToken):string
|
||||||
{
|
{
|
||||||
$user = $this->getUser($accessToken);
|
$user = $this->getUser($accessToken);
|
||||||
|
|
||||||
if(isset($user['id'])) {
|
if (isset($user['id'])) {
|
||||||
return $user['id'];
|
return $user['id'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,13 +73,14 @@ class Facebook extends OAuth
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $accessToken
|
* @param string $accessToken
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getUserEmail(string $accessToken):string
|
public function getUserEmail(string $accessToken):string
|
||||||
{
|
{
|
||||||
$user = $this->getUser($accessToken);
|
$user = $this->getUser($accessToken);
|
||||||
|
|
||||||
if(isset($user['email'])) {
|
if (isset($user['email'])) {
|
||||||
return $user['email'];
|
return $user['email'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,13 +89,14 @@ class Facebook extends OAuth
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $accessToken
|
* @param string $accessToken
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getUserName(string $accessToken):string
|
public function getUserName(string $accessToken):string
|
||||||
{
|
{
|
||||||
$user = $this->getUser($accessToken);
|
$user = $this->getUser($accessToken);
|
||||||
|
|
||||||
if(isset($user['name'])) {
|
if (isset($user['name'])) {
|
||||||
return $user['name'];
|
return $user['name'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -101,16 +105,17 @@ class Facebook extends OAuth
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $accessToken
|
* @param string $accessToken
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
protected function getUser(string $accessToken):array
|
protected function getUser(string $accessToken):array
|
||||||
{
|
{
|
||||||
if(empty($this->user)) {
|
if (empty($this->user)) {
|
||||||
$user = $this->request('GET', 'https://graph.facebook.com/' . $this->version . '/me?fields=email,name&access_token=' . urlencode($accessToken));
|
$user = $this->request('GET', 'https://graph.facebook.com/'.$this->version.'/me?fields=email,name&access_token='.urlencode($accessToken));
|
||||||
|
|
||||||
$this->user = json_decode($user, true);
|
$this->user = json_decode($user, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->user;
|
return $this->user;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,27 +24,28 @@ class Github extends OAuth
|
||||||
*/
|
*/
|
||||||
public function getLoginURL():string
|
public function getLoginURL():string
|
||||||
{
|
{
|
||||||
return 'https://github.com/login/oauth/authorize?client_id=' . urlencode($this->appID) . '&redirect_uri=' . urlencode($this->callback) . '&scope=user:email&state=' . urlencode(json_encode($this->state));
|
return 'https://github.com/login/oauth/authorize?client_id='.urlencode($this->appID).'&redirect_uri='.urlencode($this->callback).'&scope=user:email&state='.urlencode(json_encode($this->state));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $code
|
* @param string $code
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getAccessToken(string $code):string
|
public function getAccessToken(string $code):string
|
||||||
{
|
{
|
||||||
$accessToken = $this->request('POST', 'https://github.com/login/oauth/access_token', [],
|
$accessToken = $this->request('POST', 'https://github.com/login/oauth/access_token', [],
|
||||||
'client_id=' . urlencode($this->appID) .
|
'client_id='.urlencode($this->appID).
|
||||||
'&redirect_uri=' . urlencode($this->callback) .
|
'&redirect_uri='.urlencode($this->callback).
|
||||||
'&client_secret=' . urlencode($this->appSecret) .
|
'&client_secret='.urlencode($this->appSecret).
|
||||||
'&code=' . urlencode($code)
|
'&code='.urlencode($code)
|
||||||
);
|
);
|
||||||
|
|
||||||
$output = [];
|
$output = [];
|
||||||
|
|
||||||
parse_str($accessToken, $output);
|
parse_str($accessToken, $output);
|
||||||
|
|
||||||
if(isset($output['access_token'])) {
|
if (isset($output['access_token'])) {
|
||||||
return $output['access_token'];
|
return $output['access_token'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -53,13 +54,14 @@ class Github extends OAuth
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $accessToken
|
* @param $accessToken
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getUserID(string $accessToken):string
|
public function getUserID(string $accessToken):string
|
||||||
{
|
{
|
||||||
$user = $this->getUser($accessToken);
|
$user = $this->getUser($accessToken);
|
||||||
|
|
||||||
if(isset($user['id'])) {
|
if (isset($user['id'])) {
|
||||||
return $user['id'];
|
return $user['id'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,14 +70,15 @@ class Github extends OAuth
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $accessToken
|
* @param $accessToken
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getUserEmail(string $accessToken):string
|
public function getUserEmail(string $accessToken):string
|
||||||
{
|
{
|
||||||
$emails = json_decode($this->request('GET', 'https://api.github.com/user/emails', ['Authorization: token ' . urlencode($accessToken)]), true);
|
$emails = json_decode($this->request('GET', 'https://api.github.com/user/emails', ['Authorization: token '.urlencode($accessToken)]), true);
|
||||||
|
|
||||||
foreach($emails as $email) {
|
foreach ($emails as $email) {
|
||||||
if($email['primary'] && $email['verified']) {
|
if ($email['primary'] && $email['verified']) {
|
||||||
return $email['email'];
|
return $email['email'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -85,13 +88,14 @@ class Github extends OAuth
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $accessToken
|
* @param $accessToken
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getUserName(string $accessToken):string
|
public function getUserName(string $accessToken):string
|
||||||
{
|
{
|
||||||
$user = $this->getUser($accessToken);
|
$user = $this->getUser($accessToken);
|
||||||
|
|
||||||
if(isset($user['name'])) {
|
if (isset($user['name'])) {
|
||||||
return $user['name'];
|
return $user['name'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -100,14 +104,15 @@ class Github extends OAuth
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $accessToken
|
* @param string $accessToken
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
protected function getUser(string $accessToken)
|
protected function getUser(string $accessToken)
|
||||||
{
|
{
|
||||||
if(empty($this->user)) {
|
if (empty($this->user)) {
|
||||||
$this->user = json_decode($this->request('GET', 'https://api.github.com/user', ['Authorization: token ' . urlencode($accessToken)]), true);
|
$this->user = json_decode($this->request('GET', 'https://api.github.com/user', ['Authorization: token '.urlencode($accessToken)]), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->user;
|
return $this->user;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,7 @@ class LinkedIn extends OAuth
|
||||||
];
|
];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Documentation
|
* Documentation.
|
||||||
*
|
*
|
||||||
* OAuth:
|
* OAuth:
|
||||||
* https://developer.linkedin.com/docs/oauth2
|
* https://developer.linkedin.com/docs/oauth2
|
||||||
|
@ -30,7 +30,6 @@ class LinkedIn extends OAuth
|
||||||
*
|
*
|
||||||
* Basic Profile Fields:
|
* Basic Profile Fields:
|
||||||
* https://developer.linkedin.com/docs/fields/basic-profile
|
* https://developer.linkedin.com/docs/fields/basic-profile
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -46,7 +45,7 @@ class LinkedIn extends OAuth
|
||||||
*/
|
*/
|
||||||
public function getLoginURL():string
|
public function getLoginURL():string
|
||||||
{
|
{
|
||||||
return 'https://www.linkedin.com/oauth/v2/authorization?' . http_build_query([
|
return 'https://www.linkedin.com/oauth/v2/authorization?'.http_build_query([
|
||||||
'response_type' => 'code',
|
'response_type' => 'code',
|
||||||
'client_id' => $this->appID,
|
'client_id' => $this->appID,
|
||||||
'redirect_uri' => $this->callback,
|
'redirect_uri' => $this->callback,
|
||||||
|
@ -57,6 +56,7 @@ class LinkedIn extends OAuth
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $code
|
* @param string $code
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getAccessToken(string $code):string
|
public function getAccessToken(string $code):string
|
||||||
|
@ -73,7 +73,7 @@ class LinkedIn extends OAuth
|
||||||
|
|
||||||
$accessToken = json_decode($accessToken, true);
|
$accessToken = json_decode($accessToken, true);
|
||||||
|
|
||||||
if(isset($accessToken['access_token'])) {
|
if (isset($accessToken['access_token'])) {
|
||||||
return $accessToken['access_token'];
|
return $accessToken['access_token'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -82,13 +82,14 @@ class LinkedIn extends OAuth
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $accessToken
|
* @param $accessToken
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getUserID(string $accessToken):string
|
public function getUserID(string $accessToken):string
|
||||||
{
|
{
|
||||||
$user = $this->getUser($accessToken);
|
$user = $this->getUser($accessToken);
|
||||||
|
|
||||||
if(isset($user['id'])) {
|
if (isset($user['id'])) {
|
||||||
return $user['id'];
|
return $user['id'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,19 +98,19 @@ class LinkedIn extends OAuth
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $accessToken
|
* @param $accessToken
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getUserEmail(string $accessToken):string
|
public function getUserEmail(string $accessToken):string
|
||||||
{
|
{
|
||||||
$email = json_decode($this->request('GET', 'https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))', ['Authorization: Bearer ' . urlencode($accessToken)]), true);
|
$email = json_decode($this->request('GET', 'https://api.linkedin.com/v2/emailAddress?q=members&projection=(elements*(handle~))', ['Authorization: Bearer '.urlencode($accessToken)]), true);
|
||||||
|
|
||||||
if(
|
if (
|
||||||
isset($email['elements']) &&
|
isset($email['elements']) &&
|
||||||
isset($email['elements'][0]) &&
|
isset($email['elements'][0]) &&
|
||||||
isset($email['elements'][0]['handle~']) &&
|
isset($email['elements'][0]['handle~']) &&
|
||||||
isset($email['elements'][0]['handle~']['emailAddress'])
|
isset($email['elements'][0]['handle~']['emailAddress'])
|
||||||
)
|
) {
|
||||||
{
|
|
||||||
return $email['elements'][0]['handle~']['emailAddress'];
|
return $email['elements'][0]['handle~']['emailAddress'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,6 +119,7 @@ class LinkedIn extends OAuth
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $accessToken
|
* @param $accessToken
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getUserName(string $accessToken):string
|
public function getUserName(string $accessToken):string
|
||||||
|
@ -125,12 +127,12 @@ class LinkedIn extends OAuth
|
||||||
$user = $this->getUser($accessToken);
|
$user = $this->getUser($accessToken);
|
||||||
$name = '';
|
$name = '';
|
||||||
|
|
||||||
if(isset($user['localizedFirstName'])) {
|
if (isset($user['localizedFirstName'])) {
|
||||||
$name = $user['localizedFirstName'];
|
$name = $user['localizedFirstName'];
|
||||||
}
|
}
|
||||||
|
|
||||||
if(isset($user['localizedLastName'])) {
|
if (isset($user['localizedLastName'])) {
|
||||||
$name = (empty($name)) ? $user['localizedLastName'] : $name . ' ' . $user['localizedLastName'];
|
$name = (empty($name)) ? $user['localizedLastName'] : $name.' '.$user['localizedLastName'];
|
||||||
}
|
}
|
||||||
|
|
||||||
return $name;
|
return $name;
|
||||||
|
@ -138,14 +140,15 @@ class LinkedIn extends OAuth
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $accessToken
|
* @param string $accessToken
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
protected function getUser(string $accessToken)
|
protected function getUser(string $accessToken)
|
||||||
{
|
{
|
||||||
if(empty($this->user)) {
|
if (empty($this->user)) {
|
||||||
$this->user = json_decode($this->request('GET', 'https://api.linkedin.com/v2/me', ['Authorization: Bearer ' . urlencode($accessToken)]), true);
|
$this->user = json_decode($this->request('GET', 'https://api.linkedin.com/v2/me', ['Authorization: Bearer '.urlencode($accessToken)]), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->user;
|
return $this->user;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,16 +5,14 @@ namespace Auth\Validator;
|
||||||
use Utopia\Validator;
|
use Utopia\Validator;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Password
|
* Password.
|
||||||
*
|
*
|
||||||
* Validates user password string
|
* Validates user password string
|
||||||
*
|
|
||||||
* @package Utopia\Validator
|
|
||||||
*/
|
*/
|
||||||
class Password extends Validator
|
class Password extends Validator
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get Description
|
* Get Description.
|
||||||
*
|
*
|
||||||
* Returns validator description
|
* Returns validator description
|
||||||
*
|
*
|
||||||
|
@ -26,11 +24,12 @@ class Password extends Validator
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is valid
|
* Is valid.
|
||||||
*
|
*
|
||||||
* Validation username
|
* Validation username
|
||||||
*
|
*
|
||||||
* @param mixed $value
|
* @param mixed $value
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isValid($value)
|
public function isValid($value)
|
||||||
|
@ -41,4 +40,4 @@ class Password extends Validator
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,17 +12,19 @@ abstract class Adapter
|
||||||
protected $namespace = '';
|
protected $namespace = '';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set Namespace
|
* Set Namespace.
|
||||||
*
|
*
|
||||||
* Set namespace to divide different scope of data sets
|
* Set namespace to divide different scope of data sets
|
||||||
*
|
*
|
||||||
* @param $namespace
|
* @param $namespace
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function setNamespace($namespace)
|
public function setNamespace($namespace)
|
||||||
{
|
{
|
||||||
if(empty($namespace)) {
|
if (empty($namespace)) {
|
||||||
throw new Exception('Missing namespace');
|
throw new Exception('Missing namespace');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -32,16 +34,17 @@ abstract class Adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Namespace
|
* Get Namespace.
|
||||||
*
|
*
|
||||||
* Get namespace of current set scope
|
* Get namespace of current set scope
|
||||||
*
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getNamespace()
|
public function getNamespace()
|
||||||
{
|
{
|
||||||
if(empty($this->namespace)) {
|
if (empty($this->namespace)) {
|
||||||
throw new Exception('Missing namespace');
|
throw new Exception('Missing namespace');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -49,71 +52,80 @@ abstract class Adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Document
|
* Get Document.
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
abstract public function getDocument($id);
|
abstract public function getDocument($id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create Document
|
* Create Document
|
||||||
**
|
**.
|
||||||
|
*
|
||||||
* @param array $data
|
* @param array $data
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
abstract public function createDocument(array $data);
|
abstract public function createDocument(array $data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update Document
|
* Update Document.
|
||||||
*
|
*
|
||||||
* @param array $data
|
* @param array $data
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
abstract public function updateDocument(array $data);
|
abstract public function updateDocument(array $data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete Node
|
* Delete Node.
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
abstract public function deleteDocument($id);
|
abstract public function deleteDocument($id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create Namespace
|
* Create Namespace.
|
||||||
*
|
*
|
||||||
* @param string $namespace
|
* @param string $namespace
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
abstract public function createNamespace($namespace);
|
abstract public function createNamespace($namespace);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete Namespace
|
* Delete Namespace.
|
||||||
*
|
*
|
||||||
* @param string $namespace
|
* @param string $namespace
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
abstract public function deleteNamespace($namespace);
|
abstract public function deleteNamespace($namespace);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Filter
|
* Filter.
|
||||||
*
|
*
|
||||||
* Filter data sets using chosen queries
|
* Filter data sets using chosen queries
|
||||||
*
|
*
|
||||||
* @param array $options
|
* @param array $options
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
abstract public function getCollection(array $options);
|
abstract public function getCollection(array $options);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $options
|
* @param array $options
|
||||||
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
abstract public function getCount(array $options);
|
abstract public function getCount(array $options);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Last Modified
|
* Last Modified.
|
||||||
*
|
*
|
||||||
* Return unix timestamp of last time a node queried in corrent session has been changed
|
* Return unix timestamp of last time a node queried in corrent session has been changed
|
||||||
*
|
*
|
||||||
|
@ -122,7 +134,7 @@ abstract class Adapter
|
||||||
abstract public function lastModified();
|
abstract public function lastModified();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Debug Data
|
* Get Debug Data.
|
||||||
*
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -11,16 +11,16 @@ use Database\Validator\Authorization;
|
||||||
|
|
||||||
class MySQL extends Adapter
|
class MySQL extends Adapter
|
||||||
{
|
{
|
||||||
const DATA_TYPE_STRING = 'string';
|
const DATA_TYPE_STRING = 'string';
|
||||||
const DATA_TYPE_INTEGER = 'integer';
|
const DATA_TYPE_INTEGER = 'integer';
|
||||||
const DATA_TYPE_FLOAT = 'float';
|
const DATA_TYPE_FLOAT = 'float';
|
||||||
const DATA_TYPE_BOOLEAN = 'boolean';
|
const DATA_TYPE_BOOLEAN = 'boolean';
|
||||||
const DATA_TYPE_OBJECT = 'object';
|
const DATA_TYPE_OBJECT = 'object';
|
||||||
const DATA_TYPE_DICTIONARY = 'dictionary';
|
const DATA_TYPE_DICTIONARY = 'dictionary';
|
||||||
const DATA_TYPE_ARRAY = 'array';
|
const DATA_TYPE_ARRAY = 'array';
|
||||||
const DATA_TYPE_NULL = 'null';
|
const DATA_TYPE_NULL = 'null';
|
||||||
|
|
||||||
const OPTIONS_LIMIT_ATTRIBUTES = 1000;
|
const OPTIONS_LIMIT_ATTRIBUTES = 1000;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var PDO
|
* @var PDO
|
||||||
|
@ -28,21 +28,21 @@ class MySQL extends Adapter
|
||||||
protected $register;
|
protected $register;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Saved nodes
|
* Saved nodes.
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $nodes = [];
|
protected $nodes = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Count documents get usage
|
* Count documents get usage.
|
||||||
*
|
*
|
||||||
* @var int
|
* @var int
|
||||||
*/
|
*/
|
||||||
protected $count = 0;
|
protected $count = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Last modified
|
* Last modified.
|
||||||
*
|
*
|
||||||
* Read node with most recent changes
|
* Read node with most recent changes
|
||||||
*
|
*
|
||||||
|
@ -56,7 +56,7 @@ class MySQL extends Adapter
|
||||||
protected $debug = [];
|
protected $debug = [];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor.
|
||||||
*
|
*
|
||||||
* Set connection and settings
|
* Set connection and settings
|
||||||
*
|
*
|
||||||
|
@ -64,22 +64,24 @@ class MySQL extends Adapter
|
||||||
*/
|
*/
|
||||||
public function __construct(Registry $register)
|
public function __construct(Registry $register)
|
||||||
{
|
{
|
||||||
$this->register = $register;
|
$this->register = $register;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Document
|
* Get Document.
|
||||||
*
|
*
|
||||||
* @param string $id
|
* @param string $id
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function getDocument($id)
|
public function getDocument($id)
|
||||||
{
|
{
|
||||||
$this->count++;
|
++$this->count;
|
||||||
|
|
||||||
// Get fields abstraction
|
// Get fields abstraction
|
||||||
$st = $this->getPDO()->prepare('SELECT * FROM `' . $this->getNamespace() . '.database.documents` a
|
$st = $this->getPDO()->prepare('SELECT * FROM `'.$this->getNamespace().'.database.documents` a
|
||||||
WHERE a.uid = :uid AND a.status = 0
|
WHERE a.uid = :uid AND a.status = 0
|
||||||
ORDER BY a.updatedAt DESC LIMIT 10;
|
ORDER BY a.updatedAt DESC LIMIT 10;
|
||||||
');
|
');
|
||||||
|
@ -95,7 +97,7 @@ class MySQL extends Adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get fields abstraction
|
// Get fields abstraction
|
||||||
$st = $this->getPDO()->prepare('SELECT * FROM `' . $this->getNamespace() . '.database.properties` a
|
$st = $this->getPDO()->prepare('SELECT * FROM `'.$this->getNamespace().'.database.properties` a
|
||||||
WHERE a.documentUid = :documentUid AND a.documentRevision = :documentRevision
|
WHERE a.documentUid = :documentUid AND a.documentRevision = :documentRevision
|
||||||
ORDER BY `order`
|
ORDER BY `order`
|
||||||
');
|
');
|
||||||
|
@ -116,16 +118,15 @@ class MySQL extends Adapter
|
||||||
foreach ($properties as &$property) {
|
foreach ($properties as &$property) {
|
||||||
settype($property['value'], $property['primitive']);
|
settype($property['value'], $property['primitive']);
|
||||||
|
|
||||||
if($property['array']) {
|
if ($property['array']) {
|
||||||
$output[$property['key']][] = $property['value'];
|
$output[$property['key']][] = $property['value'];
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
$output[$property['key']] = $property['value'];
|
$output[$property['key']] = $property['value'];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get fields abstraction
|
// Get fields abstraction
|
||||||
$st = $this->getPDO()->prepare('SELECT * FROM `' . $this->getNamespace() . '.database.relationships` a
|
$st = $this->getPDO()->prepare('SELECT * FROM `'.$this->getNamespace().'.database.relationships` a
|
||||||
WHERE a.start = :start AND revision = :revision
|
WHERE a.start = :start AND revision = :revision
|
||||||
ORDER BY `order`
|
ORDER BY `order`
|
||||||
');
|
');
|
||||||
|
@ -141,25 +142,27 @@ class MySQL extends Adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create Document
|
* Create Document.
|
||||||
*
|
*
|
||||||
* @param array $data
|
* @param array $data
|
||||||
|
*
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function createDocument(array $data = [])
|
public function createDocument(array $data = [])
|
||||||
{
|
{
|
||||||
$order = 0;
|
$order = 0;
|
||||||
$data = array_merge(['$uid' => null, '$permissions' => []], $data); // Merge data with default params
|
$data = array_merge(['$uid' => null, '$permissions' => []], $data); // Merge data with default params
|
||||||
$signature = md5(json_encode($data, true));
|
$signature = md5(json_encode($data, true));
|
||||||
$revision = uniqid('', true);
|
$revision = uniqid('', true);
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* When updating node, check if there are any changes to update
|
* When updating node, check if there are any changes to update
|
||||||
* by comparing data md5 signatures
|
* by comparing data md5 signatures
|
||||||
*/
|
*/
|
||||||
if(null !== $data['$uid']) {
|
if (null !== $data['$uid']) {
|
||||||
$st = $this->getPDO()->prepare('SELECT signature FROM `' . $this->getNamespace() . '.database.documents` a
|
$st = $this->getPDO()->prepare('SELECT signature FROM `'.$this->getNamespace().'.database.documents` a
|
||||||
WHERE a.uid = :uid AND a.status = 0
|
WHERE a.uid = :uid AND a.status = 0
|
||||||
ORDER BY a.updatedAt DESC LIMIT 1;
|
ORDER BY a.updatedAt DESC LIMIT 1;
|
||||||
');
|
');
|
||||||
|
@ -170,67 +173,66 @@ class MySQL extends Adapter
|
||||||
|
|
||||||
$oldSignature = $st->fetch()['signature'];
|
$oldSignature = $st->fetch()['signature'];
|
||||||
|
|
||||||
if($signature === $oldSignature) {
|
if ($signature === $oldSignature) {
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add or update fields abstraction level
|
// Add or update fields abstraction level
|
||||||
$st1 = $this->getPDO()->prepare('INSERT INTO `' . $this->getNamespace() . '.database.documents`
|
$st1 = $this->getPDO()->prepare('INSERT INTO `'.$this->getNamespace().'.database.documents`
|
||||||
SET uid = :uid, createdAt = :createdAt, updatedAt = :updatedAt, signature = :signature, revision = :revision, permissions = :permissions, status = 0
|
SET uid = :uid, createdAt = :createdAt, updatedAt = :updatedAt, signature = :signature, revision = :revision, permissions = :permissions, status = 0
|
||||||
ON DUPLICATE KEY UPDATE uid = :uid, updatedAt = :updatedAt, signature = :signature, revision = :revision, permissions = :permissions;
|
ON DUPLICATE KEY UPDATE uid = :uid, updatedAt = :updatedAt, signature = :signature, revision = :revision, permissions = :permissions;
|
||||||
');
|
');
|
||||||
|
|
||||||
// Adding fields properties
|
// Adding fields properties
|
||||||
if(null === $data['$uid'] || !isset($data['$uid'])) { // Get new fields UID
|
if (null === $data['$uid'] || !isset($data['$uid'])) { // Get new fields UID
|
||||||
$data['$uid'] = $this->getUid();
|
$data['$uid'] = $this->getUid();
|
||||||
}
|
}
|
||||||
|
|
||||||
$st1->bindValue(':uid', $data['$uid'], PDO::PARAM_STR);
|
$st1->bindValue(':uid', $data['$uid'], PDO::PARAM_STR);
|
||||||
$st1->bindValue(':revision', $revision, PDO::PARAM_STR);
|
$st1->bindValue(':revision', $revision, PDO::PARAM_STR);
|
||||||
$st1->bindValue(':signature', $signature, PDO::PARAM_STR);
|
$st1->bindValue(':signature', $signature, PDO::PARAM_STR);
|
||||||
$st1->bindValue(':createdAt', date( 'Y-m-d H:i:s', time()),PDO::PARAM_STR);
|
$st1->bindValue(':createdAt', date('Y-m-d H:i:s', time()), PDO::PARAM_STR);
|
||||||
$st1->bindValue(':updatedAt', date( 'Y-m-d H:i:s', time()),PDO::PARAM_STR);
|
$st1->bindValue(':updatedAt', date('Y-m-d H:i:s', time()), PDO::PARAM_STR);
|
||||||
$st1->bindValue(':permissions', json_encode($data['$permissions']), PDO::PARAM_STR);
|
$st1->bindValue(':permissions', json_encode($data['$permissions']), PDO::PARAM_STR);
|
||||||
|
|
||||||
$st1->execute();
|
$st1->execute();
|
||||||
|
|
||||||
// Delete old properties
|
// Delete old properties
|
||||||
$rms1 = $this->getPDO()->prepare('DELETE FROM `' . $this->getNamespace() . '.database.properties` WHERE documentUid = :documentUid AND documentRevision != :documentRevision');
|
$rms1 = $this->getPDO()->prepare('DELETE FROM `'.$this->getNamespace().'.database.properties` WHERE documentUid = :documentUid AND documentRevision != :documentRevision');
|
||||||
$rms1->bindValue(':documentUid', $data['$uid'], PDO::PARAM_STR);
|
$rms1->bindValue(':documentUid', $data['$uid'], PDO::PARAM_STR);
|
||||||
$rms1->bindValue(':documentRevision', $revision, PDO::PARAM_STR);
|
$rms1->bindValue(':documentRevision', $revision, PDO::PARAM_STR);
|
||||||
$rms1->execute();
|
$rms1->execute();
|
||||||
|
|
||||||
// Delete old relationships
|
// Delete old relationships
|
||||||
$rms2 = $this->getPDO()->prepare('DELETE FROM `' . $this->getNamespace() . '.database.relationships` WHERE start = :start AND revision != :revision');
|
$rms2 = $this->getPDO()->prepare('DELETE FROM `'.$this->getNamespace().'.database.relationships` WHERE start = :start AND revision != :revision');
|
||||||
$rms2->bindValue(':start', $data['$uid'], PDO::PARAM_STR);
|
$rms2->bindValue(':start', $data['$uid'], PDO::PARAM_STR);
|
||||||
$rms2->bindValue(':revision', $revision, PDO::PARAM_STR);
|
$rms2->bindValue(':revision', $revision, PDO::PARAM_STR);
|
||||||
$rms2->execute();
|
$rms2->execute();
|
||||||
|
|
||||||
// Create new properties
|
// Create new properties
|
||||||
$st2 = $this->getPDO()->prepare('INSERT INTO `' . $this->getNamespace() . '.database.properties`
|
$st2 = $this->getPDO()->prepare('INSERT INTO `'.$this->getNamespace().'.database.properties`
|
||||||
(`documentUid`, `documentRevision`, `key`, `value`, `primitive`, `array`, `order`)
|
(`documentUid`, `documentRevision`, `key`, `value`, `primitive`, `array`, `order`)
|
||||||
VALUES (:documentUid, :documentRevision, :key, :value, :primitive, :array, :order)');
|
VALUES (:documentUid, :documentRevision, :key, :value, :primitive, :array, :order)');
|
||||||
|
|
||||||
$props = [];
|
$props = [];
|
||||||
|
|
||||||
foreach($data as $key => $value) { // Prepare properties data
|
foreach ($data as $key => $value) { // Prepare properties data
|
||||||
|
|
||||||
if(in_array($key, ['$permissions'])) {
|
if (in_array($key, ['$permissions'])) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$type = $this->getDataType($value);
|
$type = $this->getDataType($value);
|
||||||
|
|
||||||
// Handle array of relations
|
// Handle array of relations
|
||||||
if(self::DATA_TYPE_ARRAY === $type) {
|
if (self::DATA_TYPE_ARRAY === $type) {
|
||||||
foreach($value as $i => $child) {
|
foreach ($value as $i => $child) {
|
||||||
|
if (self::DATA_TYPE_DICTIONARY !== $this->getDataType($child)) { // not dictionary
|
||||||
if(self::DATA_TYPE_DICTIONARY !== $this->getDataType($child)) { // not dictionary
|
|
||||||
|
|
||||||
$props[] = [
|
$props[] = [
|
||||||
'type' => $this->getDataType($child),
|
'type' => $this->getDataType($child),
|
||||||
'key' => $key,
|
'key' => $key,
|
||||||
'value' => $child,
|
'value' => $child,
|
||||||
'array' => true,
|
'array' => true,
|
||||||
'order' => $order++,
|
'order' => $order++,
|
||||||
|
@ -248,20 +250,20 @@ class MySQL extends Adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle relation
|
// Handle relation
|
||||||
if(self::DATA_TYPE_DICTIONARY === $type) {
|
if (self::DATA_TYPE_DICTIONARY === $type) {
|
||||||
$value = $this->createDocument($value);
|
$value = $this->createDocument($value);
|
||||||
$this->createRelationship($revision, $data['$uid'], $value['$uid'], $key); //xxx
|
$this->createRelationship($revision, $data['$uid'], $value['$uid'], $key); //xxx
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle empty values
|
// Handle empty values
|
||||||
if(self::DATA_TYPE_NULL === $type) {
|
if (self::DATA_TYPE_NULL === $type) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
$props[] = [
|
$props[] = [
|
||||||
'type' => $type,
|
'type' => $type,
|
||||||
'key' => $key,
|
'key' => $key,
|
||||||
'value' => $value,
|
'value' => $value,
|
||||||
'array' => false,
|
'array' => false,
|
||||||
'order' => $order++,
|
'order' => $order++,
|
||||||
|
@ -269,8 +271,8 @@ class MySQL extends Adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($props as $prop) {
|
foreach ($props as $prop) {
|
||||||
if(is_array($prop['value'])) {
|
if (is_array($prop['value'])) {
|
||||||
throw new Exception('Value can\'t be an array: ' . json_encode($prop['value']));
|
throw new Exception('Value can\'t be an array: '.json_encode($prop['value']));
|
||||||
}
|
}
|
||||||
$st2->bindValue(':documentUid', $data['$uid'], PDO::PARAM_STR);
|
$st2->bindValue(':documentUid', $data['$uid'], PDO::PARAM_STR);
|
||||||
$st2->bindValue(':documentRevision', $revision, PDO::PARAM_STR);
|
$st2->bindValue(':documentRevision', $revision, PDO::PARAM_STR);
|
||||||
|
@ -285,17 +287,19 @@ class MySQL extends Adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO remove this dependency (check if related to nested documents)
|
//TODO remove this dependency (check if related to nested documents)
|
||||||
$this->getRedis()->expire($this->getNamespace() . ':document-' . $data['$uid'], 0);
|
$this->getRedis()->expire($this->getNamespace().':document-'.$data['$uid'], 0);
|
||||||
$this->getRedis()->expire($this->getNamespace() . ':document-' . $data['$uid'], 0);
|
$this->getRedis()->expire($this->getNamespace().':document-'.$data['$uid'], 0);
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update Document
|
* Update Document.
|
||||||
*
|
*
|
||||||
* @param array $data
|
* @param array $data
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function updateDocument(array $data = [])
|
public function updateDocument(array $data = [])
|
||||||
|
@ -304,15 +308,17 @@ class MySQL extends Adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete Document
|
* Delete Document.
|
||||||
*
|
*
|
||||||
* @param int $id
|
* @param int $id
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function deleteDocument($id)
|
public function deleteDocument($id)
|
||||||
{
|
{
|
||||||
$st1 = $this->getPDO()->prepare('DELETE FROM `' . $this->getNamespace() . '.database.documents`
|
$st1 = $this->getPDO()->prepare('DELETE FROM `'.$this->getNamespace().'.database.documents`
|
||||||
WHERE uid = :id
|
WHERE uid = :id
|
||||||
');
|
');
|
||||||
|
|
||||||
|
@ -320,7 +326,7 @@ class MySQL extends Adapter
|
||||||
|
|
||||||
$st1->execute();
|
$st1->execute();
|
||||||
|
|
||||||
$st2 = $this->getPDO()->prepare('DELETE FROM `' . $this->getNamespace() . '.database.properties`
|
$st2 = $this->getPDO()->prepare('DELETE FROM `'.$this->getNamespace().'.database.properties`
|
||||||
WHERE documentUid = :id
|
WHERE documentUid = :id
|
||||||
');
|
');
|
||||||
|
|
||||||
|
@ -328,7 +334,7 @@ class MySQL extends Adapter
|
||||||
|
|
||||||
$st2->execute();
|
$st2->execute();
|
||||||
|
|
||||||
$st3 = $this->getPDO()->prepare('DELETE FROM `' . $this->getNamespace() . '.database.relationships`
|
$st3 = $this->getPDO()->prepare('DELETE FROM `'.$this->getNamespace().'.database.relationships`
|
||||||
WHERE start = :id OR end = :id
|
WHERE start = :id OR end = :id
|
||||||
');
|
');
|
||||||
|
|
||||||
|
@ -340,22 +346,24 @@ class MySQL extends Adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create Relation
|
* Create Relation.
|
||||||
*
|
*
|
||||||
* Adds a new relationship between different nodes
|
* Adds a new relationship between different nodes
|
||||||
*
|
*
|
||||||
* @param string $revision
|
* @param string $revision
|
||||||
* @param int $start
|
* @param int $start
|
||||||
* @param int $end
|
* @param int $end
|
||||||
* @param string $key
|
* @param string $key
|
||||||
* @param bool $isArray
|
* @param bool $isArray
|
||||||
* @param int $order
|
* @param int $order
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
protected function createRelationship($revision, $start, $end, $key, $isArray = false, $order = 0)
|
protected function createRelationship($revision, $start, $end, $key, $isArray = false, $order = 0)
|
||||||
{
|
{
|
||||||
$st2 = $this->getPDO()->prepare('INSERT INTO `' . $this->getNamespace() . '.database.relationships`
|
$st2 = $this->getPDO()->prepare('INSERT INTO `'.$this->getNamespace().'.database.relationships`
|
||||||
(`revision`, `start`, `end`, `key`, `array`, `order`)
|
(`revision`, `start`, `end`, `key`, `array`, `order`)
|
||||||
VALUES (:revision, :start, :end, :key, :array, :order)');
|
VALUES (:revision, :start, :end, :key, :array, :order)');
|
||||||
|
|
||||||
|
@ -372,32 +380,33 @@ class MySQL extends Adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create Namespace
|
* Create Namespace.
|
||||||
*
|
*
|
||||||
* @param $namespace
|
* @param $namespace
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function createNamespace($namespace)
|
public function createNamespace($namespace)
|
||||||
{
|
{
|
||||||
if(empty($namespace)) {
|
if (empty($namespace)) {
|
||||||
throw new Exception('Empty namespace');
|
throw new Exception('Empty namespace');
|
||||||
}
|
}
|
||||||
|
|
||||||
$documents = 'app_' . $namespace . '.database.documents';
|
$documents = 'app_'.$namespace.'.database.documents';
|
||||||
$properties = 'app_' . $namespace . '.database.properties';
|
$properties = 'app_'.$namespace.'.database.properties';
|
||||||
$relationships = 'app_' . $namespace . '.database.relationships';
|
$relationships = 'app_'.$namespace.'.database.relationships';
|
||||||
$audit = 'app_' . $namespace . '.audit.audit';
|
$audit = 'app_'.$namespace.'.audit.audit';
|
||||||
$abuse = 'app_' . $namespace . '.abuse.abuse';
|
$abuse = 'app_'.$namespace.'.abuse.abuse';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->getPDO()->prepare('CREATE TABLE `' . $documents . '` LIKE `template.database.documents`;')->execute();
|
$this->getPDO()->prepare('CREATE TABLE `'.$documents.'` LIKE `template.database.documents`;')->execute();
|
||||||
$this->getPDO()->prepare('CREATE TABLE `' . $properties . '` LIKE `template.database.properties`;')->execute();
|
$this->getPDO()->prepare('CREATE TABLE `'.$properties.'` LIKE `template.database.properties`;')->execute();
|
||||||
$this->getPDO()->prepare('CREATE TABLE `' . $relationships . '` LIKE `template.database.relationships`;')->execute();
|
$this->getPDO()->prepare('CREATE TABLE `'.$relationships.'` LIKE `template.database.relationships`;')->execute();
|
||||||
$this->getPDO()->prepare('CREATE TABLE `' . $audit .'` LIKE `template.audit.audit`;')->execute();
|
$this->getPDO()->prepare('CREATE TABLE `'.$audit.'` LIKE `template.audit.audit`;')->execute();
|
||||||
$this->getPDO()->prepare('CREATE TABLE `' . $abuse . '` LIKE `template.abuse.abuse`;')->execute();
|
$this->getPDO()->prepare('CREATE TABLE `'.$abuse.'` LIKE `template.abuse.abuse`;')->execute();
|
||||||
}
|
} catch (Exception $e) {
|
||||||
catch (Exception $e) {
|
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -405,32 +414,33 @@ class MySQL extends Adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete Namespace
|
* Delete Namespace.
|
||||||
*
|
*
|
||||||
* @param $namespace
|
* @param $namespace
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function deleteNamespace($namespace)
|
public function deleteNamespace($namespace)
|
||||||
{
|
{
|
||||||
if(empty($namespace)) {
|
if (empty($namespace)) {
|
||||||
throw new Exception('Empty namespace');
|
throw new Exception('Empty namespace');
|
||||||
}
|
}
|
||||||
|
|
||||||
$documents = 'app_' . $namespace . '.database.documents';
|
$documents = 'app_'.$namespace.'.database.documents';
|
||||||
$properties = 'app_' . $namespace . '.database.properties';
|
$properties = 'app_'.$namespace.'.database.properties';
|
||||||
$relationships = 'app_' . $namespace . '.database.relationships';
|
$relationships = 'app_'.$namespace.'.database.relationships';
|
||||||
$audit = 'app_' . $namespace . '.audit.audit';
|
$audit = 'app_'.$namespace.'.audit.audit';
|
||||||
$abuse = 'app_' . $namespace . '.abuse.abuse';
|
$abuse = 'app_'.$namespace.'.abuse.abuse';
|
||||||
|
|
||||||
try {
|
try {
|
||||||
$this->getPDO()->prepare('DROP TABLE `' . $documents . '`;')->execute();
|
$this->getPDO()->prepare('DROP TABLE `'.$documents.'`;')->execute();
|
||||||
$this->getPDO()->prepare('DROP TABLE `' . $properties . '`;')->execute();
|
$this->getPDO()->prepare('DROP TABLE `'.$properties.'`;')->execute();
|
||||||
$this->getPDO()->prepare('DROP TABLE `' . $relationships . '`;')->execute();
|
$this->getPDO()->prepare('DROP TABLE `'.$relationships.'`;')->execute();
|
||||||
$this->getPDO()->prepare('DROP TABLE `' . $audit .'`;')->execute();
|
$this->getPDO()->prepare('DROP TABLE `'.$audit.'`;')->execute();
|
||||||
$this->getPDO()->prepare('DROP TABLE `' . $abuse . '`;')->execute();
|
$this->getPDO()->prepare('DROP TABLE `'.$abuse.'`;')->execute();
|
||||||
}
|
} catch (Exception $e) {
|
||||||
catch (Exception $e) {
|
|
||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -438,84 +448,83 @@ class MySQL extends Adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Collection
|
* Get Collection.
|
||||||
*
|
*
|
||||||
* @param array $options
|
* @param array $options
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getCollection(array $options)
|
public function getCollection(array $options)
|
||||||
{
|
{
|
||||||
$start = microtime(true);
|
$start = microtime(true);
|
||||||
$orderCastMap = [
|
$orderCastMap = [
|
||||||
'int' => 'UNSIGNED',
|
'int' => 'UNSIGNED',
|
||||||
'string' => 'CHAR',
|
'string' => 'CHAR',
|
||||||
'date' => 'DATE',
|
'date' => 'DATE',
|
||||||
'time' => 'TIME',
|
'time' => 'TIME',
|
||||||
'datetime' => 'DATETIME',
|
'datetime' => 'DATETIME',
|
||||||
];
|
];
|
||||||
$orderTypeMap = ['DESC', 'ASC'];
|
$orderTypeMap = ['DESC', 'ASC'];
|
||||||
|
|
||||||
$options['orderField'] = (empty($options['orderField'])) ? '$uid' : $options['orderField']; // Set default order field
|
$options['orderField'] = (empty($options['orderField'])) ? '$uid' : $options['orderField']; // Set default order field
|
||||||
$options['orderCast'] = (empty($options['orderCast'])) ? 'string' : $options['orderCast']; // Set default order field
|
$options['orderCast'] = (empty($options['orderCast'])) ? 'string' : $options['orderCast']; // Set default order field
|
||||||
|
|
||||||
if(!array_key_exists($options['orderCast'], $orderCastMap)) {
|
if (!array_key_exists($options['orderCast'], $orderCastMap)) {
|
||||||
throw new Exception('Invalid order cast');
|
throw new Exception('Invalid order cast');
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!in_array($options['orderType'], $orderTypeMap)) {
|
if (!in_array($options['orderType'], $orderTypeMap)) {
|
||||||
throw new Exception('Invalid order type');
|
throw new Exception('Invalid order type');
|
||||||
}
|
}
|
||||||
|
|
||||||
$where = [];
|
$where = [];
|
||||||
$join = [];
|
$join = [];
|
||||||
$sorts = [];
|
$sorts = [];
|
||||||
$search = '';
|
$search = '';
|
||||||
|
|
||||||
// Filters
|
// Filters
|
||||||
foreach($options['filters'] as $i => $filter) {
|
foreach ($options['filters'] as $i => $filter) {
|
||||||
$filter = $this->parseFilter($filter);
|
$filter = $this->parseFilter($filter);
|
||||||
$key = $filter['key'];
|
$key = $filter['key'];
|
||||||
$value = $filter['value'];
|
$value = $filter['value'];
|
||||||
$operator = $filter['operator'];
|
$operator = $filter['operator'];
|
||||||
|
|
||||||
$path = explode('.', $key);
|
$path = explode('.', $key);
|
||||||
$original = $path;
|
$original = $path;
|
||||||
|
|
||||||
if(1 < count($path)) {
|
if (1 < count($path)) {
|
||||||
$key = array_pop($path);
|
$key = array_pop($path);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
$path = [];
|
$path = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
//$path = implode('.', $path);
|
//$path = implode('.', $path);
|
||||||
|
|
||||||
$key = $this->getPDO()->quote($key, PDO::PARAM_STR);
|
$key = $this->getPDO()->quote($key, PDO::PARAM_STR);
|
||||||
$value = $this->getPDO()->quote($value, PDO::PARAM_STR);
|
$value = $this->getPDO()->quote($value, PDO::PARAM_STR);
|
||||||
//$path = $this->getPDO()->quote($path, PDO::PARAM_STR);
|
//$path = $this->getPDO()->quote($path, PDO::PARAM_STR);
|
||||||
$options['offset'] = (int)$options['offset'];
|
$options['offset'] = (int) $options['offset'];
|
||||||
$options['limit'] = (int)$options['limit'];
|
$options['limit'] = (int) $options['limit'];
|
||||||
|
|
||||||
if(empty($path)) {//if($path == "''") { // Handle direct attributes queries
|
if (empty($path)) {
|
||||||
$where[] = "JOIN `" . $this->getNamespace() . ".database.properties` b{$i} ON a.uid IS NOT NULL AND b{$i}.documentUid = a.uid AND (b{$i}.key = {$key} AND b{$i}.value {$operator} {$value})";
|
//if($path == "''") { // Handle direct attributes queries
|
||||||
}
|
$where[] = 'JOIN `'.$this->getNamespace().".database.properties` b{$i} ON a.uid IS NOT NULL AND b{$i}.documentUid = a.uid AND (b{$i}.key = {$key} AND b{$i}.value {$operator} {$value})";
|
||||||
else { // Handle direct child attributes queries
|
} else { // Handle direct child attributes queries
|
||||||
$len = count($original);
|
$len = count($original);
|
||||||
$prev = 'c' . $i;
|
$prev = 'c'.$i;
|
||||||
|
|
||||||
foreach ($original as $y => $part) {
|
foreach ($original as $y => $part) {
|
||||||
$part = $this->getPDO()->quote($part, PDO::PARAM_STR);
|
$part = $this->getPDO()->quote($part, PDO::PARAM_STR);
|
||||||
|
|
||||||
if(0 === $y) { // First key
|
if (0 === $y) { // First key
|
||||||
$join[$i] = "JOIN `" . $this->getNamespace() . ".database.relationships` c{$i} ON a.uid IS NOT NULL AND c{$i}.start = a.uid AND c{$i}.key = {$part}";
|
$join[$i] = 'JOIN `'.$this->getNamespace().".database.relationships` c{$i} ON a.uid IS NOT NULL AND c{$i}.start = a.uid AND c{$i}.key = {$part}";
|
||||||
}
|
} elseif ($y == $len - 1) { // Last key
|
||||||
else if ($y == $len - 1) { // Last key
|
$join[$i] .= 'JOIN `'.$this->getNamespace().".database.properties` e{$i} ON e{$i}.documentUid = {$prev}.end AND e{$i}.key = {$part} AND e{$i}.value {$operator} {$value}";
|
||||||
$join[$i] .= "JOIN `" . $this->getNamespace() . ".database.properties` e{$i} ON e{$i}.documentUid = {$prev}.end AND e{$i}.key = {$part} AND e{$i}.value {$operator} {$value}";
|
} else {
|
||||||
}
|
$join[$i] .= 'JOIN `'.$this->getNamespace().".database.relationships` d{$i}{$y} ON d{$i}{$y}.start = {$prev}.end AND d{$i}{$y}.key = {$part}";
|
||||||
else {
|
$prev = 'd'.$i.$y;
|
||||||
$join[$i] .= "JOIN `" . $this->getNamespace() . ".database.relationships` d{$i}{$y} ON d{$i}{$y}.start = {$prev}.end AND d{$i}{$y}.key = {$part}";
|
|
||||||
$prev = 'd' . $i . $y;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -525,44 +534,42 @@ class MySQL extends Adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sorting
|
// Sorting
|
||||||
$orderPath = explode('.', $options['orderField']);
|
$orderPath = explode('.', $options['orderField']);
|
||||||
$len = count($orderPath);
|
$len = count($orderPath);
|
||||||
$orderKey = 'order_b';
|
$orderKey = 'order_b';
|
||||||
$part = $this->getPDO()->quote(implode('', $orderPath), PDO::PARAM_STR);
|
$part = $this->getPDO()->quote(implode('', $orderPath), PDO::PARAM_STR);
|
||||||
$orderSelect = "CASE WHEN {$orderKey}.key = {$part} THEN CAST({$orderKey}.value AS {$orderCastMap[$options['orderCast']]}) END AS sort_ff";
|
$orderSelect = "CASE WHEN {$orderKey}.key = {$part} THEN CAST({$orderKey}.value AS {$orderCastMap[$options['orderCast']]}) END AS sort_ff";
|
||||||
|
|
||||||
if(1 === $len) {//if($path == "''") { // Handle direct attributes queries
|
if (1 === $len) {
|
||||||
$sorts[] = "LEFT JOIN `" . $this->getNamespace() . ".database.properties` order_b ON a.uid IS NOT NULL AND order_b.documentUid = a.uid AND (order_b.key = {$part})";
|
//if($path == "''") { // Handle direct attributes queries
|
||||||
}
|
$sorts[] = 'LEFT JOIN `'.$this->getNamespace().".database.properties` order_b ON a.uid IS NOT NULL AND order_b.documentUid = a.uid AND (order_b.key = {$part})";
|
||||||
else { // Handle direct child attributes queries
|
} else { // Handle direct child attributes queries
|
||||||
$prev = 'c';
|
$prev = 'c';
|
||||||
$orderKey = 'order_e';
|
$orderKey = 'order_e';
|
||||||
|
|
||||||
foreach ($orderPath as $y => $part) {
|
foreach ($orderPath as $y => $part) {
|
||||||
$part = $this->getPDO()->quote($part, PDO::PARAM_STR);
|
$part = $this->getPDO()->quote($part, PDO::PARAM_STR);
|
||||||
$x = $y -1;
|
$x = $y - 1;
|
||||||
|
|
||||||
if(0 === $y) { // First key
|
if (0 === $y) { // First key
|
||||||
$sorts[] = "JOIN `" . $this->getNamespace() . ".database.relationships` order_c{$y} ON a.uid IS NOT NULL AND order_c{$y}.start = a.uid AND order_c{$y}.key = {$part}";
|
$sorts[] = 'JOIN `'.$this->getNamespace().".database.relationships` order_c{$y} ON a.uid IS NOT NULL AND order_c{$y}.start = a.uid AND order_c{$y}.key = {$part}";
|
||||||
}
|
} elseif ($y == $len - 1) { // Last key
|
||||||
else if ($y == $len - 1) { // Last key
|
$sorts[] .= 'JOIN `'.$this->getNamespace().".database.properties` order_e ON order_e.documentUid = order_{$prev}{$x}.end AND order_e.key = {$part}";
|
||||||
$sorts[] .= "JOIN `" . $this->getNamespace() . ".database.properties` order_e ON order_e.documentUid = order_{$prev}{$x}.end AND order_e.key = {$part}";
|
} else {
|
||||||
}
|
$sorts[] .= 'JOIN `'.$this->getNamespace().".database.relationships` order_d{$y} ON order_d{$y}.start = order_{$prev}{$x}.end AND order_d{$y}.key = {$part}";
|
||||||
else {
|
|
||||||
$sorts[] .= "JOIN `" . $this->getNamespace() . ".database.relationships` order_d{$y} ON order_d{$y}.start = order_{$prev}{$x}.end AND order_d{$y}.key = {$part}";
|
|
||||||
$prev = 'd';
|
$prev = 'd';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/*
|
||||||
* Workaround for a MySQL bug as reported here:
|
* Workaround for a MySQL bug as reported here:
|
||||||
* https://bugs.mysql.com/bug.php?id=78485
|
* https://bugs.mysql.com/bug.php?id=78485
|
||||||
*/
|
*/
|
||||||
$options['search'] = ($options['search'] === '*') ? '' : $options['search'];
|
$options['search'] = ($options['search'] === '*') ? '' : $options['search'];
|
||||||
|
|
||||||
// Search
|
// Search
|
||||||
if(!empty($options['search'])) { // Handle free search
|
if (!empty($options['search'])) { // Handle free search
|
||||||
// $where[] = "LEFT JOIN `" . $this->getNamespace() . ".database.properties` b_search ON a.uid IS NOT NULL AND b_search.documentUid = a.uid
|
// $where[] = "LEFT JOIN `" . $this->getNamespace() . ".database.properties` b_search ON a.uid IS NOT NULL AND b_search.documentUid = a.uid
|
||||||
// LEFT JOIN
|
// LEFT JOIN
|
||||||
// `" . $this->getNamespace() . ".database.relationships` c_search ON c_search.start = a.uid
|
// `" . $this->getNamespace() . ".database.relationships` c_search ON c_search.start = a.uid
|
||||||
|
@ -580,11 +587,11 @@ class MySQL extends Adapter
|
||||||
// OR MATCH (f_search.value) AGAINST ({$this->getPDO()->quote($options['search'], PDO::PARAM_STR)} IN BOOLEAN MODE)
|
// OR MATCH (f_search.value) AGAINST ({$this->getPDO()->quote($options['search'], PDO::PARAM_STR)} IN BOOLEAN MODE)
|
||||||
// OR f_search.value LIKE {$this->getPDO()->quote('%%' . $options['search'] . '%%', PDO::PARAM_STR)})";
|
// OR f_search.value LIKE {$this->getPDO()->quote('%%' . $options['search'] . '%%', PDO::PARAM_STR)})";
|
||||||
|
|
||||||
$where[] = "LEFT JOIN `" . $this->getNamespace() . ".database.properties` b_search ON a.uid IS NOT NULL AND b_search.documentUid = a.uid AND b_search.primitive = 'string'
|
$where[] = 'LEFT JOIN `'.$this->getNamespace().".database.properties` b_search ON a.uid IS NOT NULL AND b_search.documentUid = a.uid AND b_search.primitive = 'string'
|
||||||
LEFT JOIN
|
LEFT JOIN
|
||||||
`" . $this->getNamespace() . ".database.relationships` c_search ON c_search.start = b_search.documentUid
|
`".$this->getNamespace().'.database.relationships` c_search ON c_search.start = b_search.documentUid
|
||||||
LEFT JOIN
|
LEFT JOIN
|
||||||
`" . $this->getNamespace() . ".database.properties` d_search ON d_search.documentUid = c_search.end AND d_search.primitive = 'string'
|
`'.$this->getNamespace().".database.properties` d_search ON d_search.documentUid = c_search.end AND d_search.primitive = 'string'
|
||||||
\n";
|
\n";
|
||||||
|
|
||||||
$search = "AND (MATCH (b_search.value) AGAINST ({$this->getPDO()->quote($options['search'], PDO::PARAM_STR)} IN BOOLEAN MODE)
|
$search = "AND (MATCH (b_search.value) AGAINST ({$this->getPDO()->quote($options['search'], PDO::PARAM_STR)} IN BOOLEAN MODE)
|
||||||
|
@ -593,25 +600,25 @@ class MySQL extends Adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
$select = 'DISTINCT a.uid';
|
$select = 'DISTINCT a.uid';
|
||||||
$where = implode("\n", $where);
|
$where = implode("\n", $where);
|
||||||
$join = implode("\n", $join);
|
$join = implode("\n", $join);
|
||||||
$sorts = implode("\n", $sorts);
|
$sorts = implode("\n", $sorts);
|
||||||
$range = "LIMIT {$options['offset']}, {$options['limit']}";
|
$range = "LIMIT {$options['offset']}, {$options['limit']}";
|
||||||
$roles = [];
|
$roles = [];
|
||||||
|
|
||||||
foreach (Authorization::getRoles() as $role) {
|
foreach (Authorization::getRoles() as $role) {
|
||||||
$roles[] = 'JSON_CONTAINS(REPLACE(a.permissions, \'{self}\', a.uid), \'"' . $role . '"\', \'$.read\')';
|
$roles[] = 'JSON_CONTAINS(REPLACE(a.permissions, \'{self}\', a.uid), \'"'.$role.'"\', \'$.read\')';
|
||||||
}
|
}
|
||||||
|
|
||||||
if(false === Authorization::$status) { // FIXME temporary solution (hopefully)
|
if (false === Authorization::$status) { // FIXME temporary solution (hopefully)
|
||||||
$roles = ['1=1'];
|
$roles = ['1=1'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$query = "SELECT %s, {$orderSelect}
|
$query = "SELECT %s, {$orderSelect}
|
||||||
FROM `" . $this->getNamespace() . ".database.documents` a {$where}{$join}{$sorts}
|
FROM `".$this->getNamespace().".database.documents` a {$where}{$join}{$sorts}
|
||||||
WHERE status = 0
|
WHERE status = 0
|
||||||
{$search}
|
{$search}
|
||||||
AND (" . implode('||', $roles) . ")
|
AND (".implode('||', $roles).")
|
||||||
ORDER BY sort_ff {$options['orderType']} %s";
|
ORDER BY sort_ff {$options['orderType']} %s";
|
||||||
|
|
||||||
$st = $this->getPDO()->prepare(sprintf($query, $select, $range));
|
$st = $this->getPDO()->prepare(sprintf($query, $select, $range));
|
||||||
|
@ -621,7 +628,7 @@ class MySQL extends Adapter
|
||||||
$results = ['data' => []];
|
$results = ['data' => []];
|
||||||
|
|
||||||
// Get entire fields data for each id
|
// Get entire fields data for each id
|
||||||
foreach($st->fetchAll() as $node) {
|
foreach ($st->fetchAll() as $node) {
|
||||||
$results['data'][] = $node['uid'];
|
$results['data'][] = $node['uid'];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -634,12 +641,12 @@ class MySQL extends Adapter
|
||||||
$this->resetDebug();
|
$this->resetDebug();
|
||||||
|
|
||||||
$this
|
$this
|
||||||
->setDebug('query', preg_replace('/\s+/', ' ',sprintf($query, $select, $range)))
|
->setDebug('query', preg_replace('/\s+/', ' ', sprintf($query, $select, $range)))
|
||||||
->setDebug('time', microtime(true) - $start)
|
->setDebug('time', microtime(true) - $start)
|
||||||
->setDebug('filters', count($options['filters']))
|
->setDebug('filters', count($options['filters']))
|
||||||
->setDebug('joins', substr_count($query, 'JOIN'))
|
->setDebug('joins', substr_count($query, 'JOIN'))
|
||||||
->setDebug('count', count($results['data']))
|
->setDebug('count', count($results['data']))
|
||||||
->setDebug('sum', (int)$count['sum'])
|
->setDebug('sum', (int) $count['sum'])
|
||||||
->setDebug('documents', $this->count)
|
->setDebug('documents', $this->count)
|
||||||
;
|
;
|
||||||
|
|
||||||
|
@ -647,80 +654,79 @@ class MySQL extends Adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Collection
|
* Get Collection.
|
||||||
*
|
*
|
||||||
* @param array $options
|
* @param array $options
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getCount(array $options)
|
public function getCount(array $options)
|
||||||
{
|
{
|
||||||
$start = microtime(true);
|
$start = microtime(true);
|
||||||
$where = [];
|
$where = [];
|
||||||
$join = [];
|
$join = [];
|
||||||
|
|
||||||
// Filters
|
// Filters
|
||||||
foreach($options['filters'] as $i => $filter) {
|
foreach ($options['filters'] as $i => $filter) {
|
||||||
$filter = $this->parseFilter($filter);
|
$filter = $this->parseFilter($filter);
|
||||||
$key = $filter['key'];
|
$key = $filter['key'];
|
||||||
$value = $filter['value'];
|
$value = $filter['value'];
|
||||||
$operator = $filter['operator'];
|
$operator = $filter['operator'];
|
||||||
$path = explode('.', $key);
|
$path = explode('.', $key);
|
||||||
$original = $path;
|
$original = $path;
|
||||||
|
|
||||||
if(1 < count($path)) {
|
if (1 < count($path)) {
|
||||||
$key = array_pop($path);
|
$key = array_pop($path);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
$path = [];
|
$path = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
$key = $this->getPDO()->quote($key, PDO::PARAM_STR);
|
$key = $this->getPDO()->quote($key, PDO::PARAM_STR);
|
||||||
$value = $this->getPDO()->quote($value, PDO::PARAM_STR);
|
$value = $this->getPDO()->quote($value, PDO::PARAM_STR);
|
||||||
|
|
||||||
if(empty($path)) {//if($path == "''") { // Handle direct attributes queries
|
if (empty($path)) {
|
||||||
$where[] = "JOIN `" . $this->getNamespace() . ".database.properties` b{$i} ON a.uid IS NOT NULL AND b{$i}.documentUid = a.uid AND (b{$i}.key = {$key} AND b{$i}.value {$operator} {$value})";
|
//if($path == "''") { // Handle direct attributes queries
|
||||||
}
|
$where[] = 'JOIN `'.$this->getNamespace().".database.properties` b{$i} ON a.uid IS NOT NULL AND b{$i}.documentUid = a.uid AND (b{$i}.key = {$key} AND b{$i}.value {$operator} {$value})";
|
||||||
else { // Handle direct child attributes queries
|
} else { // Handle direct child attributes queries
|
||||||
$len = count($original);
|
$len = count($original);
|
||||||
$prev = 'c' . $i;
|
$prev = 'c'.$i;
|
||||||
|
|
||||||
foreach ($original as $y => $part) {
|
foreach ($original as $y => $part) {
|
||||||
$part = $this->getPDO()->quote($part, PDO::PARAM_STR);
|
$part = $this->getPDO()->quote($part, PDO::PARAM_STR);
|
||||||
|
|
||||||
if(0 === $y) { // First key
|
if (0 === $y) { // First key
|
||||||
$join[$i] = "JOIN `" . $this->getNamespace() . ".database.relationships` c{$i} ON a.uid IS NOT NULL AND c{$i}.start = a.uid AND c{$i}.key = {$part}";
|
$join[$i] = 'JOIN `'.$this->getNamespace().".database.relationships` c{$i} ON a.uid IS NOT NULL AND c{$i}.start = a.uid AND c{$i}.key = {$part}";
|
||||||
}
|
} elseif ($y == $len - 1) { // Last key
|
||||||
else if ($y == $len - 1) { // Last key
|
$join[$i] .= 'JOIN `'.$this->getNamespace().".database.properties` e{$i} ON e{$i}.documentUid = {$prev}.end AND e{$i}.key = {$part} AND e{$i}.value {$operator} {$value}";
|
||||||
$join[$i] .= "JOIN `" . $this->getNamespace() . ".database.properties` e{$i} ON e{$i}.documentUid = {$prev}.end AND e{$i}.key = {$part} AND e{$i}.value {$operator} {$value}";
|
} else {
|
||||||
}
|
$join[$i] .= 'JOIN `'.$this->getNamespace().".database.relationships` d{$i}{$y} ON d{$i}{$y}.start = {$prev}.end AND d{$i}{$y}.key = {$part}";
|
||||||
else {
|
$prev = 'd'.$i.$y;
|
||||||
$join[$i] .= "JOIN `" . $this->getNamespace() . ".database.relationships` d{$i}{$y} ON d{$i}{$y}.start = {$prev}.end AND d{$i}{$y}.key = {$part}";
|
|
||||||
$prev = 'd' . $i . $y;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$where = implode("\n", $where);
|
$where = implode("\n", $where);
|
||||||
$join = implode("\n", $join);
|
$join = implode("\n", $join);
|
||||||
$func = "JOIN `" . $this->getNamespace() . ".database.properties` b_func ON a.uid IS NOT NULL
|
$func = 'JOIN `'.$this->getNamespace().".database.properties` b_func ON a.uid IS NOT NULL
|
||||||
AND a.uid = b_func.documentUid
|
AND a.uid = b_func.documentUid
|
||||||
AND (b_func.key = 'sizeOriginal')";
|
AND (b_func.key = 'sizeOriginal')";
|
||||||
$roles = [];
|
$roles = [];
|
||||||
|
|
||||||
foreach (Authorization::getRoles() as $role) {
|
foreach (Authorization::getRoles() as $role) {
|
||||||
$roles[] = 'JSON_CONTAINS(REPLACE(a.permissions, \'{self}\', a.uid), \'"' . $role . '"\', \'$.read\')';
|
$roles[] = 'JSON_CONTAINS(REPLACE(a.permissions, \'{self}\', a.uid), \'"'.$role.'"\', \'$.read\')';
|
||||||
}
|
}
|
||||||
|
|
||||||
if(false === Authorization::$status) { // FIXME temporary solution (hopefully)
|
if (false === Authorization::$status) { // FIXME temporary solution (hopefully)
|
||||||
$roles = ['1=1'];
|
$roles = ['1=1'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$query = "SELECT SUM(b_func.value) as result
|
$query = 'SELECT SUM(b_func.value) as result
|
||||||
FROM `" . $this->getNamespace() . ".database.documents` a {$where}{$join}{$func}
|
FROM `'.$this->getNamespace().".database.documents` a {$where}{$join}{$func}
|
||||||
WHERE status = 0
|
WHERE status = 0
|
||||||
AND (" . implode('||', $roles) . ")";
|
AND (".implode('||', $roles).')';
|
||||||
|
|
||||||
$st = $this->getPDO()->prepare(sprintf($query));
|
$st = $this->getPDO()->prepare(sprintf($query));
|
||||||
|
|
||||||
|
@ -731,36 +737,36 @@ class MySQL extends Adapter
|
||||||
$this->resetDebug();
|
$this->resetDebug();
|
||||||
|
|
||||||
$this
|
$this
|
||||||
->setDebug('query', preg_replace('/\s+/', ' ',sprintf($query)))
|
->setDebug('query', preg_replace('/\s+/', ' ', sprintf($query)))
|
||||||
->setDebug('time', microtime(true) - $start)
|
->setDebug('time', microtime(true) - $start)
|
||||||
->setDebug('filters', count($options['filters']))
|
->setDebug('filters', count($options['filters']))
|
||||||
->setDebug('joins', substr_count($query, 'JOIN'))
|
->setDebug('joins', substr_count($query, 'JOIN'))
|
||||||
;
|
;
|
||||||
|
|
||||||
return (int)(isset($result['result'])) ? $result['result'] : 0;
|
return (int) (isset($result['result'])) ? $result['result'] : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Unique Document ID
|
* Get Unique Document ID.
|
||||||
*/
|
*/
|
||||||
public function getUid()
|
public function getUid()
|
||||||
{
|
{
|
||||||
$unique = uniqid();
|
$unique = uniqid();
|
||||||
$attempts = 5;
|
$attempts = 5;
|
||||||
|
|
||||||
for ($i = 1; $i <= $attempts; $i++) {
|
for ($i = 1; $i <= $attempts; ++$i) {
|
||||||
$document = $this->getDocument($unique);
|
$document = $this->getDocument($unique);
|
||||||
|
|
||||||
if(empty($document) || $document['$uid'] !== $unique) {
|
if (empty($document) || $document['$uid'] !== $unique) {
|
||||||
return $unique;
|
return $unique;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Exception('Failed to create a unique ID (' . $attempts . ' attempts)');
|
throw new Exception('Failed to create a unique ID ('.$attempts.' attempts)');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Last Modified
|
* Last Modified.
|
||||||
*
|
*
|
||||||
* Return unix timestamp of last time a node queried in corrent session has been changed
|
* Return unix timestamp of last time a node queried in corrent session has been changed
|
||||||
*
|
*
|
||||||
|
@ -772,15 +778,17 @@ class MySQL extends Adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse Filter
|
* Parse Filter.
|
||||||
*
|
*
|
||||||
* @param string $filter
|
* @param string $filter
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
protected function parseFilter($filter)
|
protected function parseFilter($filter)
|
||||||
{
|
{
|
||||||
$operatorsMap = ['!=', '>=', '<=', '=', '>', '<']; // Do not edit order of this array
|
$operatorsMap = ['!=', '>=', '<=', '=', '>', '<']; // Do not edit order of this array
|
||||||
|
|
||||||
//FIXME bug with >= <= operators
|
//FIXME bug with >= <= operators
|
||||||
|
|
||||||
|
@ -793,13 +801,13 @@ class MySQL extends Adapter
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(empty($operator)) {
|
if (empty($operator)) {
|
||||||
throw new Exception('Invalid operator');
|
throw new Exception('Invalid operator');
|
||||||
}
|
}
|
||||||
|
|
||||||
$filter = explode($operator, $filter);
|
$filter = explode($operator, $filter);
|
||||||
|
|
||||||
if(count($filter) != 2) {
|
if (count($filter) != 2) {
|
||||||
throw new Exception('Invalid filter expression');
|
throw new Exception('Invalid filter expression');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -811,18 +819,20 @@ class MySQL extends Adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Data Type
|
* Get Data Type.
|
||||||
*
|
*
|
||||||
* Check value data type. return value can be on of the following:
|
* Check value data type. return value can be on of the following:
|
||||||
* string, integer, float, boolean, object, list or null
|
* string, integer, float, boolean, object, list or null
|
||||||
*
|
*
|
||||||
* @param $value
|
* @param $value
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
|
*
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
*/
|
*/
|
||||||
protected function getDataType($value)
|
protected function getDataType($value)
|
||||||
{
|
{
|
||||||
switch(gettype($value)) {
|
switch (gettype($value)) {
|
||||||
|
|
||||||
case 'string':
|
case 'string':
|
||||||
return self::DATA_TYPE_STRING;
|
return self::DATA_TYPE_STRING;
|
||||||
|
@ -841,7 +851,7 @@ class MySQL extends Adapter
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'array':
|
case 'array':
|
||||||
if((bool)count(array_filter(array_keys($value), 'is_string'))) {
|
if ((bool) count(array_filter(array_keys($value), 'is_string'))) {
|
||||||
return self::DATA_TYPE_DICTIONARY;
|
return self::DATA_TYPE_DICTIONARY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -853,12 +863,13 @@ class MySQL extends Adapter
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
throw new Exception('Unknown data type: ' . $value . ' (' . gettype($value) . ')');
|
throw new Exception('Unknown data type: '.$value.' ('.gettype($value).')');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $key
|
* @param $key
|
||||||
* @param $value
|
* @param $value
|
||||||
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setDebug($key, $value)
|
public function setDebug($key, $value)
|
||||||
|
@ -877,15 +888,16 @@ class MySQL extends Adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* return $this;
|
* return $this;.
|
||||||
*/
|
*/
|
||||||
public function resetDebug()
|
public function resetDebug()
|
||||||
{
|
{
|
||||||
$this->debug =[];
|
$this->debug = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return PDO
|
* @return PDO
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
protected function getPDO():PDO
|
protected function getPDO():PDO
|
||||||
|
@ -895,10 +907,11 @@ class MySQL extends Adapter
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
|
*
|
||||||
* @return Client
|
* @return Client
|
||||||
*/
|
*/
|
||||||
protected function getRedis():Client
|
protected function getRedis():Client
|
||||||
{
|
{
|
||||||
return $this->register->get('cache');
|
return $this->register->get('cache');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,29 +21,32 @@ class Redis extends Adapter
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Redis constructor.
|
* Redis constructor.
|
||||||
* @param Adapter $adapter
|
*
|
||||||
|
* @param Adapter $adapter
|
||||||
* @param Registry $register
|
* @param Registry $register
|
||||||
*/
|
*/
|
||||||
public function __construct(Adapter $adapter, Registry $register)
|
public function __construct(Adapter $adapter, Registry $register)
|
||||||
{
|
{
|
||||||
$this->register = $register;
|
$this->register = $register;
|
||||||
$this->adapter = $adapter;
|
$this->adapter = $adapter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Document
|
* Get Document.
|
||||||
*
|
*
|
||||||
* @param string $id
|
* @param string $id
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function getDocument($id)
|
public function getDocument($id)
|
||||||
{
|
{
|
||||||
$output = json_decode($this->getRedis()->get($this->getNamespace() . ':document-' . $id), true);
|
$output = json_decode($this->getRedis()->get($this->getNamespace().':document-'.$id), true);
|
||||||
|
|
||||||
if(!$output) {
|
if (!$output) {
|
||||||
$output = $this->adapter->getDocument($id);
|
$output = $this->adapter->getDocument($id);
|
||||||
$this->getRedis()->set($this->getNamespace() . ':document-' . $id, json_encode($output, JSON_UNESCAPED_UNICODE));
|
$this->getRedis()->set($this->getNamespace().':document-'.$id, json_encode($output, JSON_UNESCAPED_UNICODE));
|
||||||
}
|
}
|
||||||
|
|
||||||
$output = $this->parseRelations($output);
|
$output = $this->parseRelations($output);
|
||||||
|
@ -53,36 +56,37 @@ class Redis extends Adapter
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $output
|
* @param $output
|
||||||
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
protected function parseRelations($output)
|
protected function parseRelations($output)
|
||||||
{
|
{
|
||||||
$keys = [];
|
$keys = [];
|
||||||
|
|
||||||
if(empty($output) || !isset($output['temp-relations'])) {
|
if (empty($output) || !isset($output['temp-relations'])) {
|
||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach($output['temp-relations'] as $relationship) {
|
foreach ($output['temp-relations'] as $relationship) {
|
||||||
$keys[] = $this->getNamespace() . ':document-' . $relationship['end'];
|
$keys[] = $this->getNamespace().':document-'.$relationship['end'];
|
||||||
}
|
}
|
||||||
|
|
||||||
$nodes = (!empty($keys)) ? $this->getRedis()->mget($keys) : [];
|
$nodes = (!empty($keys)) ? $this->getRedis()->mget($keys) : [];
|
||||||
|
|
||||||
foreach($output['temp-relations'] as $i => $relationship) {
|
foreach ($output['temp-relations'] as $i => $relationship) {
|
||||||
$node = $relationship['end'];
|
$node = $relationship['end'];
|
||||||
|
|
||||||
$node = (!empty($nodes[$i])) ? $this->parseRelations(json_decode($nodes[$i], true)) : $this->getDocument($node);
|
$node = (!empty($nodes[$i])) ? $this->parseRelations(json_decode($nodes[$i], true)) : $this->getDocument($node);
|
||||||
|
|
||||||
if(empty($node)) {
|
if (empty($node)) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($relationship['array']) {
|
if ($relationship['array']) {
|
||||||
$output[$relationship['key']][] = $node;
|
$output[$relationship['key']][] = $node;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
$output[$relationship['key']] = $node;
|
$output[$relationship['key']] = $node;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -93,60 +97,67 @@ class Redis extends Adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create Document
|
* Create Document.
|
||||||
*
|
*
|
||||||
* @param array $data
|
* @param array $data
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function createDocument(array $data = [])
|
public function createDocument(array $data = [])
|
||||||
{
|
{
|
||||||
$data = $this->adapter->createDocument($data);
|
$data = $this->adapter->createDocument($data);
|
||||||
|
|
||||||
$this->getRedis()->expire($this->getNamespace() . ':document-' . $data['$uid'], 0);
|
$this->getRedis()->expire($this->getNamespace().':document-'.$data['$uid'], 0);
|
||||||
$this->getRedis()->expire($this->getNamespace() . ':document-' . $data['$uid'], 0);
|
$this->getRedis()->expire($this->getNamespace().':document-'.$data['$uid'], 0);
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update Document
|
* Update Document.
|
||||||
*
|
*
|
||||||
* @param array $data
|
* @param array $data
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function updateDocument(array $data = [])
|
public function updateDocument(array $data = [])
|
||||||
{
|
{
|
||||||
$data = $this->adapter->updateDocument($data);
|
$data = $this->adapter->updateDocument($data);
|
||||||
|
|
||||||
$this->getRedis()->expire($this->getNamespace() . ':document-' . $data['$uid'], 0);
|
$this->getRedis()->expire($this->getNamespace().':document-'.$data['$uid'], 0);
|
||||||
$this->getRedis()->expire($this->getNamespace() . ':document-' . $data['$uid'], 0);
|
$this->getRedis()->expire($this->getNamespace().':document-'.$data['$uid'], 0);
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete Document
|
* Delete Document.
|
||||||
*
|
*
|
||||||
* @param $id
|
* @param $id
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function deleteDocument($id)
|
public function deleteDocument($id)
|
||||||
{
|
{
|
||||||
$data = $this->adapter->deleteDocument($id);
|
$data = $this->adapter->deleteDocument($id);
|
||||||
|
|
||||||
$this->getRedis()->expire($this->getNamespace() . ':document-' . $id, 0);
|
$this->getRedis()->expire($this->getNamespace().':document-'.$id, 0);
|
||||||
$this->getRedis()->expire($this->getNamespace() . ':document-' . $id, 0);
|
$this->getRedis()->expire($this->getNamespace().':document-'.$id, 0);
|
||||||
|
|
||||||
return $data;
|
return $data;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create Namespace
|
* Create Namespace.
|
||||||
*
|
*
|
||||||
* @param string $namespace
|
* @param string $namespace
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function createNamespace($namespace)
|
public function createNamespace($namespace)
|
||||||
|
@ -155,9 +166,10 @@ class Redis extends Adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete Namespace
|
* Delete Namespace.
|
||||||
*
|
*
|
||||||
* @param string $namespace
|
* @param string $namespace
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function deleteNamespace($namespace)
|
public function deleteNamespace($namespace)
|
||||||
|
@ -167,7 +179,9 @@ class Redis extends Adapter
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $options
|
* @param array $options
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function getCollection(array $options)
|
public function getCollection(array $options)
|
||||||
|
@ -175,16 +189,16 @@ class Redis extends Adapter
|
||||||
$data = $this->adapter->getCollection($options);
|
$data = $this->adapter->getCollection($options);
|
||||||
$keys = [];
|
$keys = [];
|
||||||
|
|
||||||
foreach($data as $node) {
|
foreach ($data as $node) {
|
||||||
$keys[] = $this->getNamespace() . ':document-' . $node;
|
$keys[] = $this->getNamespace().':document-'.$node;
|
||||||
}
|
}
|
||||||
|
|
||||||
$nodes = (!empty($keys)) ? $this->getRedis()->mget($keys) : [];
|
$nodes = (!empty($keys)) ? $this->getRedis()->mget($keys) : [];
|
||||||
|
|
||||||
foreach($data as $i => &$node) {
|
foreach ($data as $i => &$node) {
|
||||||
$temp = (!empty($nodes[$i])) ? $this->parseRelations(json_decode($nodes[$i], true)) : $this->getDocument($node);
|
$temp = (!empty($nodes[$i])) ? $this->parseRelations(json_decode($nodes[$i], true)) : $this->getDocument($node);
|
||||||
|
|
||||||
if(!empty($temp)) {
|
if (!empty($temp)) {
|
||||||
$node = $temp;
|
$node = $temp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -194,7 +208,9 @@ class Redis extends Adapter
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $options
|
* @param array $options
|
||||||
|
*
|
||||||
* @return int
|
* @return int
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function getCount(array $options)
|
public function getCount(array $options)
|
||||||
|
@ -203,7 +219,7 @@ class Redis extends Adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Last Modified
|
* Last Modified.
|
||||||
*
|
*
|
||||||
* Return unix timestamp of last time a node queried in current session has been changed
|
* Return unix timestamp of last time a node queried in current session has been changed
|
||||||
*
|
*
|
||||||
|
@ -211,7 +227,7 @@ class Redis extends Adapter
|
||||||
*/
|
*/
|
||||||
public function lastModified()
|
public function lastModified()
|
||||||
{
|
{
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -224,6 +240,7 @@ class Redis extends Adapter
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
|
*
|
||||||
* @return Client
|
* @return Client
|
||||||
*/
|
*/
|
||||||
protected function getRedis():Client
|
protected function getRedis():Client
|
||||||
|
@ -232,12 +249,14 @@ class Redis extends Adapter
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set Namespace
|
* Set Namespace.
|
||||||
*
|
*
|
||||||
* Set namespace to divide different scope of data sets
|
* Set namespace to divide different scope of data sets
|
||||||
*
|
*
|
||||||
* @param $namespace
|
* @param $namespace
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function setNamespace($namespace)
|
public function setNamespace($namespace)
|
||||||
|
@ -246,4 +265,4 @@ class Redis extends Adapter
|
||||||
|
|
||||||
return parent::setNamespace($namespace);
|
return parent::setNamespace($namespace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,38 +45,44 @@ class Database
|
||||||
protected $adapter;
|
protected $adapter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set Adapter
|
* Set Adapter.
|
||||||
*
|
*
|
||||||
* @param Adapter $adapter
|
* @param Adapter $adapter
|
||||||
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setAdapter(Adapter $adapter)
|
public function setAdapter(Adapter $adapter)
|
||||||
{
|
{
|
||||||
$this->adapter = $adapter;
|
$this->adapter = $adapter;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set Namespace
|
* Set Namespace.
|
||||||
*
|
*
|
||||||
* Set namespace to divide different scope of data sets
|
* Set namespace to divide different scope of data sets
|
||||||
*
|
*
|
||||||
* @param $namespace
|
* @param $namespace
|
||||||
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function setNamespace($namespace)
|
public function setNamespace($namespace)
|
||||||
{
|
{
|
||||||
$this->adapter->setNamespace($namespace);
|
$this->adapter->setNamespace($namespace);
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Namespace
|
* Get Namespace.
|
||||||
*
|
*
|
||||||
* Get namespace of current set scope
|
* Get namespace of current set scope
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function getNamespace()
|
public function getNamespace()
|
||||||
|
@ -85,9 +91,10 @@ class Database
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create Namespace
|
* Create Namespace.
|
||||||
|
*
|
||||||
|
* @param int $namespace
|
||||||
*
|
*
|
||||||
* @param int $namespace
|
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function createNamespace($namespace)
|
public function createNamespace($namespace)
|
||||||
|
@ -96,9 +103,10 @@ class Database
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete Namespace
|
* Delete Namespace.
|
||||||
|
*
|
||||||
|
* @param int $namespace
|
||||||
*
|
*
|
||||||
* @param int $namespace
|
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function deleteNamespace($namespace)
|
public function deleteNamespace($namespace)
|
||||||
|
@ -108,6 +116,7 @@ class Database
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $options
|
* @param array $options
|
||||||
|
*
|
||||||
* @return Document[]|Document
|
* @return Document[]|Document
|
||||||
*/
|
*/
|
||||||
public function getCollection(array $options)
|
public function getCollection(array $options)
|
||||||
|
@ -127,15 +136,15 @@ class Database
|
||||||
|
|
||||||
$results = $this->adapter->getCollection($options);
|
$results = $this->adapter->getCollection($options);
|
||||||
|
|
||||||
foreach($results as &$node) {
|
foreach ($results as &$node) {
|
||||||
$node = new Document($node);
|
$node = new Document($node);
|
||||||
}
|
}
|
||||||
|
|
||||||
if($options['first']) {
|
if ($options['first']) {
|
||||||
$results = reset($results);
|
$results = reset($results);
|
||||||
}
|
}
|
||||||
|
|
||||||
if($options['last']) {
|
if ($options['last']) {
|
||||||
$results = end($results);
|
$results = end($results);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -143,21 +152,21 @@ class Database
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $id
|
* @param int $id
|
||||||
* @param bool $mock is mocked data allowed?
|
* @param bool $mock is mocked data allowed?
|
||||||
|
*
|
||||||
* @return Document
|
* @return Document
|
||||||
*/
|
*/
|
||||||
public function getDocument($id, $mock = true)
|
public function getDocument($id, $mock = true)
|
||||||
{
|
{
|
||||||
if(is_null($id)) {
|
if (is_null($id)) {
|
||||||
return new Document([]);
|
return new Document([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
$document = new Document((isset($this->mocks[$id]) && $mock) ? $this->mocks[$id] : $this->adapter->getDocument($id));
|
$document = new Document((isset($this->mocks[$id]) && $mock) ? $this->mocks[$id] : $this->adapter->getDocument($id));
|
||||||
$validator = new Authorization($document, 'read');
|
$validator = new Authorization($document, 'read');
|
||||||
|
|
||||||
|
if (!$validator->isValid($document->getPermissions())) { // Check if user has read access to this document
|
||||||
if(!$validator->isValid($document->getPermissions())) { // Check if user has read access to this document
|
|
||||||
return new Document([]);
|
return new Document([]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -166,7 +175,9 @@ class Database
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $data
|
* @param array $data
|
||||||
|
*
|
||||||
* @return Document|bool
|
* @return Document|bool
|
||||||
|
*
|
||||||
* @throws AuthorizationException
|
* @throws AuthorizationException
|
||||||
* @throws StructureException
|
* @throws StructureException
|
||||||
*/
|
*/
|
||||||
|
@ -174,15 +185,15 @@ class Database
|
||||||
{
|
{
|
||||||
$document = new Document($data);
|
$document = new Document($data);
|
||||||
|
|
||||||
$validator = new Authorization($document, 'write');
|
$validator = new Authorization($document, 'write');
|
||||||
|
|
||||||
if(!$validator->isValid($document->getPermissions())) { // Check if user has write access to this document
|
if (!$validator->isValid($document->getPermissions())) { // Check if user has write access to this document
|
||||||
throw new AuthorizationException($validator->getDescription());
|
throw new AuthorizationException($validator->getDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
$validator = new Structure($this);
|
$validator = new Structure($this);
|
||||||
|
|
||||||
if(!$validator->isValid($document)) {
|
if (!$validator->isValid($document)) {
|
||||||
throw new StructureException($validator->getDescription()); // var_dump($validator->getDescription()); return false;
|
throw new StructureException($validator->getDescription()); // var_dump($validator->getDescription()); return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -191,12 +202,14 @@ class Database
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $data
|
* @param array $data
|
||||||
|
*
|
||||||
* @return Document|false
|
* @return Document|false
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function updateDocument(array $data)
|
public function updateDocument(array $data)
|
||||||
{
|
{
|
||||||
if(!isset($data['$uid'])) {
|
if (!isset($data['$uid'])) {
|
||||||
throw new Exception('Must define $uid attribute');
|
throw new Exception('Must define $uid attribute');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -206,21 +219,21 @@ class Database
|
||||||
$data['$uid'] = $document->getUid();
|
$data['$uid'] = $document->getUid();
|
||||||
$data['$collection'] = $document->getCollection();
|
$data['$collection'] = $document->getCollection();
|
||||||
|
|
||||||
$validator = new Authorization($document, 'write');
|
$validator = new Authorization($document, 'write');
|
||||||
|
|
||||||
if(!$validator->isValid($document->getPermissions())) { // Check if user has write access to this document
|
if (!$validator->isValid($document->getPermissions())) { // Check if user has write access to this document
|
||||||
throw new AuthorizationException($validator->getDescription()); // var_dump($validator->getDescription()); return false;
|
throw new AuthorizationException($validator->getDescription()); // var_dump($validator->getDescription()); return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$new = new Document($data);
|
$new = new Document($data);
|
||||||
|
|
||||||
if(!$validator->isValid($new->getPermissions())) { // Check if user has write access to this document
|
if (!$validator->isValid($new->getPermissions())) { // Check if user has write access to this document
|
||||||
throw new AuthorizationException($validator->getDescription()); // var_dump($validator->getDescription()); return false;
|
throw new AuthorizationException($validator->getDescription()); // var_dump($validator->getDescription()); return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$validator = new Structure($this);
|
$validator = new Structure($this);
|
||||||
|
|
||||||
if(!$validator->isValid($new)) { // Make sure updated structure still apply collection rules (if any)
|
if (!$validator->isValid($new)) { // Make sure updated structure still apply collection rules (if any)
|
||||||
throw new StructureException($validator->getDescription()); // var_dump($validator->getDescription()); return false;
|
throw new StructureException($validator->getDescription()); // var_dump($validator->getDescription()); return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -229,16 +242,18 @@ class Database
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $id
|
* @param int $id
|
||||||
|
*
|
||||||
* @return Document|false
|
* @return Document|false
|
||||||
|
*
|
||||||
* @throws AuthorizationException
|
* @throws AuthorizationException
|
||||||
*/
|
*/
|
||||||
public function deleteDocument($id)
|
public function deleteDocument($id)
|
||||||
{
|
{
|
||||||
$document = $this->getDocument($id);
|
$document = $this->getDocument($id);
|
||||||
|
|
||||||
$validator = new Authorization($document, 'write');
|
$validator = new Authorization($document, 'write');
|
||||||
|
|
||||||
if(!$validator->isValid($document->getPermissions())) { // Check if user has write access to this document
|
if (!$validator->isValid($document->getPermissions())) { // Check if user has write access to this document
|
||||||
throw new AuthorizationException($validator->getDescription());
|
throw new AuthorizationException($validator->getDescription());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,6 +280,7 @@ class Database
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $options
|
* @param array $options
|
||||||
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getCount(array $options)
|
public function getCount(array $options)
|
||||||
|
@ -281,31 +297,38 @@ class Database
|
||||||
/**
|
/**
|
||||||
* @param string $key
|
* @param string $key
|
||||||
* @param string $value
|
* @param string $value
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function setMock($key, $value) {
|
public function setMock($key, $value)
|
||||||
|
{
|
||||||
$this->mocks[$key] = $value;
|
$this->mocks[$key] = $value;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $mocks
|
* @param string $mocks
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function setMocks(array $mocks) {
|
public function setMocks(array $mocks)
|
||||||
|
{
|
||||||
$this->mocks = $mocks;
|
$this->mocks = $mocks;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getMocks() {
|
public function getMocks()
|
||||||
|
{
|
||||||
return $this->mocks;
|
return $this->mocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Last Modified
|
* Get Last Modified.
|
||||||
*
|
*
|
||||||
* Return unix timestamp of last time a node queried in current session has been changed
|
* Return unix timestamp of last time a node queried in current session has been changed
|
||||||
*
|
*
|
||||||
|
@ -315,4 +338,4 @@ class Database
|
||||||
{
|
{
|
||||||
return $this->adapter->lastModified();
|
return $this->adapter->lastModified();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,30 +6,30 @@ use ArrayObject;
|
||||||
|
|
||||||
class Document extends ArrayObject
|
class Document extends ArrayObject
|
||||||
{
|
{
|
||||||
const SET_TYPE_ASSIGN = 'assign';
|
const SET_TYPE_ASSIGN = 'assign';
|
||||||
const SET_TYPE_PREPEND = 'prepend';
|
const SET_TYPE_PREPEND = 'prepend';
|
||||||
const SET_TYPE_APPEND = 'append';
|
const SET_TYPE_APPEND = 'append';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct
|
* Construct.
|
||||||
*
|
*
|
||||||
* Construct a new fields object
|
* Construct a new fields object
|
||||||
*
|
*
|
||||||
* @see ArrayObject::__construct
|
* @see ArrayObject::__construct
|
||||||
* @param null $input
|
*
|
||||||
* @param int $flags
|
* @param null $input
|
||||||
|
* @param int $flags
|
||||||
* @param string $iterator_class
|
* @param string $iterator_class
|
||||||
*/
|
*/
|
||||||
public function __construct($input = null, $flags = 0, $iterator_class = "ArrayIterator")
|
public function __construct($input = null, $flags = 0, $iterator_class = 'ArrayIterator')
|
||||||
{
|
{
|
||||||
foreach($input as $key => &$value) {
|
foreach ($input as $key => &$value) {
|
||||||
if(is_array($value)) {
|
if (is_array($value)) {
|
||||||
if(isset($value['$uid']) || isset($value['$collection'])){
|
if (isset($value['$uid']) || isset($value['$collection'])) {
|
||||||
$input[$key] = new self($value);
|
$input[$key] = new self($value);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
foreach ($value as $childKey => $child) {
|
foreach ($value as $childKey => $child) {
|
||||||
if(isset($child['$uid']) || isset($child['$collection'])){
|
if (isset($child['$uid']) || isset($child['$collection'])) {
|
||||||
$value[$childKey] = new self($child);
|
$value[$childKey] = new self($child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -65,12 +65,13 @@ class Document extends ArrayObject
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Attribute
|
* Get Attribute.
|
||||||
*
|
*
|
||||||
* Method for getting a specific fields attribute. If $name is not found $default value will be returned.
|
* Method for getting a specific fields attribute. If $name is not found $default value will be returned.
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param mixed $default
|
* @param mixed $default
|
||||||
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function getAttribute($name, $default = null)
|
public function getAttribute($name, $default = null)
|
||||||
|
@ -79,8 +80,8 @@ class Document extends ArrayObject
|
||||||
|
|
||||||
$temp = &$this;
|
$temp = &$this;
|
||||||
|
|
||||||
foreach($name as $key) {
|
foreach ($name as $key) {
|
||||||
if(!isset($temp[$key])) {
|
if (!isset($temp[$key])) {
|
||||||
return $default;
|
return $default;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -91,13 +92,14 @@ class Document extends ArrayObject
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set Attribute
|
* Set Attribute.
|
||||||
*
|
*
|
||||||
* Method for setting a specific field attribute
|
* Method for setting a specific field attribute
|
||||||
*
|
*
|
||||||
* @param string $key
|
* @param string $key
|
||||||
* @param mixed $value
|
* @param mixed $value
|
||||||
* @param string $type
|
* @param string $type
|
||||||
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
public function setAttribute($key, $value, $type = self::SET_TYPE_ASSIGN)
|
public function setAttribute($key, $value, $type = self::SET_TYPE_ASSIGN)
|
||||||
|
@ -120,33 +122,33 @@ class Document extends ArrayObject
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Search
|
* Search.
|
||||||
*
|
*
|
||||||
* Get array child by key and value match
|
* Get array child by key and value match
|
||||||
*
|
*
|
||||||
* @param $key
|
* @param $key
|
||||||
* @param $value
|
* @param $value
|
||||||
* @param array|null $scope
|
* @param array|null $scope
|
||||||
|
*
|
||||||
* @return Document|Document[]|mixed|null|array
|
* @return Document|Document[]|mixed|null|array
|
||||||
*/
|
*/
|
||||||
public function search($key, $value, $scope = null)
|
public function search($key, $value, $scope = null)
|
||||||
{
|
{
|
||||||
$array = (!is_null($scope)) ? $scope : $this;
|
$array = (!is_null($scope)) ? $scope : $this;
|
||||||
|
|
||||||
if(is_array($array) || $array instanceof self) {
|
if (is_array($array) || $array instanceof self) {
|
||||||
if(isset($array[$key]) && $array[$key] == $value) {
|
if (isset($array[$key]) && $array[$key] == $value) {
|
||||||
return $array;
|
return $array;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($array as $k => $v) {
|
foreach ($array as $k => $v) {
|
||||||
if((is_array($v) || $v instanceof self) && (!empty($v))) {
|
if ((is_array($v) || $v instanceof self) && (!empty($v))) {
|
||||||
$result = $this->search($key, $value, $v);
|
$result = $this->search($key, $value, $v);
|
||||||
|
|
||||||
if(!empty($result)) {
|
if (!empty($result)) {
|
||||||
return $result;
|
return $result;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
if ($k === $key && $v === $value) {
|
if ($k === $key && $v === $value) {
|
||||||
return $array;
|
return $array;
|
||||||
}
|
}
|
||||||
|
@ -154,15 +156,15 @@ class Document extends ArrayObject
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if($array === $value) {
|
if ($array === $value) {
|
||||||
return $array;
|
return $array;
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Checks if document has data
|
* Checks if document has data.
|
||||||
*
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
|
@ -172,12 +174,13 @@ class Document extends ArrayObject
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Array Copy
|
* Get Array Copy.
|
||||||
*
|
*
|
||||||
* Outputs entity as a PHP array
|
* Outputs entity as a PHP array
|
||||||
*
|
*
|
||||||
* @param array $whitelist
|
* @param array $whitelist
|
||||||
* @param array $blacklist
|
* @param array $blacklist
|
||||||
|
*
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getArrayCopy(array $whitelist = [], array $blacklist = [])
|
public function getArrayCopy(array $whitelist = [], array $blacklist = [])
|
||||||
|
@ -187,36 +190,33 @@ class Document extends ArrayObject
|
||||||
$output = array();
|
$output = array();
|
||||||
|
|
||||||
foreach ($array as $key => &$value) {
|
foreach ($array as $key => &$value) {
|
||||||
if(!empty($whitelist) && !in_array($key, $whitelist)) { // Export only whitelisted fields
|
if (!empty($whitelist) && !in_array($key, $whitelist)) { // Export only whitelisted fields
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!empty($blacklist) && in_array($key, $blacklist)) { // Don't export blacklisted fields
|
if (!empty($blacklist) && in_array($key, $blacklist)) { // Don't export blacklisted fields
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($value instanceof self) {
|
if ($value instanceof self) {
|
||||||
$output[$key] = $value->getArrayCopy($whitelist, $blacklist);
|
$output[$key] = $value->getArrayCopy($whitelist, $blacklist);
|
||||||
}
|
} elseif (is_array($value)) {
|
||||||
elseif (is_array($value)) {
|
|
||||||
foreach ($value as $childKey => &$child) {
|
foreach ($value as $childKey => &$child) {
|
||||||
if ($child instanceof self) {
|
if ($child instanceof self) {
|
||||||
$output[$key][$childKey] = $child->getArrayCopy($whitelist, $blacklist);
|
$output[$key][$childKey] = $child->getArrayCopy($whitelist, $blacklist);
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
$output[$key][$childKey] = $child;
|
$output[$key][$childKey] = $child;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(empty($value)) {
|
if (empty($value)) {
|
||||||
$output[$key] = $value;
|
$output[$key] = $value;
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
$output[$key] = $value;
|
$output[$key] = $value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return $output;
|
return $output;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,5 +4,4 @@ namespace Database\Exception;
|
||||||
|
|
||||||
class Authorization extends \Exception
|
class Authorization extends \Exception
|
||||||
{
|
{
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -4,5 +4,4 @@ namespace Database\Exception;
|
||||||
|
|
||||||
class Structure extends \Exception
|
class Structure extends \Exception
|
||||||
{
|
{
|
||||||
|
}
|
||||||
}
|
|
||||||
|
|
|
@ -10,7 +10,7 @@ class Authorization extends Validator
|
||||||
/**
|
/**
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
static protected $roles = ['*'];
|
protected static $roles = ['*'];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var Document
|
* @var Document
|
||||||
|
@ -31,7 +31,7 @@ class Authorization extends Validator
|
||||||
* Structure constructor.
|
* Structure constructor.
|
||||||
*
|
*
|
||||||
* @param Document $document
|
* @param Document $document
|
||||||
* @param string $action
|
* @param string $action
|
||||||
*/
|
*/
|
||||||
public function __construct(Document $document, $action)
|
public function __construct(Document $document, $action)
|
||||||
{
|
{
|
||||||
|
@ -40,7 +40,7 @@ class Authorization extends Validator
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Description
|
* Get Description.
|
||||||
*
|
*
|
||||||
* Returns validator description
|
* Returns validator description
|
||||||
*
|
*
|
||||||
|
@ -52,35 +52,37 @@ class Authorization extends Validator
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is valid
|
* Is valid.
|
||||||
*
|
*
|
||||||
* Returns true if valid or false if not.
|
* Returns true if valid or false if not.
|
||||||
*
|
*
|
||||||
* @param array $permissions
|
* @param array $permissions
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isValid($permissions)
|
public function isValid($permissions)
|
||||||
{
|
{
|
||||||
if(!self::$status) {
|
if (!self::$status) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!isset($permissions[$this->action])) {
|
if (!isset($permissions[$this->action])) {
|
||||||
$this->message = 'Missing action key: "' . $this->action . '"';
|
$this->message = 'Missing action key: "'.$this->action.'"';
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$permission = null;
|
$permission = null;
|
||||||
|
|
||||||
foreach ($permissions[$this->action] as $permission) {
|
foreach ($permissions[$this->action] as $permission) {
|
||||||
$permission = str_replace(':{self}', ':' . $this->document->getUid(), $permission);
|
$permission = str_replace(':{self}', ':'.$this->document->getUid(), $permission);
|
||||||
|
|
||||||
if(in_array($permission, self::getRoles())) {
|
if (in_array($permission, self::getRoles())) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->message = 'User is missing ' . $this->action . ' for ' . $permission . ' permission. only this scope "' . json_encode(self::getRoles()) . '" is given.';
|
$this->message = 'User is missing '.$this->action.' for '.$permission.' permission. only this scope "'.json_encode(self::getRoles()).'" is given.';
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -88,7 +90,7 @@ class Authorization extends Validator
|
||||||
/**
|
/**
|
||||||
* @param string $role
|
* @param string $role
|
||||||
*/
|
*/
|
||||||
static public function setRole($role)
|
public static function setRole($role)
|
||||||
{
|
{
|
||||||
self::$roles[] = $role;
|
self::$roles[] = $role;
|
||||||
}
|
}
|
||||||
|
@ -96,7 +98,7 @@ class Authorization extends Validator
|
||||||
/**
|
/**
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
static public function getRoles()
|
public static function getRoles()
|
||||||
{
|
{
|
||||||
return self::$roles;
|
return self::$roles;
|
||||||
}
|
}
|
||||||
|
@ -104,12 +106,12 @@ class Authorization extends Validator
|
||||||
/**
|
/**
|
||||||
* @var bool
|
* @var bool
|
||||||
*/
|
*/
|
||||||
static public $status = true;
|
public static $status = true;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static public function enable()
|
public static function enable()
|
||||||
{
|
{
|
||||||
self::$status = true;
|
self::$status = true;
|
||||||
}
|
}
|
||||||
|
@ -117,8 +119,8 @@ class Authorization extends Validator
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
static public function disable()
|
public static function disable()
|
||||||
{
|
{
|
||||||
self::$status = false;
|
self::$status = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ class Collection extends Structure
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Database $database
|
* @param Database $database
|
||||||
* @param array $collections
|
* @param array $collections
|
||||||
*/
|
*/
|
||||||
public function __construct(Database $database, array $collections)
|
public function __construct(Database $database, array $collections)
|
||||||
{
|
{
|
||||||
|
@ -30,22 +30,25 @@ class Collection extends Structure
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param Document $document
|
* @param Document $document
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isValid($document)
|
public function isValid($document)
|
||||||
{
|
{
|
||||||
$document = (is_array($document)) ? new Document($document) : $document;
|
$document = (is_array($document)) ? new Document($document) : $document;
|
||||||
|
|
||||||
if(is_null($document->getCollection())) {
|
if (is_null($document->getCollection())) {
|
||||||
$this->message = 'Missing collection attribute $collection';
|
$this->message = 'Missing collection attribute $collection';
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!in_array($document->getCollection(), $this->collections)) {
|
if (!in_array($document->getCollection(), $this->collections)) {
|
||||||
$this->message = 'Collection is not allowed';
|
$this->message = 'Collection is not allowed';
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return parent::isValid($document);
|
return parent::isValid($document);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@ class Key extends Validator
|
||||||
protected $message = 'Parameter must contain only letters with no spaces or special chars and be shorter than 32 chars';
|
protected $message = 'Parameter must contain only letters with no spaces or special chars and be shorter than 32 chars';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Description
|
* Get Description.
|
||||||
*
|
*
|
||||||
* Returns validator description
|
* Returns validator description
|
||||||
*
|
*
|
||||||
|
@ -24,24 +24,24 @@ class Key extends Validator
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is valid
|
* Is valid.
|
||||||
*
|
*
|
||||||
* Returns true if valid or false if not.
|
* Returns true if valid or false if not.
|
||||||
*
|
*
|
||||||
* @param $value
|
* @param $value
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isValid($value)
|
public function isValid($value)
|
||||||
{
|
{
|
||||||
if (preg_match('/[^A-Za-z0-9\-\_]/', $value))
|
if (preg_match('/[^A-Za-z0-9\-\_]/', $value)) {
|
||||||
{
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mb_strlen($value) > 40) {
|
if (mb_strlen($value) > 40) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,7 @@ class Permissions extends Validator
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Description
|
* Get Description.
|
||||||
*
|
*
|
||||||
* Returns validator description
|
* Returns validator description
|
||||||
*
|
*
|
||||||
|
@ -40,29 +40,33 @@ class Permissions extends Validator
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is valid
|
* Is valid.
|
||||||
*
|
*
|
||||||
* Returns true if valid or false if not.
|
* Returns true if valid or false if not.
|
||||||
*
|
*
|
||||||
* @param array $value
|
* @param array $value
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isValid($value)
|
public function isValid($value)
|
||||||
{
|
{
|
||||||
if(!is_array($value) && !empty($value)) {
|
if (!is_array($value) && !empty($value)) {
|
||||||
$this->message = 'Invalid permissions data structure';
|
$this->message = 'Invalid permissions data structure';
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($value as $action => $roles) {
|
foreach ($value as $action => $roles) {
|
||||||
if(!in_array($action, ['read', 'write'])) {
|
if (!in_array($action, ['read', 'write'])) {
|
||||||
$this->message = 'Unknown action ("' . $action. '")';
|
$this->message = 'Unknown action ("'.$action.'")';
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($roles as $role) {
|
foreach ($roles as $role) {
|
||||||
if(!is_string($role)) {
|
if (!is_string($role)) {
|
||||||
$this->message = 'Permissions role must be a string';
|
$this->message = 'Permissions role must be a string';
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,4 +74,4 @@ class Permissions extends Validator
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -19,7 +19,7 @@ class Structure extends Validator
|
||||||
protected $id = null;
|
protected $id = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Basic rules to apply on all documents
|
* Basic rules to apply on all documents.
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
|
@ -93,6 +93,7 @@ class Structure extends Validator
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Structure constructor.
|
* Structure constructor.
|
||||||
|
*
|
||||||
* @param Database $database
|
* @param Database $database
|
||||||
*/
|
*/
|
||||||
public function __construct(Database $database)
|
public function __construct(Database $database)
|
||||||
|
@ -101,7 +102,7 @@ class Structure extends Validator
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Description
|
* Get Description.
|
||||||
*
|
*
|
||||||
* Returns validator description
|
* Returns validator description
|
||||||
*
|
*
|
||||||
|
@ -109,15 +110,16 @@ class Structure extends Validator
|
||||||
*/
|
*/
|
||||||
public function getDescription()
|
public function getDescription()
|
||||||
{
|
{
|
||||||
return 'Invalid document (#' . $this->id . '): ' . $this->message;
|
return 'Invalid document (#'.$this->id.'): '.$this->message;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is valid
|
* Is valid.
|
||||||
*
|
*
|
||||||
* Returns true if valid or false if not.
|
* Returns true if valid or false if not.
|
||||||
*
|
*
|
||||||
* @param Document $document
|
* @param Document $document
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isValid($document)
|
public function isValid($document)
|
||||||
|
@ -126,36 +128,39 @@ class Structure extends Validator
|
||||||
|
|
||||||
$this->id = $document->getUid();
|
$this->id = $document->getUid();
|
||||||
|
|
||||||
if(is_null($document->getCollection())) {
|
if (is_null($document->getCollection())) {
|
||||||
$this->message = 'Missing collection attribute $collection';
|
$this->message = 'Missing collection attribute $collection';
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$collection = $this->getCollection($document->getCollection());
|
$collection = $this->getCollection($document->getCollection());
|
||||||
|
|
||||||
if(is_null($collection->getUid()) || Database::SYSTEM_COLLECTION_COLLECTIONS != $collection->getCollection()) {
|
if (is_null($collection->getUid()) || Database::SYSTEM_COLLECTION_COLLECTIONS != $collection->getCollection()) {
|
||||||
$this->message = 'Collection not found';
|
$this->message = 'Collection not found';
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
$array = $document->getArrayCopy();
|
$array = $document->getArrayCopy();
|
||||||
$rules = array_merge($this->rules, $collection->getAttribute('rules', []));
|
$rules = array_merge($this->rules, $collection->getAttribute('rules', []));
|
||||||
|
|
||||||
foreach ($rules as $rule) { // Check all required keys are set
|
foreach ($rules as $rule) { // Check all required keys are set
|
||||||
if(isset($rule['key']) && !isset($array[$rule['key']])
|
if (isset($rule['key']) && !isset($array[$rule['key']])
|
||||||
&& isset($rule['required']) && true == $rule['required']) {
|
&& isset($rule['required']) && true == $rule['required']) {
|
||||||
$this->message = 'Missing required key "' . $rule['key'] . '"';
|
$this->message = 'Missing required key "'.$rule['key'].'"';
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ($array as $key => $value) {
|
foreach ($array as $key => $value) {
|
||||||
$rule = $collection->search('key', $key, $rules);
|
$rule = $collection->search('key', $key, $rules);
|
||||||
$ruleType = (isset($rule['type'])) ? $rule['type'] : '';
|
$ruleType = (isset($rule['type'])) ? $rule['type'] : '';
|
||||||
$ruleOptions = (isset($rule['options'])) ? $rule['options'] : '';
|
$ruleOptions = (isset($rule['options'])) ? $rule['options'] : '';
|
||||||
$ruleRequired = (isset($rule['required'])) ? $rule['required'] : true;
|
$ruleRequired = (isset($rule['required'])) ? $rule['required'] : true;
|
||||||
$ruleArray = (isset($rule['array'])) ? $rule['array'] : false;
|
$ruleArray = (isset($rule['array'])) ? $rule['array'] : false;
|
||||||
$validator = null;
|
$validator = null;
|
||||||
|
|
||||||
switch ($ruleType) {
|
switch ($ruleType) {
|
||||||
case 'uid':
|
case 'uid':
|
||||||
|
@ -194,42 +199,46 @@ class Structure extends Validator
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(empty($validator)) { // Error creating validator for property
|
if (empty($validator)) { // Error creating validator for property
|
||||||
$this->message = 'Unknown property "' . $key . '"' .
|
$this->message = 'Unknown property "'.$key.'"'.
|
||||||
'. Make sure to follow ' . strtolower($collection->getAttribute('name', 'unknown')) . ' collection structure';
|
'. Make sure to follow '.strtolower($collection->getAttribute('name', 'unknown')).' collection structure';
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($ruleRequired && ('' === $value || null === $value)) {
|
if ($ruleRequired && ('' === $value || null === $value)) {
|
||||||
$this->message = 'Required property "' . $key . '" has no value';
|
$this->message = 'Required property "'.$key.'" has no value';
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!$ruleRequired && empty($value)) {
|
if (!$ruleRequired && empty($value)) {
|
||||||
unset($array[$key]);
|
unset($array[$key]);
|
||||||
unset($rule);
|
unset($rule);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if($ruleArray) { // Array of values validation
|
if ($ruleArray) { // Array of values validation
|
||||||
if(!is_array($value)) {
|
if (!is_array($value)) {
|
||||||
$this->message = 'Property "' . $key . '" must be an array';
|
$this->message = 'Property "'.$key.'" must be an array';
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO add is required check here
|
// TODO add is required check here
|
||||||
|
|
||||||
foreach ($value as $node) {
|
foreach ($value as $node) {
|
||||||
if(!$validator->isValid($node)) { // Check if property is valid, if not required can also be empty
|
if (!$validator->isValid($node)) { // Check if property is valid, if not required can also be empty
|
||||||
$this->message = 'Property "' . $key . '" has invalid input. ' . $validator->getDescription();
|
$this->message = 'Property "'.$key.'" has invalid input. '.$validator->getDescription();
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else { // Single value validation
|
||||||
else { // Single value validation
|
if ((!$validator->isValid($value)) && !('' === $value && !$ruleRequired)) { // Error when value is not valid, and is not optional and empty
|
||||||
if((!$validator->isValid($value)) && !('' === $value && !$ruleRequired)) { // Error when value is not valid, and is not optional and empty
|
$this->message = 'Property "'.$key.'" has invalid input. '.$validator->getDescription();
|
||||||
$this->message = 'Property "' . $key . '" has invalid input. ' . $validator->getDescription();
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -238,9 +247,10 @@ class Structure extends Validator
|
||||||
unset($rule);
|
unset($rule);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!empty($array)) { // No fields should be left unvalidated
|
if (!empty($array)) { // No fields should be left unvalidated
|
||||||
$this->message = 'Unknown properties are not allowed (' . implode(', ', array_keys($array)) . ') for this collection' .
|
$this->message = 'Unknown properties are not allowed ('.implode(', ', array_keys($array)).') for this collection'.
|
||||||
'. Make sure to follow ' . strtolower($collection->getAttribute('name', 'unknown')) . ' collection structure';
|
'. Make sure to follow '.strtolower($collection->getAttribute('name', 'unknown')).' collection structure';
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,4 +261,4 @@ class Structure extends Validator
|
||||||
{
|
{
|
||||||
return $this->database->getDocument($uid);
|
return $this->database->getDocument($uid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use Utopia\Validator;
|
||||||
class UID extends Validator
|
class UID extends Validator
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get Description
|
* Get Description.
|
||||||
*
|
*
|
||||||
* Returns validator description
|
* Returns validator description
|
||||||
*
|
*
|
||||||
|
@ -19,19 +19,20 @@ class UID extends Validator
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is valid
|
* Is valid.
|
||||||
*
|
*
|
||||||
* Returns true if valid or false if not.
|
* Returns true if valid or false if not.
|
||||||
*
|
*
|
||||||
* @param string $value
|
* @param string $value
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isValid($value)
|
public function isValid($value)
|
||||||
{
|
{
|
||||||
if(is_numeric($value)) {
|
if (is_numeric($value)) {
|
||||||
//return false;
|
//return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ class Event
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event constructor.
|
* Event constructor.
|
||||||
|
*
|
||||||
* @param string $queue
|
* @param string $queue
|
||||||
* @param string $class
|
* @param string $class
|
||||||
*/
|
*/
|
||||||
|
@ -34,17 +35,20 @@ class Event
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $key
|
* @param string $key
|
||||||
* @param mixed $value
|
* @param mixed $value
|
||||||
|
*
|
||||||
* @return $this
|
* @return $this
|
||||||
*/
|
*/
|
||||||
public function setParam($key, $value)
|
public function setParam($key, $value)
|
||||||
{
|
{
|
||||||
$this->params[$key] = $value;
|
$this->params[$key] = $value;
|
||||||
|
|
||||||
return $this;
|
return $this;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $key
|
* @param string $key
|
||||||
|
*
|
||||||
* @return mixed|null
|
* @return mixed|null
|
||||||
*/
|
*/
|
||||||
public function getParam($key)
|
public function getParam($key)
|
||||||
|
@ -53,10 +57,10 @@ class Event
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute Event
|
* Execute Event.
|
||||||
*/
|
*/
|
||||||
public function trigger()
|
public function trigger()
|
||||||
{
|
{
|
||||||
Resque::enqueue($this->queue, $this->class, $this->params);
|
Resque::enqueue($this->queue, $this->class, $this->params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,38 +10,41 @@ class OpenSSL
|
||||||
* @param $data
|
* @param $data
|
||||||
* @param $method
|
* @param $method
|
||||||
* @param $key
|
* @param $key
|
||||||
* @param int $options
|
* @param int $options
|
||||||
* @param string $iv
|
* @param string $iv
|
||||||
* @param null $tag
|
* @param null $tag
|
||||||
* @param string $aad
|
* @param string $aad
|
||||||
* @param int $tag_length
|
* @param int $tag_length
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
static public function encrypt($data, $method, $key, $options = 0, $iv = '', &$tag = null, $aad = '', $tag_length = 16)
|
public static function encrypt($data, $method, $key, $options = 0, $iv = '', &$tag = null, $aad = '', $tag_length = 16)
|
||||||
{
|
{
|
||||||
return openssl_encrypt($data, $method, $key, $options, $iv,$tag, $aad, $tag_length);
|
return openssl_encrypt($data, $method, $key, $options, $iv, $tag, $aad, $tag_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $data
|
* @param $data
|
||||||
* @param $method
|
* @param $method
|
||||||
* @param $password
|
* @param $password
|
||||||
* @param int $options
|
* @param int $options
|
||||||
* @param string $iv
|
* @param string $iv
|
||||||
* @param string $tag
|
* @param string $tag
|
||||||
* @param string $aad
|
* @param string $aad
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
static public function decrypt($data, $method, $password, $options = 1, $iv = '', $tag = '', $aad = '')
|
public static function decrypt($data, $method, $password, $options = 1, $iv = '', $tag = '', $aad = '')
|
||||||
{
|
{
|
||||||
return openssl_decrypt($data, $method, $password, $options, $iv, $tag, $aad);
|
return openssl_decrypt($data, $method, $password, $options, $iv, $tag, $aad);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $method
|
* @param string $method
|
||||||
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
static public function cipherIVLength($method)
|
public static function cipherIVLength($method)
|
||||||
{
|
{
|
||||||
return openssl_cipher_iv_length($method);
|
return openssl_cipher_iv_length($method);
|
||||||
}
|
}
|
||||||
|
@ -49,10 +52,11 @@ class OpenSSL
|
||||||
/**
|
/**
|
||||||
* @param $length
|
* @param $length
|
||||||
* @param null $crypto_strong
|
* @param null $crypto_strong
|
||||||
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
static public function randomPseudoBytes($length, &$crypto_strong = null)
|
public static function randomPseudoBytes($length, &$crypto_strong = null)
|
||||||
{
|
{
|
||||||
return openssl_random_pseudo_bytes($length, $crypto_strong);
|
return openssl_random_pseudo_bytes($length, $crypto_strong);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,39 +15,42 @@ class Resize
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $data
|
* @param string $data
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function __construct($data)
|
public function __construct($data)
|
||||||
{
|
{
|
||||||
$this->image = new Imagick();
|
$this->image = new Imagick();
|
||||||
|
|
||||||
$this->image->readImageBlob($data);
|
$this->image->readImageBlob($data);
|
||||||
|
|
||||||
$this->width = $this->image->getImageWidth();
|
$this->width = $this->image->getImageWidth();
|
||||||
$this->height = $this->image->getImageHeight();
|
$this->height = $this->image->getImageHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $width
|
* @param int $width
|
||||||
* @param int $height
|
* @param int $height
|
||||||
|
*
|
||||||
* @return Resize
|
* @return Resize
|
||||||
|
*
|
||||||
* @throws \ImagickException
|
* @throws \ImagickException
|
||||||
*/
|
*/
|
||||||
public function crop(int $width, int $height)
|
public function crop(int $width, int $height)
|
||||||
{
|
{
|
||||||
$originalAspect = $this->width / $this->height;
|
$originalAspect = $this->width / $this->height;
|
||||||
|
|
||||||
if(empty($width)) {
|
if (empty($width)) {
|
||||||
$width = $height * $originalAspect;
|
$width = $height * $originalAspect;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(empty($height)) {
|
if (empty($height)) {
|
||||||
$height = $width / $originalAspect;
|
$height = $width / $originalAspect;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(empty($height) && empty($width)) {
|
if (empty($height) && empty($width)) {
|
||||||
$height = $this->height;
|
$height = $this->height;
|
||||||
$width = $this->width;
|
$width = $this->width;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($this->image->getImageFormat() == 'GIF') {
|
if ($this->image->getImageFormat() == 'GIF') {
|
||||||
|
@ -58,8 +61,7 @@ class Resize
|
||||||
}
|
}
|
||||||
|
|
||||||
$this->image->deconstructImages();
|
$this->image->deconstructImages();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
$this->image->cropThumbnailImage($width, $height);
|
$this->image->cropThumbnailImage($width, $height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -68,10 +70,13 @@ class Resize
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $color
|
* @param $color
|
||||||
|
*
|
||||||
* @return Resize
|
* @return Resize
|
||||||
|
*
|
||||||
* @throws \ImagickException
|
* @throws \ImagickException
|
||||||
*/
|
*/
|
||||||
public function setBackground($color) {
|
public function setBackground($color)
|
||||||
|
{
|
||||||
$this->image->setImageBackgroundColor($color);
|
$this->image->setImageBackgroundColor($color);
|
||||||
$this->image = $this->image->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN);
|
$this->image = $this->image->mergeImageLayers(Imagick::LAYERMETHOD_FLATTEN);
|
||||||
|
|
||||||
|
@ -79,13 +84,15 @@ class Resize
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Output
|
* Output.
|
||||||
*
|
*
|
||||||
* Prints manipulated image.
|
* Prints manipulated image.
|
||||||
*
|
*
|
||||||
* @param string $type
|
* @param string $type
|
||||||
* @param int $quality
|
* @param int $quality
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function output(string $type, int $quality = 75)
|
public function output(string $type, int $quality = 75)
|
||||||
|
@ -97,7 +104,9 @@ class Resize
|
||||||
* @param string $path
|
* @param string $path
|
||||||
* @param $type
|
* @param $type
|
||||||
* @param int $quality
|
* @param int $quality
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function save(string $path = null, string $type = '', int $quality = 75)
|
public function save(string $path = null, string $type = '', int $quality = 75)
|
||||||
|
@ -122,9 +131,9 @@ class Resize
|
||||||
case 'webp':
|
case 'webp':
|
||||||
//$this->image->setImageFormat('webp');
|
//$this->image->setImageFormat('webp');
|
||||||
|
|
||||||
$signature = $this->image->getImageSignature();
|
$signature = $this->image->getImageSignature();
|
||||||
$temp = '/tmp/temp-' . $signature . '.' . strtolower($this->image->getImageFormat());
|
$temp = '/tmp/temp-'.$signature.'.'.strtolower($this->image->getImageFormat());
|
||||||
$output = '/tmp/output-' . $signature . '.webp';
|
$output = '/tmp/output-'.$signature.'.webp';
|
||||||
|
|
||||||
// save temp
|
// save temp
|
||||||
$this->image->writeImages($temp, true);
|
$this->image->writeImages($temp, true);
|
||||||
|
@ -135,10 +144,9 @@ class Resize
|
||||||
$data = file_get_contents($output);
|
$data = file_get_contents($output);
|
||||||
|
|
||||||
//load webp
|
//load webp
|
||||||
if(empty($path)) {
|
if (empty($path)) {
|
||||||
return $data;
|
return $data;
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
file_put_contents($path, $data, LOCK_EX);
|
file_put_contents($path, $data, LOCK_EX);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -149,20 +157,20 @@ class Resize
|
||||||
unlink($output);
|
unlink($output);
|
||||||
unlink($temp);
|
unlink($temp);
|
||||||
|
|
||||||
return null;
|
return;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'png':
|
case 'png':
|
||||||
/* Scale quality from 0-100 to 0-9 */
|
/* Scale quality from 0-100 to 0-9 */
|
||||||
$scaleQuality = round(($quality/100) * 9);
|
$scaleQuality = round(($quality / 100) * 9);
|
||||||
|
|
||||||
/* Invert quality setting as 0 is best, not 9 */
|
/* Invert quality setting as 0 is best, not 9 */
|
||||||
$invertScaleQuality = 9 - $scaleQuality;
|
$invertScaleQuality = 9 - $scaleQuality;
|
||||||
|
|
||||||
$this->image->setImageCompressionQuality($invertScaleQuality);
|
$this->image->setImageCompressionQuality($invertScaleQuality);
|
||||||
|
|
||||||
$this->image->setImageFormat("png");
|
$this->image->setImageFormat('png');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -170,10 +178,9 @@ class Resize
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(empty($path)) {
|
if (empty($path)) {
|
||||||
return $this->image->getImagesBlob();
|
return $this->image->getImagesBlob();
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
$this->image->writeImages($path, true);
|
$this->image->writeImages($path, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,7 +189,8 @@ class Resize
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $newHeight
|
* @param int $newHeight
|
||||||
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
protected function getSizeByFixedHeight(int $newHeight):int
|
protected function getSizeByFixedHeight(int $newHeight):int
|
||||||
|
@ -194,7 +202,8 @@ class Resize
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param int $newWidth
|
* @param int $newWidth
|
||||||
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
protected function getSizeByFixedWidth(int $newWidth):int
|
protected function getSizeByFixedWidth(int $newWidth):int
|
||||||
|
@ -204,4 +213,4 @@ class Resize
|
||||||
|
|
||||||
return $newHeight;
|
return $newHeight;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,7 @@ class GZIP extends Compression
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Compress
|
* Compress.
|
||||||
*
|
*
|
||||||
* We use gzencode over gzcompress for better support of the first format among other tools.
|
* We use gzencode over gzcompress for better support of the first format among other tools.
|
||||||
* (http://stackoverflow.com/a/621987/2299554)
|
* (http://stackoverflow.com/a/621987/2299554)
|
||||||
|
@ -23,6 +23,7 @@ class GZIP extends Compression
|
||||||
* @see http://php.net/manual/en/function.gzencode.php
|
* @see http://php.net/manual/en/function.gzencode.php
|
||||||
*
|
*
|
||||||
* @param string $data
|
* @param string $data
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function compress(string $data):string
|
public function compress(string $data):string
|
||||||
|
@ -31,13 +32,14 @@ class GZIP extends Compression
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Decompress
|
* Decompress.
|
||||||
*
|
*
|
||||||
* @param string $data
|
* @param string $data
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function decompress(string $data):string
|
public function decompress(string $data):string
|
||||||
{
|
{
|
||||||
return gzdecode($data);
|
return gzdecode($data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ namespace Storage\Compression;
|
||||||
abstract class Compression
|
abstract class Compression
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Return the name of compression algorithm
|
* Return the name of compression algorithm.
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
|
@ -13,13 +13,15 @@ abstract class Compression
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $data
|
* @param $data
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
abstract public function compress(string $data);
|
abstract public function compress(string $data);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param $data
|
* @param $data
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
abstract public function decompress(string $data);
|
abstract public function decompress(string $data);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use Exception;
|
||||||
abstract class Device
|
abstract class Device
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Get Name
|
* Get Name.
|
||||||
*
|
*
|
||||||
* Get storage device name
|
* Get storage device name
|
||||||
*
|
*
|
||||||
|
@ -16,7 +16,7 @@ abstract class Device
|
||||||
abstract public function getName();
|
abstract public function getName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Description
|
* Get Description.
|
||||||
*
|
*
|
||||||
* Get storage device description and purpose.
|
* Get storage device description and purpose.
|
||||||
*
|
*
|
||||||
|
@ -25,7 +25,7 @@ abstract class Device
|
||||||
abstract public function getDescription();
|
abstract public function getDescription();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Root
|
* Get Root.
|
||||||
*
|
*
|
||||||
* Get storage device root path
|
* Get storage device root path
|
||||||
*
|
*
|
||||||
|
@ -34,42 +34,45 @@ abstract class Device
|
||||||
abstract public function getRoot();
|
abstract public function getRoot();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Path
|
* Get Path.
|
||||||
*
|
*
|
||||||
* Each device hold a complex directory structure that is being build in this method.
|
* Each device hold a complex directory structure that is being build in this method.
|
||||||
*
|
*
|
||||||
* @param $filename
|
* @param $filename
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getPath($filename)
|
public function getPath($filename)
|
||||||
{
|
{
|
||||||
return $this->getRoot() . DIRECTORY_SEPARATOR . $filename;
|
return $this->getRoot().DIRECTORY_SEPARATOR.$filename;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Upload
|
* Upload.
|
||||||
*
|
*
|
||||||
* Upload a file to desired destination in the selected disk.
|
* Upload a file to desired destination in the selected disk.
|
||||||
*
|
*
|
||||||
* @param string $target
|
* @param string $target
|
||||||
* @param string $filename
|
* @param string $filename
|
||||||
|
*
|
||||||
* @throws \Exception
|
* @throws \Exception
|
||||||
|
*
|
||||||
* @return string|bool saved destination on success or false on failures
|
* @return string|bool saved destination on success or false on failures
|
||||||
*/
|
*/
|
||||||
public function upload($target, $filename = '')
|
public function upload($target, $filename = '')
|
||||||
{
|
{
|
||||||
$filename = (empty($filename)) ? $target : $filename;
|
$filename = (empty($filename)) ? $target : $filename;
|
||||||
$filename = uniqid() . '.' . pathinfo($filename, PATHINFO_EXTENSION);
|
$filename = uniqid().'.'.pathinfo($filename, PATHINFO_EXTENSION);
|
||||||
|
|
||||||
$path = $this->getPath($filename);
|
$path = $this->getPath($filename);
|
||||||
|
|
||||||
if(!is_uploaded_file($target)) {
|
if (!is_uploaded_file($target)) {
|
||||||
throw new Exception('File is not a valid uploaded file');
|
throw new Exception('File is not a valid uploaded file');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!file_exists(dirname($path))) { // Checks if directory path to file exists
|
if (!file_exists(dirname($path))) { // Checks if directory path to file exists
|
||||||
if(!mkdir(dirname($path), 0755, true)) {
|
if (!mkdir(dirname($path), 0755, true)) {
|
||||||
throw new Exception('Can\'t create directory ' . dirname($path));
|
throw new Exception('Can\'t create directory '.dirname($path));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,9 +84,10 @@ abstract class Device
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Read file by given path
|
* Read file by given path.
|
||||||
*
|
*
|
||||||
* @param string $path
|
* @param string $path
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function read(string $path):string
|
public function read(string $path):string
|
||||||
|
@ -92,10 +96,11 @@ abstract class Device
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Write file by given path
|
* Write file by given path.
|
||||||
*
|
*
|
||||||
* @param string $path
|
* @param string $path
|
||||||
* @param string $data
|
* @param string $data
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function write(string $path, string $data):bool
|
public function write(string $path, string $data):bool
|
||||||
|
@ -104,11 +109,12 @@ abstract class Device
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete file in given path, Return true on success and false on failure
|
* Delete file in given path, Return true on success and false on failure.
|
||||||
*
|
*
|
||||||
* @see http://php.net/manual/en/function.filesize.php
|
* @see http://php.net/manual/en/function.filesize.php
|
||||||
*
|
*
|
||||||
* @param string $path
|
* @param string $path
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function delete(string $path):bool
|
public function delete(string $path):bool
|
||||||
|
@ -117,37 +123,38 @@ abstract class Device
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Delete all file and directories in given path, Return true on success and false on failure
|
* Delete all file and directories in given path, Return true on success and false on failure.
|
||||||
*
|
*
|
||||||
* @see https://paulund.co.uk/php-delete-directory-and-files-in-directory
|
* @see https://paulund.co.uk/php-delete-directory-and-files-in-directory
|
||||||
*
|
*
|
||||||
* @param string $path
|
* @param string $path
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function deleteDir($target):bool
|
public function deleteDir($target):bool
|
||||||
{
|
{
|
||||||
if (is_dir($target)) {
|
if (is_dir($target)) {
|
||||||
$files = glob($target . '*', GLOB_MARK); // GLOB_MARK adds a slash to directories returned
|
$files = glob($target.'*', GLOB_MARK); // GLOB_MARK adds a slash to directories returned
|
||||||
|
|
||||||
foreach ($files as $file) {
|
foreach ($files as $file) {
|
||||||
$this->deleteDir($file);
|
$this->deleteDir($file);
|
||||||
}
|
}
|
||||||
|
|
||||||
rmdir($target);
|
rmdir($target);
|
||||||
}
|
} elseif (is_file($target)) {
|
||||||
elseif (is_file($target)) {
|
unlink($target);
|
||||||
unlink( $target );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns given file path its size
|
* Returns given file path its size.
|
||||||
*
|
*
|
||||||
* @see http://php.net/manual/en/function.filesize.php
|
* @see http://php.net/manual/en/function.filesize.php
|
||||||
*
|
*
|
||||||
* @param $path
|
* @param $path
|
||||||
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getFileSize(string $path):int
|
public function getFileSize(string $path):int
|
||||||
|
@ -156,11 +163,12 @@ abstract class Device
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns given file path its mime type
|
* Returns given file path its mime type.
|
||||||
*
|
*
|
||||||
* @see http://php.net/manual/en/function.mime-content-type.php
|
* @see http://php.net/manual/en/function.mime-content-type.php
|
||||||
*
|
*
|
||||||
* @param $path
|
* @param $path
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getFileMimeType(string $path):string
|
public function getFileMimeType(string $path):string
|
||||||
|
@ -169,11 +177,12 @@ abstract class Device
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns given file path its MD5 hash value
|
* Returns given file path its MD5 hash value.
|
||||||
*
|
*
|
||||||
* @see http://php.net/manual/en/function.md5-file.php
|
* @see http://php.net/manual/en/function.md5-file.php
|
||||||
*
|
*
|
||||||
* @param $path
|
* @param $path
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getFileHash(string $path):string
|
public function getFileHash(string $path):string
|
||||||
|
@ -182,13 +191,14 @@ abstract class Device
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get directory size in bytes
|
* Get directory size in bytes.
|
||||||
*
|
*
|
||||||
* Return -1 on error
|
* Return -1 on error
|
||||||
*
|
*
|
||||||
* Based on http://www.jonasjohn.de/snippets/php/dir-size.htm
|
* Based on http://www.jonasjohn.de/snippets/php/dir-size.htm
|
||||||
*
|
*
|
||||||
* @param $path
|
* @param $path
|
||||||
|
*
|
||||||
* @return int
|
* @return int
|
||||||
*/
|
*/
|
||||||
public function getDirectorySize(string $path):int
|
public function getDirectorySize(string $path):int
|
||||||
|
@ -197,19 +207,21 @@ abstract class Device
|
||||||
|
|
||||||
$directory = opendir($path);
|
$directory = opendir($path);
|
||||||
|
|
||||||
if (!$directory)
|
if (!$directory) {
|
||||||
return -1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
while (($file = readdir($directory)) !== false) {
|
while (($file = readdir($directory)) !== false) {
|
||||||
// Skip file pointers
|
// Skip file pointers
|
||||||
if ($file[0] == '.') continue;
|
if ($file[0] == '.') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// Go recursive down, or add the file size
|
// Go recursive down, or add the file size
|
||||||
if (is_dir($path . $file)) {
|
if (is_dir($path.$file)) {
|
||||||
$size += $this->getDirectorySize($path . $file . DIRECTORY_SEPARATOR);
|
$size += $this->getDirectorySize($path.$file.DIRECTORY_SEPARATOR);
|
||||||
}
|
} else {
|
||||||
else {
|
$size += filesize($path.$file);
|
||||||
$size += filesize($path . $file);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -219,7 +231,7 @@ abstract class Device
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Partition Free Space
|
* Get Partition Free Space.
|
||||||
*
|
*
|
||||||
* disk_free_space — Returns available space on filesystem or disk partition
|
* disk_free_space — Returns available space on filesystem or disk partition
|
||||||
*
|
*
|
||||||
|
@ -231,7 +243,7 @@ abstract class Device
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Partition Total Space
|
* Get Partition Total Space.
|
||||||
*
|
*
|
||||||
* disk_total_space — Returns the total size of a filesystem or disk partition
|
* disk_total_space — Returns the total size of a filesystem or disk partition
|
||||||
*
|
*
|
||||||
|
@ -243,25 +255,26 @@ abstract class Device
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Human readable data size format from bytes input
|
* Human readable data size format from bytes input.
|
||||||
*
|
*
|
||||||
* As published on https://gist.github.com/liunian/9338301 (first comment)
|
* As published on https://gist.github.com/liunian/9338301 (first comment)
|
||||||
*
|
*
|
||||||
* @param int $bytes
|
* @param int $bytes
|
||||||
* @param int $decimals
|
* @param int $decimals
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function human($bytes, $decimals = 2)
|
public function human($bytes, $decimals = 2)
|
||||||
{
|
{
|
||||||
$units = array('B','kB','MB','GB','TB','PB','EB','ZB','YB');
|
$units = array('B','kB','MB','GB','TB','PB','EB','ZB','YB');
|
||||||
$step = 1024;
|
$step = 1024;
|
||||||
$i = 0;
|
$i = 0;
|
||||||
|
|
||||||
while (($bytes / $step) > 0.9) {
|
while (($bytes / $step) > 0.9) {
|
||||||
$bytes = $bytes / $step;
|
$bytes = $bytes / $step;
|
||||||
$i++;
|
++$i;
|
||||||
}
|
}
|
||||||
|
|
||||||
return round($bytes, $decimals) . $units[$i];
|
return round($bytes, $decimals).$units[$i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,7 @@ class Local extends Device
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Local constructor.
|
* Local constructor.
|
||||||
|
*
|
||||||
* @param string $root
|
* @param string $root
|
||||||
*/
|
*/
|
||||||
public function __construct($root = '')
|
public function __construct($root = '')
|
||||||
|
@ -41,21 +42,22 @@ class Local extends Device
|
||||||
*/
|
*/
|
||||||
public function getRoot()
|
public function getRoot()
|
||||||
{
|
{
|
||||||
return '/storage/uploads/' . $this->root;
|
return '/storage/uploads/'.$this->root;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $filename
|
* @param string $filename
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getPath($filename)
|
public function getPath($filename)
|
||||||
{
|
{
|
||||||
$path = '';
|
$path = '';
|
||||||
|
|
||||||
for ($i = 0; $i < 4; $i++) {
|
for ($i = 0; $i < 4; ++$i) {
|
||||||
$path = ($i < strlen($filename)) ? $path . DIRECTORY_SEPARATOR . $filename[$i] : $path . DIRECTORY_SEPARATOR . 'x';
|
$path = ($i < strlen($filename)) ? $path.DIRECTORY_SEPARATOR.$filename[$i] : $path.DIRECTORY_SEPARATOR.'x';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->getRoot() . $path . DIRECTORY_SEPARATOR . $filename;
|
return $this->getRoot().$path.DIRECTORY_SEPARATOR.$filename;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,16 +32,17 @@ class S3 extends Device
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param string $filename
|
* @param string $filename
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function getPath($filename)
|
public function getPath($filename)
|
||||||
{
|
{
|
||||||
$path = '';
|
$path = '';
|
||||||
|
|
||||||
for ($i = 0; $i < 4; $i++) {
|
for ($i = 0; $i < 4; ++$i) {
|
||||||
$path = ($i < strlen($filename)) ? $path . DIRECTORY_SEPARATOR . $filename[$i] : $path . DIRECTORY_SEPARATOR . 'x';
|
$path = ($i < strlen($filename)) ? $path.DIRECTORY_SEPARATOR.$filename[$i] : $path.DIRECTORY_SEPARATOR.'x';
|
||||||
}
|
}
|
||||||
|
|
||||||
return $this->getRoot() . $path . DIRECTORY_SEPARATOR . $filename;
|
return $this->getRoot().$path.DIRECTORY_SEPARATOR.$filename;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,60 +7,64 @@ use Exception;
|
||||||
class Storage
|
class Storage
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Devices
|
* Devices.
|
||||||
*
|
*
|
||||||
* List of all available storage devices
|
* List of all available storage devices
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
static $devices = array();
|
public static $devices = array();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add Device
|
* Add Device.
|
||||||
*
|
*
|
||||||
* Add device by name
|
* Add device by name
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
* @param Device $device
|
* @param Device $device
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
static public function addDevice($name, Device $device)
|
public static function addDevice($name, Device $device)
|
||||||
{
|
{
|
||||||
if(array_key_exists($name, self::$devices)) {
|
if (array_key_exists($name, self::$devices)) {
|
||||||
throw new Exception('The device "' . $name . '" is already listed');
|
throw new Exception('The device "'.$name.'" is already listed');
|
||||||
}
|
}
|
||||||
|
|
||||||
self::$devices[$name] = $device;
|
self::$devices[$name] = $device;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Device
|
* Get Device.
|
||||||
*
|
*
|
||||||
* Get device by name
|
* Get device by name
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
|
*
|
||||||
* @return Device
|
* @return Device
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
static public function getDevice($name)
|
public static function getDevice($name)
|
||||||
{
|
{
|
||||||
if(!array_key_exists($name, self::$devices)) {
|
if (!array_key_exists($name, self::$devices)) {
|
||||||
throw new Exception('The device "' . $name . '" is not listed');
|
throw new Exception('The device "'.$name.'" is not listed');
|
||||||
}
|
}
|
||||||
|
|
||||||
return self::$devices[$name];
|
return self::$devices[$name];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Exists
|
* Exists.
|
||||||
*
|
*
|
||||||
* Checks if given storage name is registered or not
|
* Checks if given storage name is registered or not
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
static public function exists($name)
|
public static function exists($name)
|
||||||
{
|
{
|
||||||
return (bool)array_key_exists($name, self::$devices);
|
return (bool) array_key_exists($name, self::$devices);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,18 +6,18 @@ use Utopia\Validator;
|
||||||
|
|
||||||
class File extends Validator
|
class File extends Validator
|
||||||
{
|
{
|
||||||
|
|
||||||
public function getDescription()
|
public function getDescription()
|
||||||
{
|
{
|
||||||
return 'File is not valid';
|
return 'File is not valid';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* NOT MUCH RIGHT NOW
|
* NOT MUCH RIGHT NOW.
|
||||||
*
|
*
|
||||||
* TODO think what to do here, currently only used for parameter to be present in SDKs
|
* TODO think what to do here, currently only used for parameter to be present in SDKs
|
||||||
*
|
*
|
||||||
* @param string $name
|
* @param string $name
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isValid($name)
|
public function isValid($name)
|
||||||
|
|
|
@ -6,25 +6,25 @@ use Utopia\Validator;
|
||||||
|
|
||||||
class FileName extends Validator
|
class FileName extends Validator
|
||||||
{
|
{
|
||||||
|
|
||||||
public function getDescription()
|
public function getDescription()
|
||||||
{
|
{
|
||||||
return 'Filename is not valid';
|
return 'Filename is not valid';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The file name can only contain "a-z", "A-Z", "0-9" and "-" and not empty
|
* The file name can only contain "a-z", "A-Z", "0-9" and "-" and not empty.
|
||||||
|
*
|
||||||
|
* @param string $name
|
||||||
*
|
*
|
||||||
* @param string $name
|
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isValid($name)
|
public function isValid($name)
|
||||||
{
|
{
|
||||||
if(empty($name)) {
|
if (empty($name)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(!preg_match('/^[a-zA-Z0-9.]+$/', $name)) {
|
if (!preg_match('/^[a-zA-Z0-9.]+$/', $name)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,13 +21,14 @@ class FileSize extends Validator
|
||||||
|
|
||||||
public function getDescription()
|
public function getDescription()
|
||||||
{
|
{
|
||||||
return 'File size can\'t be bigger than ' . $this->max;
|
return 'File size can\'t be bigger than '.$this->max;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Finds whether a file size is smaller than required limit
|
* Finds whether a file size is smaller than required limit.
|
||||||
|
*
|
||||||
|
* @param int $fileSize
|
||||||
*
|
*
|
||||||
* @param int $fileSize
|
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isValid($fileSize)
|
public function isValid($fileSize)
|
||||||
|
|
|
@ -8,21 +8,21 @@ use Utopia\Validator;
|
||||||
class FileType extends Validator
|
class FileType extends Validator
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* File Types Constants
|
* File Types Constants.
|
||||||
*/
|
*/
|
||||||
const FILE_TYPE_JPEG = 'jpeg';
|
const FILE_TYPE_JPEG = 'jpeg';
|
||||||
const FILE_TYPE_GIF = 'gif';
|
const FILE_TYPE_GIF = 'gif';
|
||||||
const FILE_TYPE_PNG = 'png';
|
const FILE_TYPE_PNG = 'png';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* File Type Binaries
|
* File Type Binaries.
|
||||||
*
|
*
|
||||||
* @var array
|
* @var array
|
||||||
*/
|
*/
|
||||||
protected $types = array(
|
protected $types = array(
|
||||||
self::FILE_TYPE_JPEG => "\xFF\xD8\xFF",
|
self::FILE_TYPE_JPEG => "\xFF\xD8\xFF",
|
||||||
self::FILE_TYPE_GIF => 'GIF',
|
self::FILE_TYPE_GIF => 'GIF',
|
||||||
self::FILE_TYPE_PNG => "\x89\x50\x4e\x47\x0d\x0a",
|
self::FILE_TYPE_PNG => "\x89\x50\x4e\x47\x0d\x0a",
|
||||||
);
|
);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -31,7 +31,8 @@ class FileType extends Validator
|
||||||
protected $whiteList;
|
protected $whiteList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param array $whiteList
|
* @param array $whiteList
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function __construct(array $whiteList)
|
public function __construct(array $whiteList)
|
||||||
|
@ -51,12 +52,14 @@ class FileType extends Validator
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is Valid
|
* Is Valid.
|
||||||
*
|
*
|
||||||
* Binary check to finds whether a file is of valid type
|
* Binary check to finds whether a file is of valid type
|
||||||
*
|
*
|
||||||
* @see http://stackoverflow.com/a/3313196
|
* @see http://stackoverflow.com/a/3313196
|
||||||
* @param string $path
|
*
|
||||||
|
* @param string $path
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isValid($path)
|
public function isValid($path)
|
||||||
|
|
|
@ -7,9 +7,8 @@ use Utopia\Validator;
|
||||||
|
|
||||||
class Cron extends Validator
|
class Cron extends Validator
|
||||||
{
|
{
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get Description
|
* Get Description.
|
||||||
*
|
*
|
||||||
* Returns validator description
|
* Returns validator description
|
||||||
*
|
*
|
||||||
|
@ -21,19 +20,20 @@ class Cron extends Validator
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Is valid
|
* Is valid.
|
||||||
*
|
*
|
||||||
* Returns true if valid or false if not.
|
* Returns true if valid or false if not.
|
||||||
*
|
*
|
||||||
* @param mixed $value
|
* @param mixed $value
|
||||||
|
*
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
public function isValid($value)
|
public function isValid($value)
|
||||||
{
|
{
|
||||||
if(!CronExpression::isValidExpression($value)) {
|
if (!CronExpression::isValidExpression($value)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,12 +8,13 @@ use Utopia\View;
|
||||||
class Template extends View
|
class Template extends View
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* Render
|
* Render.
|
||||||
*
|
*
|
||||||
* Render view .phtml template file if template has not been set as rendered yet using $this->setRendered(true).
|
* Render view .phtml template file if template has not been set as rendered yet using $this->setRendered(true).
|
||||||
* In case path is not readable throws Exception.
|
* In case path is not readable throws Exception.
|
||||||
*
|
*
|
||||||
* @return string
|
* @return string
|
||||||
|
*
|
||||||
* @throws Exception
|
* @throws Exception
|
||||||
*/
|
*/
|
||||||
public function render()
|
public function render()
|
||||||
|
@ -24,9 +25,8 @@ class Template extends View
|
||||||
|
|
||||||
if (is_readable($this->path)) {
|
if (is_readable($this->path)) {
|
||||||
$template = file_get_contents($this->path); // Include template file
|
$template = file_get_contents($this->path); // Include template file
|
||||||
}
|
} else {
|
||||||
else {
|
throw new Exception('"'.$this->path.'" template is not readable or not found');
|
||||||
throw new Exception('"' . $this->path . '" template is not readable or not found');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
$template = str_replace(array_keys($this->params), array_values($this->params), $template);
|
$template = str_replace(array_keys($this->params), array_values($this->params), $template);
|
||||||
|
@ -35,54 +35,57 @@ class Template extends View
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Parse URL
|
* Parse URL.
|
||||||
*
|
*
|
||||||
* Parse URL string to array
|
* Parse URL string to array
|
||||||
*
|
*
|
||||||
* @param $url
|
* @param $url
|
||||||
|
*
|
||||||
* @return mixed On seriously malformed URLs, parse_url() may return FALSE.
|
* @return mixed On seriously malformed URLs, parse_url() may return FALSE.
|
||||||
*/
|
*/
|
||||||
static public function parseURL($url)
|
public static function parseURL($url)
|
||||||
{
|
{
|
||||||
return parse_url($url);
|
return parse_url($url);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Un-Parse URL
|
* Un-Parse URL.
|
||||||
*
|
*
|
||||||
* Convert PHP array to query string
|
* Convert PHP array to query string
|
||||||
*
|
*
|
||||||
* @param $url
|
* @param $url
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
static public function unParseURL(array $url)
|
public static function unParseURL(array $url)
|
||||||
{
|
{
|
||||||
$scheme = isset($url['scheme']) ? $url['scheme'] . '://' : '';
|
$scheme = isset($url['scheme']) ? $url['scheme'].'://' : '';
|
||||||
$host = isset($url['host']) ? $url['host'] : '';
|
$host = isset($url['host']) ? $url['host'] : '';
|
||||||
$port = isset($url['port']) ? ':' . $url['port'] : '';
|
$port = isset($url['port']) ? ':'.$url['port'] : '';
|
||||||
|
|
||||||
$user = isset($url['user']) ? $url['user'] : '';
|
$user = isset($url['user']) ? $url['user'] : '';
|
||||||
$pass = isset($url['pass']) ? ':' . $url['pass'] : '';
|
$pass = isset($url['pass']) ? ':'.$url['pass'] : '';
|
||||||
$pass = ($user || $pass) ? "$pass@" : '';
|
$pass = ($user || $pass) ? "$pass@" : '';
|
||||||
|
|
||||||
$path = isset($url['path']) ? $url['path'] : '';
|
$path = isset($url['path']) ? $url['path'] : '';
|
||||||
$query = isset($url['query']) && !empty($url['query']) ? '?' . $url['query'] : '';
|
$query = isset($url['query']) && !empty($url['query']) ? '?'.$url['query'] : '';
|
||||||
|
|
||||||
$fragment = isset($url['fragment']) ? '#' . $url['fragment'] : '';
|
$fragment = isset($url['fragment']) ? '#'.$url['fragment'] : '';
|
||||||
|
|
||||||
return $scheme . $user . $pass . $host . $port . $path . $query . $fragment;
|
return $scheme.$user.$pass.$host.$port.$path.$query.$fragment;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merge Query
|
* Merge Query.
|
||||||
*
|
*
|
||||||
* Merge array of params to query string
|
* Merge array of params to query string
|
||||||
*
|
*
|
||||||
* @param $query1
|
* @param $query1
|
||||||
* @param array $query2
|
* @param array $query2
|
||||||
|
*
|
||||||
* @return string
|
* @return string
|
||||||
*/
|
*/
|
||||||
static public function mergeQuery($query1, array $query2)
|
public static function mergeQuery($query1, array $query2)
|
||||||
{
|
{
|
||||||
$parsed = [];
|
$parsed = [];
|
||||||
|
|
||||||
|
@ -92,4 +95,4 @@ class Template extends View
|
||||||
|
|
||||||
return http_build_query($parsed);
|
return http_build_query($parsed);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue