- First commit, User loading and Authentication are working

This commit is contained in:
Dave M. 2021-03-01 16:32:48 +00:00
commit 8d1a310921
15 changed files with 1274 additions and 0 deletions

26
composer.json Normal file
View File

@ -0,0 +1,26 @@
{
"name": "mcnd/ulmus-ldap",
"description": "A simple LDAP extension for Ulmus.",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Dave Mc Nicoll",
"email": "mcndave@gmail.com"
}
],
"require": {
"mcnd/ulmus": "dev-master"
},
"repositories": [
{
"type": "vcs",
"url": "https://github.com/mcNdave/ulmus.git"
}
],
"autoload": {
"psr-4": {
"Ulmus\\Ldap\\": "src/"
}
}
}

165
src/Adapter/Ldap.php Normal file
View File

@ -0,0 +1,165 @@
<?php
namespace Ulmus\Ldap\Adapter;
use Ulmus\{ Common\PdoObject, Exception\AdapterConfigurationException };
use Ulmus\Ldap\Common\LdapObject;
use function ldap_set_option, ldap_start_tls, ldap_bind, ldap_unbind, ldap_connect, ldap_close, ldap_get_entries;
class Ldap implements \Ulmus\Adapter\AdapterInterface {
public const IDENTIFIER_DN = 101;
public const IDENTIFIER_FILTER = 102;
public int $version = 3;
public bool $encrypt;
public array $hosts;
public string $baseDn;
public string $username;
public string $password;
public string $accountSuffix;
public string $pathCertCrt;
public string $pathCertKey;
public LdapObject $ldapObject;
public function __construct(
? string $host = null,
? string $baseDn = null,
? string $username = null,
? string $password = null,
? string $accountSuffix = null
) {
if ($host) {
$this->hosts = [ $host ];
}
if ($baseDn) {
$this->baseDn = $baseDn;
}
if ($username) {
$this->username = $username;
}
if ($password) {
$this->password = $password;
}
if ($accountSuffix) {
$this->accountSuffix = $accountSuffix;
}
}
public function authenticate(string $username, string $password) : bool
{
$this->ldapObject = $this->getLdapObject();
$bind = $this->ldapObject->bind($username, $password);
return $bind;
}
public function connect() : object
{
$this->ldapObject = $this->getLdapObject();
$this->bindUser();
return $this->ldapObject;
}
public function bindUser() : void
{
if ( ! $this->ldapObject->bind($this->username, $this->password) ) {
throw new \Exception("LDAP bind failed with given user $usr.");
}
}
protected function getLdapObject() : LdapObject
{
$ldapObject = new LdapObject();
$ldapObject->connect($this->hosts[0], $this->baseDn);
$ldapObject->setOptions([
\LDAP_OPT_PROTOCOL_VERSION => $this->version,
\LDAP_OPT_REFERRALS => 0,
]);
if ( isset($this->pathCertCrt) && isset($this->pathCertKey) ) {
$ldapObject->setOptions([
\LDAP_OPT_X_TLS_CERTFILE => $this->pathCertCrt,
\LDAP_OPT_X_TLS_KEYFILE => $this->pathCertKey,
], false);
$ldapObject->startTLS();
}
return $ldapObject;
}
public function buildDataSourceName() : string
{
return "";
}
public function setup(array $configuration) : void
{
$configuration = array_change_key_case($configuration, \CASE_LOWER);
if ( false === ( $this->hosts = $configuration['hosts'] ?? false ) ) {
throw new AdapterConfigurationException("Your `host` setting is missing. It is a mandatory parameter for this driver.");
}
elseif ( false === ( $this->baseDn = $configuration['base_dn'] ?? false ) ) {
throw new AdapterConfigurationException("Your `base_dn` setting is missing. The adapter won't connect without it.");
}
elseif ( false === ( $this->username = $configuration['username'] ?? false ) ) {
throw new AdapterConfigurationException("Your `username` is missing from your configuration array");
}
elseif ( false === ( $this->password = $configuration['password'] ?? false ) ) {
throw new AdapterConfigurationException("Your `password` is missing from your configuration array");
}
elseif ( false === ( $this->accountSuffix = $configuration['account_suffix'] ?? false ) ) {
throw new AdapterConfigurationException("Your `account_suffix` is missing from your configuration array");
}
/*
if ( false !== ( $configuration['app'] ?? false ) ) {
$this->app = $configuration['app'];
}
*/
}
public function escapeIdentifier(string $segment, int $type, string $ignore = "") : string
{
switch($type) {
case static::IDENTIFIER_DN:
return ldap_escape($segment, $ignore, LDAP_ESCAPE_DN);
case static::IDENTIFIER_FIELD:
case static::IDENTIFIER_FILTER:
return ldap_escape($segment, $ignore, LDAP_ESCAPE_FILTER);
default:
return ldap_escape($segment, $ignore);
}
}
public function defaultEngine(): ? string
{
return null;
}
}

