public function getGroups(array $fields = ['*'], $recursive = false, array $visited = [])
    {
        if (! in_array($this->schema->memberOf(), $fields)) {
            // We want to make sure that we always select the memberof
            // field in case developers want recursive members.
            $fields = array_merge($fields, [$this->schema->memberOf()]);
        }

        $groups = $this->getGroupsByNames($this->getMemberOf(), $fields);

        // We need to check if we're working with a User model. Only users
        // contain a primary group. If we are, we'll merge the users
        // primary group into the resulting collection.
        if ($this instanceof User && $primary = $this->getPrimaryGroup()) {
            $groups->push($primary);
        }

        // If recursive results are requested, we'll ask each group
        // for their groups, and merge the resulting collection.
        if ($recursive) {
            /** @var Group $group */
            foreach ($groups as $group) {
                // We need to validate that we haven't already queried
                // for this group's members so we don't allow
                // infinite recursion in case of circular
                // group dependencies in LDAP.
                if (! in_array($group->getDn(), $visited)) {
                    $visited[] = $group->getDn();

                    $members = $group->getGroups($fields, $recursive, $visited);

                    /** @var Group $member */
                    foreach ($members as $member) {
                        $visited[] = $member->getDn();
                    }

                    $groups = $groups->merge($members);
                }
            }
        }

        return $groups;
    }