blob: 7a89457c1149d2a071ccfdd29cfe37c0cf317b3e [file] [log] [blame]
<?php
namespace Adldap\Models;
use Adldap\Utilities;
use InvalidArgumentException;
/**
* Class Group.
*
* Represents an LDAP group (security / distribution).
*/
class Group extends Entry
{
use Concerns\HasMemberOf;
use Concerns\HasDescription;
/**
* Returns all users apart of the current group.
*
* @link https://msdn.microsoft.com/en-us/library/ms677097(v=vs.85).aspx
*
* @return \Adldap\Query\Collection
*/
public function getMembers()
{
$members = $this->getMembersFromAttribute($this->schema->member());
if (count($members) === 0) {
$members = $this->getPaginatedMembers();
}
return $this->newCollection($members);
}
/**
* Returns the group's member names only.
*
* @return array
*/
public function getMemberNames()
{
$members = [];
$dns = $this->getAttribute($this->schema->member()) ?: [];
foreach ($dns as $dn) {
$exploded = Utilities::explodeDn($dn);
if (array_key_exists(0, $exploded)) {
$members[] = $exploded[0];
}
}
return $members;
}
/**
* Sets the groups members using an array of user DNs.
*
* @param array $entries
*
* @return $this
*/
public function setMembers(array $entries)
{
return $this->setAttribute($this->schema->member(), $entries);
}
/**
* Adds multiple entries to the current group.
*
* @param array $members
*
* @return bool
*/
public function addMembers(array $members)
{
$members = array_map(function ($member) {
return $member instanceof Model
? $member->getDn()
: $member;
}, $members);
$mod = $this->newBatchModification(
$this->schema->member(),
LDAP_MODIFY_BATCH_ADD,
$members
);
return $this->addModification($mod)->save();
}
/**
* Adds an entry to the current group.
*
* @param string|Entry $member
*
* @throws InvalidArgumentException When the given entry is empty or contains no distinguished name.
*
* @return bool
*/
public function addMember($member)
{
$member = ($member instanceof Model ? $member->getDn() : $member);
if (is_null($member)) {
throw new InvalidArgumentException(
'Cannot add member to group. The members distinguished name cannot be null.'
);
}
$mod = $this->newBatchModification(
$this->schema->member(),
LDAP_MODIFY_BATCH_ADD,
[$member]
);
return $this->addModification($mod)->save();
}
/**
* Removes an entry from the current group.
*
* @param string|Entry $member
*
* @throws InvalidArgumentException
*
* @return bool
*/
public function removeMember($member)
{
$member = ($member instanceof Model ? $member->getDn() : $member);
if (is_null($member)) {
throw new InvalidArgumentException(
'Cannot remove member to group. The members distinguished name cannot be null.'
);
}
$mod = $this->newBatchModification(
$this->schema->member(),
LDAP_MODIFY_BATCH_REMOVE,
[$member]
);
return $this->addModification($mod)->save();
}
/**
* Removes all members from the current group.
*
* @return bool
*/
public function removeMembers()
{
$mod = $this->newBatchModification(
$this->schema->member(),
LDAP_MODIFY_BATCH_REMOVE_ALL
);
return $this->addModification($mod)->save();
}
/**
* Returns the group type integer.
*
* @link https://msdn.microsoft.com/en-us/library/ms675935(v=vs.85).aspx
*
* @return string
*/
public function getGroupType()
{
return $this->getFirstAttribute($this->schema->groupType());
}
/**
* Retrieves group members by the specified model attribute.
*
* @param $attribute
*
* @return array
*/
protected function getMembersFromAttribute($attribute)
{
$members = [];
$entries = $this->getAttribute($attribute) ?: [];
$query = $this->query->newInstance();
// Retrieving the member identifier to allow
// compatibility with LDAP variants.
$identifier = $this->schema->memberIdentifier();
foreach ($entries as $entry) {
// If our identifier is a distinguished name, then we need to
// use an alternate query method, as we can't locate records
// by distinguished names using an LDAP filter.
if ($identifier == 'dn' || $identifier == 'distinguishedname') {
$member = $query->findByDn($entry);
} else {
// We'll ensure we clear our filters when retrieving each member,
// so we can continue fetching the next one in line.
$member = $query->clearFilters()->findBy($identifier, $entry);
}
// We'll double check that we've received a model from
// our query before adding it into our results.
if ($member instanceof Model) {
$members[] = $member;
}
}
return $members;
}
/**
* Retrieves members that are contained in a member range.
*
* @return array
*/
protected function getPaginatedMembers()
{
$members = [];
$keys = array_keys($this->attributes);
// We need to filter out the model attributes so
// we only retrieve the member range.
$attributes = array_values(array_filter($keys, function ($key) {
return strpos($key, 'member;range') !== false;
}));
// We'll grab the member range key so we can run a
// regex on it to determine the range.
$key = reset($attributes);
preg_match_all(
'/member;range\=([0-9]{1,4})-([0-9*]{1,4})/',
$key,
$matches
);
if ($key && count($matches) == 3) {
// Retrieve the ending range number.
$to = $matches[2][0];
// Retrieve the current groups members from the
// current range string (ex. 'member;0-50').
$members = $this->getMembersFromAttribute($key);
// If the query already included all member results (indicated
// by the '*'), then we can return here. Otherwise we need
// to continue on and retrieve the rest.
if ($to === '*') {
return $members;
}
// Determine the amount of members we're requesting per query.
$range = $to - $matches[1][0];
// Set our starting range to our last end range plus one.
$from = $to + 1;
// We'll determine the new end range by adding the
// total range to our new starting range.
$to = $from + $range;
// We'll need to query for the current model again but with
// a new range to retrieve the other members.
/** @var Group $group */
$group = $this->query->newInstance()->findByDn(
$this->getDn(),
[$this->query->getSchema()->memberRange($from, $to)]
);
// Finally, we'll merge our current members
// with the newly returned members.
$members = array_merge(
$members,
$group->getMembers()->toArray()
);
}
return $members;
}
}