174
src/Common/LdapObject.php Normal file
View File

@ -0,0 +1,174 @@
<?php
namespace Ulmus\Ldap\Common;
use function ldap_set_option, ldap_start_tls, ldap_bind, ldap_unbind, ldap_connect, ldap_close, ldap_get_entries, ldap_count_entries;
class LdapObject {
public static ? string $dump = null;
public $connection;
public $search;
public int $rowCount = 0;
public int $bufferedRows = 0;
public string $dn;
public bool $binded = false;
public function __destruct()
{
isset($this->connection) and ldap_close($this->connection);
}
public function connect(string $host, string $baseDn) : bool
{
$this->connection = ldap_connect($host);
$this->dn = $baseDn;
return $this->connection !== false;
}
public function setOptions(array $options, $useConnectionRessource = true) : void
{
foreach($options as $field => $value) {
ldap_set_option($useConnectionRessource ? $this->connection : null, $field, $value);
}
}
public function startTLS() : void
{
ldap_start_tls($this->connection);
}
public function bind(? string $dn, ? string $password) : bool
{
if ($this->binded) {
throw new \Exception("LdapObject is already binded with a user. Use the unbind() method to release it.");
}
return $this->binded = ldap_bind($this->connection, $dn, $password);
}
public function unbind() : void
{
if ($this->binded) {
$this->binded = ! ldap_unbind($this->connection);
}
}
public function select(array $filter, array $fields = [])
{
static::$dump && call_user_func_array(static::$dump, [ $sql, $parameters ]);
$this->search = ldap_search($this->connection, $this->dn, $filter['filters'], $filter['fields'], 0, $filter['limit'] ?? -1);
$this->rowCount = $this->bufferedRows = ldap_count_entries($this->connection, $this->search);
return $this;
}
public function fetch() /* : bool|array */
{
if (! $this->search ) {
throw new \Exception('Impossible to fetch from LdapObject from which select() was not called first.');
}
if ( ! $this->bufferedRows ) {
return false;
}
if ( $this->rowCount === $this->bufferedRows ) {
$result = ldap_first_entry($this->connection, $this->search);
}
else {
$result = ldap_next_entry($this->connection, $this->search);
}
if ($result) {
$this->bufferedRows--;
$dataset = [];
if ( $attributes = ldap_get_attributes($this->connection, $result) ) {
for ($i = 0; $i < $attributes['count']; $i++) {
$key = $attributes[$i];
$dataset[strtolower($key)] = $attributes[$key][0];
}
}
return $dataset;
}
return false;
}
public function rowCount() : int
{
return $this->rowCount;
}
public function fetchAll()
{
return ldap_get_entries($this->connection, $result);
}
public function closeCursor() : void {}
public function runQuery(string $sql, array $parameters = [])
{
static::$dump && call_user_func_array(static::$dump, [ $sql, $parameters ]);
try {
if (false !== ( $statement = $this->prepare($sql) )) {
return $this->execute($statement, $parameters, true);
}
}
catch (\PDOException $e) {
throw new \PdoException($e->getMessage() . " `$sql` with data:" . json_encode($parameters));
}
return null;
}
public function execute(PDOStatement $statement, array $parameters = [], bool $commit = true)
{
try {
if ( ! $this->inTransaction() ) {
$this->beginTransaction();
}
if (empty($parameters) ? $statement->execute() : $statement->execute($parameters)) {
$statement->lastInsertId = $this->lastInsertId();
if ( $commit ) {
$this->commit();
}
return $statement;
}
else {
throw new \PDOException($statement->errorCode() . " - " . json_encode($statement->errorInfo()));
}
}
catch (\PDOException $e) {
$this->rollback();
throw $e;
}
catch (\Throwable $e) {
if ( function_exists("debogueur") ) {
debogueur($statement, $parameters, $commit);
}
throw $e;
}
return null;
}
}

