diff --git a/src/Adapter/Ldap.php b/src/Adapter/Ldap.php index 2fe03f1..f6bf3d2 100644 --- a/src/Adapter/Ldap.php +++ b/src/Adapter/Ldap.php @@ -149,8 +149,8 @@ class Ldap implements \Ulmus\Adapter\AdapterInterface { case static::IDENTIFIER_DN: return ldap_escape($segment, $ignore, LDAP_ESCAPE_DN); - case static::IDENTIFIER_FIELD: case static::IDENTIFIER_FILTER: + case static::IDENTIFIER_FIELD: return ldap_escape($segment, $ignore, LDAP_ESCAPE_FILTER); default: diff --git a/src/Annotation/Classes/ObjectClass.php b/src/Annotation/Classes/ObjectClass.php new file mode 100644 index 0000000..8a57aee --- /dev/null +++ b/src/Annotation/Classes/ObjectClass.php @@ -0,0 +1,15 @@ +type = $type; + } + } +} diff --git a/src/Common/LdapObject.php b/src/Common/LdapObject.php index e882770..45c18bc 100644 --- a/src/Common/LdapObject.php +++ b/src/Common/LdapObject.php @@ -64,9 +64,9 @@ class LdapObject { public function select(array $filter, array $fields = []) { - static::$dump && call_user_func_array(static::$dump, [ $sql, $parameters ]); + static::$dump && call_user_func_array(static::$dump, [ $filter, $fields ]); - $this->search = ldap_search($this->connection, $this->dn, $filter['filters'], $filter['fields'], 0, $filter['limit'] ?? -1); + $this->search = ldap_search($this->connection, $this->dn, $filter['filters'], $filter['fields'], 0, 0); $this->rowCount = $this->bufferedRows = ldap_count_entries($this->connection, $this->search); @@ -75,18 +75,20 @@ class LdapObject { public function fetch() /* : bool|array */ { + static $result; + if (! $this->search ) { throw new \Exception('Impossible to fetch from LdapObject from which select() was not called first.'); } if ( ! $this->bufferedRows ) { - return false; + return $result = false; } if ( $this->rowCount === $this->bufferedRows ) { $result = ldap_first_entry($this->connection, $this->search); } else { - $result = ldap_next_entry($this->connection, $this->search); + $result = ldap_next_entry($this->connection, $result); } if ($result) { @@ -119,56 +121,4 @@ class LdapObject { } 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; - } } diff --git a/src/ConnectionAdapter.php b/src/ConnectionAdapter.php index 6d5f234..0bab431 100644 --- a/src/ConnectionAdapter.php +++ b/src/ConnectionAdapter.php @@ -14,7 +14,7 @@ class ConnectionAdapter extends \Ulmus\ConnectionAdapter protected AdapterInterface $adapter; - public $connection; + private $connection; public function resolveConfiguration() : void { diff --git a/src/Entity/Container.php b/src/Entity/Container.php deleted file mode 100644 index c2e088f..0000000 --- a/src/Entity/Container.php +++ /dev/null @@ -1,10 +0,0 @@ - "st") + */ + public string $state; + + /** + * @Field('name' => 'physicalDeliveryOfficeName') + */ + public string $officeName; + + /** + * @Field('name' => 'postalAddress') + */ + public string $address; + + /** + * @Field + */ + public string $postalCode; + + /** + * @Field + */ + public string $telephoneNumber; + + public function __toString() : string + { + return $this->ou; + } +} \ No newline at end of file diff --git a/src/Entity/User.php b/src/Entity/User.php index c6cdabc..1037d47 100644 --- a/src/Entity/User.php +++ b/src/Entity/User.php @@ -4,6 +4,9 @@ namespace Ulmus\Ldap\Entity; use Ulmus\Ldap\Entity\Field\{ Datetime }; +/** + * @ObjectClass('user') + */ class User { use \Ulmus\Ldap\EntityTrait; @@ -125,6 +128,6 @@ class User public function __toString() : string { - return $this->displayName; + return implode(' ', array_filter([ $this->firstname ?? "", $this->lastname ?? "" ])) ?: $this->displayName; } } \ No newline at end of file diff --git a/src/EntityTrait.php b/src/EntityTrait.php index 15c8083..88f50e5 100644 --- a/src/EntityTrait.php +++ b/src/EntityTrait.php @@ -4,41 +4,26 @@ 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 }; +use Ulmus\Ldap\Annotation\Classes\{ ObjectClass, }; 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){ diff --git a/src/Query/Filter.php b/src/Query/Filter.php index b752dc5..d0470e6 100644 --- a/src/Query/Filter.php +++ b/src/Query/Filter.php @@ -31,7 +31,7 @@ class Filter extends Fragment { $this->condition = $condition; $this->parent = $queryBuilder->Filter ?? null; } - + public function add($field, $value, string $operator, string $condition, bool $not = false) : self { $this->conditionList[] = [ @@ -61,8 +61,10 @@ class Filter extends Fragment { } } + $render = implode('', $stack); + return [ - 'filters' => implode('', $stack) + 'filters' => count($stack) > 1 ? $latest->applyOperator($render) : $render ]; } @@ -91,24 +93,22 @@ class Filter extends Fragment { { $value = $this->value(); - return $this->content ?: $this->content = implode("", array_filter([ - "(", - $this->condition, - $this->not ? Filter::CONDITION_NOT : "", + $return = $this->content ?: $this->content = implode("", array_filter([ $this->field, $this->operator(), - $value, - ")", + $this->operator === Filter::OPERATOR_LIKE ? "*{$this->value}*" : $value, ])); + + return $this->applyOperator($return, ""); } protected function operator() : string { - if ( is_array($this->value) ) { - return (in_array($this->operator, [ '!=', '<>' ]) ? Filter::CONDITION_NOT . " " : "") . Filter::COMPARISON_IN; - } + return $this->operator === Filter::OPERATOR_LIKE ? "=" : $this->operator; + } - return $this->operator; + public function applyOperator(string $content, string $operator = Filter::CONDITION_AND) { + return "($operator$content)"; } protected function value() diff --git a/src/Repository.php b/src/Repository.php index 8971229..7089ba3 100644 --- a/src/Repository.php +++ b/src/Repository.php @@ -2,12 +2,15 @@ namespace Ulmus\Ldap; -use Ulmus\Ulmus; +use Ulmus\Ldap\Annotation\Classes\ObjectClass; +use Ulmus\{EntityCollection, Ulmus, SearchRequest, Query}; use Ulmus\Annotation\Property\{ Where, Having, Relation, Join, WithJoin, Relation\Ignore as RelationIgnore }; use Ulmus\Common\EntityResolver; class Repository extends \Ulmus\Repository { + use Repository\ConditionTrait; + const DEFAULT_ALIAS = ""; public array $events = []; @@ -17,14 +20,45 @@ class Repository extends \Ulmus\Repository $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))); } - + + if ( null !== $objectClass = $this->entityResolver->getAnnotationFromClassname( ObjectClass::class ) ) { + $this->where('objectclass', $objectClass->type); + } + return $this; } + public function escapeValue(string $identifier) : string + { + return $this->adapter->adapter()->escapeIdentifier($identifier, Adapter\Ldap::IDENTIFIER_FILTER); + } + + public function filterServerRequest(SearchRequest\SearchRequestInterface $searchRequest, bool $count = true) : self + { + if ($count) { + $this->eventRegister(new class($searchRequest) implements \Ulmus\Event\Repository\CollectionFromQueryInterface { + + protected SearchRequest\SearchRequestInterface $searchRequest; + + public function __construct(SearchRequest\SearchRequestInterface $searchRequest) { + $this->searchRequest = $searchRequest; + } + + public function execute(EntityCollection $collection) : EntityCollection + { + $this->searchRequest->count = $collection->count(); + + return $collection; + } + }); + } + + return parent::filterServerRequest($searchRequest, false); + } } \ No newline at end of file diff --git a/src/Repository/ConditionTrait.php b/src/Repository/ConditionTrait.php index 7f2fc7c..1e83ed4 100644 --- a/src/Repository/ConditionTrait.php +++ b/src/Repository/ConditionTrait.php @@ -4,35 +4,20 @@ namespace Ulmus\Ldap\Repository; use Ulmus\Query; +use Ulmus\Repository; + +use Ulmus\Ldap\Query\Filter; + trait ConditionTrait { - public function open(string $condition = Query\Where::CONDITION_AND) : self + public function where($field, $value, string $operator = Query\Where::OPERATOR_EQUAL, $condition = Query\Where::CONDITION_AND) : Repository { - $this->queryBuilder->open($condition); - + $this->queryBuilder->where($this->escapeField($field), $this->escapeValue($value), $operator, $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 + public function wheres(array $fieldValues, string $operator = Query\Where::OPERATOR_EQUAL) : Repository { foreach($fieldValues as $field => $value) { $this->where($field, $value, $operator); @@ -41,108 +26,108 @@ trait ConditionTrait return $this; } - public function and($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self + public function and($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : Repository { return $this->where($field, $value, $operator); } - public function or($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self + public function or($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : Repository { - $this->queryBuilder->where($field, $value, $operator, Query\Where::CONDITION_OR); + $this->queryBuilder->where($this->escapeField($field), $this->escapeValue($value), $operator, Query\Where::CONDITION_OR); return $this; } - public function notWhere($field, $value, string $operator = Query\Where::OPERATOR_NOT_EQUAL) : self + public function notWhere($field, $value, string $operator = Query\Where::OPERATOR_NOT_EQUAL) : Repository { - $this->queryBuilder->where($field, $value, $operator, Query\Where::CONDITION_AND, true); + $this->queryBuilder->where($this->escapeField($field), $this->escapeValue($value), $operator, Query\Where::CONDITION_AND, true); return $this; } - public function orNot($field, $value, string $operator = Query\Where::OPERATOR_NOT_EQUAL) : self + public function orNot($field, $value, string $operator = Query\Where::OPERATOR_NOT_EQUAL) : Repository { - $this->queryBuilder->notWhere($field, $value, $operator, Query\Where::CONDITION_OR, true); + $this->queryBuilder->notWhere($this->escapeField($field), $this->escapeValue($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) : Repository + { + $this->where($field, $value, $operator, $condition); return $this; } - public function having($field, $value, string $operator = Query\Where::OPERATOR_EQUAL, $condition = Query\Where::CONDITION_AND) : self + public function orHaving($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : Repository { - $this->queryBuilder->having($field, $value, $operator, $condition); + $this->orWhere($field, $value, $operator, Query\Where::CONDITION_OR); return $this; } - public function orHaving($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self + public function notHaving($field, $value, string $operator = Query\Where::OPERATOR_NOT_EQUAL) : Repository { - $this->queryBuilder->having($field, $value, $operator, Query\Where::CONDITION_OR); + $this->queryBuilder->where($this->escapeField($field), $this->escapeValue($value), $operator, Query\Where::CONDITION_AND, true); return $this; } - public function notHaving($field, $value, string $operator = Query\Where::OPERATOR_NOT_EQUAL) : self + public function orNotHaving($field, $value) : Repository { - $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); + $this->queryBuilder->where($this->escapeField($field), $this->escapeValue($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 + public function in($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : Repository { - $this->queryBuilder->where($field, $value, $operator); +// $this->queryBuilder->where($field, $value, $operator); return $this; } - public function orIn($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : self + public function orIn($field, $value, string $operator = Query\Where::OPERATOR_EQUAL) : Repository { - $this->queryBuilder->where($field, $value, $operator, Query\Where::CONDITION_OR); +// $this->queryBuilder->where($field, $value, $operator, Query\Where::CONDITION_OR); return $this; } - public function notIn($field, $value) : self + public function notIn($field, $value) : Repository { - $this->queryBuilder->where($field, $value, Query\Where::OPERATOR_NOT_EQUAL); +// $this->queryBuilder->where($field, $value, Query\Where::OPERATOR_NOT_EQUAL); return $this; } - public function orNotIn($field, $value) : self + public function orNotIn($field, $value) : Repository { - return $this->orNot($field, $value, Query\Where::OPERATOR_NOT_EQUAL, Query\Where::CONDITION_OR, true); +// return $this->orNot($field, $value, Query\Where::OPERATOR_NOT_EQUAL, Query\Where::CONDITION_OR, true); } - public function like($field, $value) : self + public function like($field, $value) : Repository { - $this->where($field, $value, Query\Where::OPERATOR_LIKE); + $this->where($field, $value, Filter::OPERATOR_LIKE); return $this; } - public function orLike($field, $value) : self + public function orLike($field, $value) : Repository { - $this->or($field, $value, Query\Where::OPERATOR_LIKE); + $this->or($field, $value, Filter::OPERATOR_LIKE); return $this; } - public function notLike($field, $value) : self + public function notLike($field, $value) : Repository { - $this->notWhere($field, $value, Query\Where::OPERATOR_LIKE); + $this->notWhere($field, $value, Filter::OPERATOR_LIKE); return $this; } - public function likes(array $fieldValues, string $condition = Query\Where::CONDITION_AND) : self + public function likes(array $fieldValues, string $condition = Query\Where::CONDITION_AND) : Repository { foreach($fieldValues as $field => $value) { $this->like($field, $value);