70
src/ConnectionAdapter.php Normal file
View File

@ -0,0 +1,70 @@
<?php
namespace Ulmus\Ldap;
use Ulmus\Adapter\AdapterInterface;
use Ulmus\Common\PdoObject;
class ConnectionAdapter extends \Ulmus\ConnectionAdapter
{
public string $name;
public array $configuration;
protected AdapterInterface $adapter;
public $connection;
public function resolveConfiguration() : void
{
$connection = $this->configuration['connections'][$this->name] ?? [];
if ( false !== ( $adapterName = $connection['adapter'] ?? false ) ) {
$this->adapter = $this->instanciateAdapter($adapterName);
}
else {
$this->adapter = new Adapter\Ldap();
}
$this->adapter->setup($connection);
}
public function getConfiguration() : array
{
return $this->configuration['connections'][$this->name];
}
/**
* Connect the adapter
* @return self
*/
public function connect() : self
{
$this->connection = $this->adapter->connect();
return $this;
}
public function connector() : object
{
return $this->connection;
}
public function adapter() : AdapterInterface
{
return $this->adapter;
}
/**
* Instanciate an adapter which interact with the data source
* @param string $name An Ulmus adapter or full class name implementing AdapterInterface
* @return AdapterInterface
*/
protected function instanciateAdapter($name) : AdapterInterface
{
$class = substr($name, 0, 2) === "\\" ? $name : "\\Ulmus\\Adapter\\$name";
return new $class();
}
}

10
src/Entity/Computer.php Normal file
View File

@ -0,0 +1,10 @@
<?php
namespace Ulmus\Ldap\Entity;
class Computer
{
}

10
src/Entity/Container.php Normal file
View File

@ -0,0 +1,10 @@
<?php
namespace Ulmus\Ldap\Entity;
class Container
{
}

View File

@ -0,0 +1,12 @@
<?php
namespace Ulmus\Ldap\Entity\Field;
class Datetime extends \Ulmus\Entity\Field\Datetime {
public function load(...$arguments)
{
return new static(substr($arguments[0], 0, 8));
}
}

130
src/Entity/User.php Normal file
View File

@ -0,0 +1,130 @@
<?php
namespace Ulmus\Ldap\Entity;
use Ulmus\Ldap\Entity\Field\{ Datetime };
class User
{
use \Ulmus\Ldap\EntityTrait;
/**
* @Id
*/
public string $samaccountname;
/**
* @Field
*/
public string $mail;
/**
* @Field
*/
public string $mailNickname;
/**
* @Field('name' => 'givenname')
*/
public string $firstname;
/**
* @Field('name' => 'sn')
*/
public string $lastname;
/**
* @Field
*/
public string $displayName;
/**
* @Field
*/
public string $name;
/**
* @Field
*/
public string $userPrincipalName;
/**
* @Field
*/
public string $description;
/**
* @Field('name' => "st")
*/
public string $state;
/**
* @Field('name' => 'physicalDeliveryOfficeName')
*/
public string $officeName;
/**
* @Field
*/
public string $company;
/**
* @Field
*/
public string $department;
/**
* @Field
*/
public string $title;
/**
* @Field
*/
public string $userAccountControl;
/**
* @Field
*/
public string $extensionAttribute1;
/**
* @Field
*/
public string $extensionAttribute2;
/**
* @Field
*/
public string $extensionAttribute3;
/**
* @Field
*/
public string $extensionAttribute4;
/**
* @Field
*/
public int $logonCount;
/**
* @Field
*/
public Datetime $lastLogonDate;
/**
* @Field('name' => 'createTimeStamp')
*/
public Datetime $createdAt;
/**
* @Field('name' => 'modifyTimeStamp')
*/
public Datetime $updatedAt;
public function __toString() : string
{
return $this->displayName;
}
}

48
src/EntityTrait.php Normal file
View File

@ -0,0 +1,48 @@
<?php
namespace Ulmus\Ldap;
use Ulmus\{ Ulmus, EventTrait, Query, Common\EntityResolver, Common\EntityField };
use Ulmus\Annotation\Classes\{ Method, Table, Collation, };
use Ulmus\Annotation\Property\{ Field, Filter, Relation, OrderBy, Where, Join, Virtual, On, WithJoin, };
use Ulmus\Annotation\Property\Field\{ Id, ForeignKey, CreatedAt, UpdatedAt, Datetime as DateTime, Date, Time, Bigint, Tinyint, Text, Mediumtext, Longtext, };
use Ulmus\Annotation\Property\Relation\{ Ignore as RelationIgnore };
trait EntityTrait {
use \Ulmus\EntityTrait;
/**
* @Ignore
*/
public static function resolveEntity() : EntityResolver
{
return Ulmus::resolveEntity(static::class);
}
/**
* @Ignore
*/
public static function repository(string $alias = Repository::DEFAULT_ALIAS) : Repository
{
return new Repository(static::class, $alias);
}
/**
* @Ignore
*/
public static function field($name, ? string $alias = null) : EntityField
{
return new EntityField(static::class, $name, $alias ?: Repository::DEFAULT_ALIAS, Ulmus::resolveEntity(static::class));
}
/**
* @Ignore
*/
public static function fields(array $fields, ? string $alias = null) : string
{
return implode(', ', array_map(function($item) use ($alias){
return static::field($item, $alias);
}, $fields));
}
}

148
src/Query/Filter.php Normal file
View File

@ -0,0 +1,148 @@
<?php
namespace Ulmus\Ldap\Query;
use Ulmus\Common\{ EntityField, Sql };
use Ulmus\Query\{ QueryBuilderInterface, Fragment };
class Filter extends Fragment {
const OPERATOR_LIKE = "LIKE";
const OPERATOR_EQUAL = "=";
const OPERATOR_NOT_EQUAL = "<>";
const CONDITION_AND = "&";
const CONDITION_OR = "|";
const CONDITION_NOT = "!";
const COMPARISON_IN = "IN";
const COMPARISON_IS = "IS";
const COMPARISON_NULL = "NULL";
public array $conditionList;
public QueryBuilderInterface $queryBuilder;
public ? Filter $parent = null;
public string $condition = self::CONDITION_AND;
public function __construct(? QueryBuilderInterface $queryBuilder, $condition = self::CONDITION_AND)
{
$this->queryBuilder = $queryBuilder;
$this->condition = $condition;
$this->parent = $queryBuilder->Filter ?? null;
}
public function add($field, $value, string $operator, string $condition, bool $not = false) : self
{
$this->conditionList[] = [
$field,
$value,
$operator ?: $this->queryBuilder->conditionOperator,
$condition,
$not
];
return $this;
}
public function render(bool $skipToken = false) : array
{
$stack = [];
foreach ($this->conditionList ?? [] as $key => $item) {
if ( $item instanceof Filter ) {
if ( $item->conditionList ?? false ) {
$stack[] = ( $key !== 0 ? "{$item->condition} " : "" ) . "(" . implode('', $item->render($skipToken)) . ")";
}
}
else {
list($field, $value, $operator, $condition, $not) = $item;
$stack[] = $latest = $this->FilterCondition($field, $value, $operator, $key !== 0 ? $condition : "", $not);
}
}
return [
'filters' => implode('', $stack)
];
}
protected function FilterCondition($field, $value, string $operator = self::OPERATOR_EQUAL, string $condition = self::CONDITION_AND, bool $not = false) {
return new class($this->queryBuilder, $field, $value, $operator, $condition, $not) {
public $value;
public bool $not = false;
public string $field;
public string $operator;
public string $condition;
public QueryBuilderInterface $queryBuilder;
protected string $content = "";
public function __construct(QueryBuilderInterface $queryBuilder, string $field, $value, string $operator, string $condition, bool $not) {
$this->queryBuilder = $queryBuilder;
$this->field = $field;
$this->value = $value;
$this->condition = $condition;
$this->operator = $operator;
$this->not = $not;
}
public function render() : string
{
$value = $this->value();
return $this->content ?: $this->content = implode("", array_filter([
"(",
$this->condition,
$this->not ? Filter::CONDITION_NOT : "",
$this->field,
$this->operator(),
$value,
")",
]));
}
protected function operator() : string
{
if ( is_array($this->value) ) {
return (in_array($this->operator, [ '!=', '<>' ]) ? Filter::CONDITION_NOT . " " : "") . Filter::COMPARISON_IN;
}
return $this->operator;
}
protected function value()
{
if ( is_array($this->value) ) {
$stack = [];
foreach($this->value as $item) {
$stack[] = $this->filterValue($item);
}
return "(" . implode(", ", $stack) . ")";
}
return $this->filterValue($this->value);
}
protected function filterValue($value)
{
if ( $value === null ) {
throw new \Exception("NULL is not an acceptable value for filter request.");
}
elseif ( is_object($value) && ( $value instanceof EntityField ) ) {
return $value->name();
}
else {
return $value;
}
}
public function __toString() : string
{
return $this->render();
}
};
}
}

22
src/Query/Limit.php Normal file
View File

@ -0,0 +1,22 @@
<?php
namespace Ulmus\Ldap\Query;
class Limit extends \Ulmus\Query\Fragment {
public int $limit = 0;
public function set($limit) : self
{
$this->limit = $limit;
return $this;
}
public function render() : array
{
return [
'limit' => $this->limit,
];
}
}

40
src/Query/Select.php Normal file
View File

@ -0,0 +1,40 @@
<?php
namespace Ulmus\Ldap\Query;
class Select extends \Ulmus\Query\Fragment {
public bool $distinct = false;
public bool $union = false;
public ? int $top = null;
protected array $fields = [];
public function set($fields) : self
{
$this->fields = is_array($fields) ? $fields : [ $fields ];
return $this;
}
public function add($fields) : self
{
if ( is_array($fields) ) {
$this->fields = array_merge($this->fields, $fields);
}
else {
$this->fields[] = $fields;
}
return $this;
}
public function render() : array
{
return [
'fields' => $this->fields
];
}
}

236
src/QueryBuilder.php Normal file
View File

@ -0,0 +1,236 @@
<?php
namespace Ulmus\Ldap;
use Ulmus;
class QueryBuilder implements Ulmus\Query\QueryBuilderInterface
{
public Query\Filter $where;
public Ulmus\Query\QueryBuilderInterface $parent;
/**
* Those are the parameters we are going to bind to PDO.
*/
public array $parameters = [];
/**
*
* Those values are to be inserted or updated
*/
public array $values = [];
public string $whereConditionOperator = Ulmus\Query\Where::CONDITION_AND;
public string $havingConditionOperator = Ulmus\Query\Where::CONDITION_AND;
protected int $parameterIndex = 0;
protected array $queryStack = [];
public function select($field) : self
{
if ( null !== ( $select = $this->getFragment(Query\Select::class) ) ) {
$select->add($field);
}
else {
$select = new Query\Select();
$select->set($field);
$this->push($select);
}
return $this;
}
public function from(string $table, ? string $alias, ? string $schema) : self
{
return $this;
}
public function update(string $table, ? string $alias = null, ? string $database = null, ? string $schema = null) : self
{
return $this;
}
public function delete() : self
{
if ( ! $this->getFragment(Ulmus\Query\Delete::class) ) {
$this->push(new Ulmus\Query\Delete());
}
return $this;
}
public function open(string $condition = Ulmus\Query\Where::CONDITION_AND) : self
{
if ( null !== ($this->where ?? null) ) {
$this->where->conditionList[] = $new = new Query\Filter($this, $condition);
$this->where = $new;
}
else {
$this->where = new Query\Filter($this, $condition);
$this->push($this->where);
$this->where->conditionList[] = $new = new Query\Filter($this, $condition);
$this->where = $new;
}
return $this;
}
public function close() : self
{
if ( null !== ($this->where ?? null) && $this->where->parent ) {
# if an enclosure was opened, and nothing done, we must remove the unused node
if ( empty($this->where->conditionList) && (count($this->where->parent->conditionList) === 1) ) {
unset($this->where->parent->conditionList);
}
$this->where = $this->where->parent;
}
return $this;
}
public function where(/* stringable*/ $field, $value, string $operator = Ulmus\Query\Where::OPERATOR_EQUAL, string $condition = Ulmus\Query\Where::CONDITION_AND, bool $not = false) : self
{
# Empty IN case
if ( [] === $value ) {
return $this;
}
if ( $this->where ?? false ) {
$where = $this->where;
}
elseif ( null === ( $where = $this->getFragment(Query\Filter::class) ) ) {
$this->where = $where = new Query\Filter($this);
$this->push($where);
}
$this->whereConditionOperator = $operator;
$where->add($field, $value, $operator, $condition, $not);
return $this;
}
public function notWhere($field, $value, string $operator = Ulmus\Query\Where::CONDITION_AND) : self
{
return $this->where($field, $value, $operator, true);
}
public function limit(int $value) : self
{
if ( null === $limit = $this->getFragment(Ulmus\Query\Limit::class) ) {
$limit = new Query\Limit();
$this->push($limit);
}
$limit->set($value);
return $this;
}
public function offset(int $value) : self
{
if ( null === $offset = $this->getFragment(Ulmus\Query\Offset::class) ) {
$offset = new Ulmus\Query\Offset();
$this->push($offset);
}
$offset->set($value);
return $this;
}
public function orderBy(string $field, ? string $direction = null) : self
{
return $this;
}
public function create(array $fieldlist, string $table, ? string $database = null, ? string $schema = null) : self
{
return $this;
}
public function push(Ulmus\Query\Fragment $queryFragment) : self
{
$this->queryStack[] = $queryFragment;
return $this;
}
public function pull(Ulmus\Query\Fragment $queryFragment) : self
{
return array_shift($this->queryStack);
}
public function render(bool $skipToken = false) : array
{
$stack = [];
foreach($this->queryStack as $fragment) {
$stack = array_merge($stack, (array) $fragment->render($skipToken));
}
return $stack;
}
public function reset() : void
{
$this->parameters = $this->values = $this->queryStack = [];
$this->whereConditionOperator = Ulmus\Query\Where::CONDITION_AND;
$this->havingConditionOperator = Ulmus\Query\Where::CONDITION_AND;
$this->parameterIndex = 0;
unset($this->where, $this->having);
}
public function getFragment(string $class, int $index = 0) : ? Ulmus\Query\Fragment
{
foreach($this->queryStack as $item) {
if ( get_class($item) === $class ) {
if ( $index-- === 0 ) {
return $item;
}
}
}
return null;
}
public function removeFragment(Ulmus\Query\Fragment $fragment) : void
{
foreach($this->queryStack as $key => $item) {
if ( $item === $fragment ) {
unset($this->queryStack[$key]);
}
}
}
public function __toString() : string
{
return $this->render();
}
public function addParameter($value, string $key = null) : string
{
if ( $this->parent ?? false ) {
return $this->parent->addParameter($value, $key);
}
if ( $key === null ) {
$key = ":p" . $this->parameterIndex++;
}
$this->parameters[$key] = $value;
return $key;
}
public function addValues(array $values) : void
{
$this->values = $values;
}
}

30
src/Repository.php Normal file
View File

@ -0,0 +1,30 @@
<?php
namespace Ulmus\Ldap;
use Ulmus\Ulmus;
use Ulmus\Annotation\Property\{ Where, Having, Relation, Join, WithJoin, Relation\Ignore as RelationIgnore };
use Ulmus\Common\EntityResolver;
class Repository extends \Ulmus\Repository
{
const DEFAULT_ALIAS = "";
public array $events = [];
public function __construct(string $entity, string $alias = self::DEFAULT_ALIAS, ConnectionAdapter $adapter = null) {
parent::__construct($entity, $alias, $adapter);
$this->queryBuilder = new QueryBuilder();
}
protected function selectSqlQuery() : self
{
if ( null === $this->queryBuilder->getFragment(Query\Select::class) ) {
$this->select(array_keys($this->entityResolver->fieldList(EntityResolver::KEY_COLUMN_NAME)));
}
return $this;
}
}

View File

@ -0,0 +1,153 @@
<?php
namespace Ulmus\Ldap\Repository;
use Ulmus\Query;
trait ConditionTrait
{
public function open(string $condition = Query\Where::CONDITION_AND) : self
{
$this->queryBuilder->open($condition);
return $this;
}
public function orOpen() : self
{
return $this->open(Query\Where::CONDITION_OR);
}
public function close() : self
{
$this->queryBuilder->close();
return $this;
}
public function where($field, $value, string $operator = Query\Where::OPERATOR_EQUAL, $condition = Query\Where::CONDITION_AND) : self
{
$this->queryBuilder->where($field, $value, $operator, $condition);
return $this;
}
public function wheres(array $fieldValues, string $operator = Query\Where::OPERATOR_EQUAL) : self
{
foreach($fieldValues as $field => $value) {
$this->where($field, $value, $operator);
}
return $this;
}
public function and($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self
{
return $this->where($field, $value, $operator);
}
public function or($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self
{
$this->queryBuilder->where($field, $value, $operator, Query\Where::CONDITION_OR);
return $this;
}
public function notWhere($field, $value, string $operator = Query\Where::OPERATOR_NOT_EQUAL) : self
{
$this->queryBuilder->where($field, $value, $operator, Query\Where::CONDITION_AND, true);
return $this;
}
public function orNot($field, $value, string $operator = Query\Where::OPERATOR_NOT_EQUAL) : self
{
$this->queryBuilder->notWhere($field, $value, $operator, Query\Where::CONDITION_OR, true);
return $this;
}
public function having($field, $value, string $operator = Query\Where::OPERATOR_EQUAL, $condition = Query\Where::CONDITION_AND) : self
{
$this->queryBuilder->having($field, $value, $operator, $condition);
return $this;
}
public function orHaving($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self
{
$this->queryBuilder->having($field, $value, $operator, Query\Where::CONDITION_OR);
return $this;
}
public function notHaving($field, $value, string $operator = Query\Where::OPERATOR_NOT_EQUAL) : self
{
$this->queryBuilder->having($field, $value, $operator, Query\Where::CONDITION_AND, true);
return $this;
}
public function orNotHaving($field, $value) : self
{
$this->queryBuilder->having($field, $value, Query\Where::OPERATOR_NOT_EQUAL, Query\Where::CONDITION_OR, true);
return $this;
}
public function in($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self
{
$this->queryBuilder->where($field, $value, $operator);
return $this;
}
public function orIn($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self
{
$this->queryBuilder->where($field, $value, $operator, Query\Where::CONDITION_OR);
return $this;
}
public function notIn($field, $value) : self
{
$this->queryBuilder->where($field, $value, Query\Where::OPERATOR_NOT_EQUAL);
return $this;
}
public function orNotIn($field, $value) : self
{
return $this->orNot($field, $value, Query\Where::OPERATOR_NOT_EQUAL, Query\Where::CONDITION_OR, true);
}
public function like($field, $value) : self
{
$this->where($field, $value, Query\Where::OPERATOR_LIKE);
return $this;
}
public function orLike($field, $value) : self
{
$this->or($field, $value, Query\Where::OPERATOR_LIKE);
return $this;
}
public function notLike($field, $value) : self
{
$this->notWhere($field, $value, Query\Where::OPERATOR_LIKE);
return $this;
}
public function likes(array $fieldValues, string $condition = Query\Where::CONDITION_AND) : self
{
foreach($fieldValues as $field => $value) {
$this->like($field, $value);
}
return $this;
}
}