Since it's such a different case than the other two types,
hasAndBelongsToMany gets its own method.

@param Garp_Util_Configuration $options
@return bool Success
10819
protected static function _relateHasAndBelongsToMany($options) {
        $modelA = $options['modelA'];
        $modelB = $options['modelB'];
        $keyA   = $options['keyA'];
        $keyB   = $options['keyB'];
        $ruleA  = $options['ruleA'];
        $ruleB  = $options['ruleB'];
        $bindingModel = !$options['bindingModel'] ? $modelA->getBindingModel($modelB) :
            $options['bindingModel'];

        /**
         * Warning: assumptions are made!
         * - at this point, we assume the bindingModel has no relationships
         *   to models other than modelA and modelB (so we don't need a rule or anything
         *   to find the right reference in the referenceMap)
         * - also, we assume the references can be found from the bindingModel. There will be
         *   no trying nor catching, if the reference is not here, we just crash the heck out of it.
         */
        $referenceA = $bindingModel->getReference(get_class($modelA), $ruleA);
        $referenceB = $bindingModel->getReference(get_class($modelB), $ruleB);

        // The only place where extraFields is used: to fill fields other than the primary key
        // references in the binding row
        $bindingRow = $bindingModel->createRow($options['extraFields']);
        self::_addForeignKeysToRow($bindingRow, $referenceA, $keyA);
        self::_addForeignKeysToRow($bindingRow, $referenceB, $keyB);
        $success = $bindingRow->save();

        // Homophyllic relations can be saved bidirectionally
        if ($options['bidirectional'] && $modelA->getName() == $modelB->getName()) {
            $bidirectionalRow = $bindingModel->createRow($options['extraFields']);
            self::_addForeignKeysToRow($bidirectionalRow, $referenceA, $keyB);
            self::_addForeignKeysToRow($bidirectionalRow, $referenceB, $keyA);
            $success = $success && $bidirectionalRow->save();
        }

        return $success;
    }
1214972
public function set_option($options = array()) {
        global $DB;

        if (!empty($options['name'])) {
            $r = new stdClass();
            $r->id   = $this->id;
            $r->name = $options['name'];
            $DB->update_record('repository_instances', $r);
            unset($options['name']);
        }
        foreach ($options as $name=>$value) {
            if ($id = $DB->get_field('repository_instance_config', 'id', array('name'=>$name, 'instanceid'=>$this->id))) {
                $DB->set_field('repository_instance_config', 'value', $value, array('id'=>$id));
            } else {
                $config = new stdClass();
                $config->instanceid = $this->id;
                $config->name   = $name;
                $config->value  = $value;
                $DB->insert_record('repository_instance_config', $config);
            }
        }
        cache::make('core', 'repositories')->purge();
        return true;
    }
1248891
public function getPk($options = '')
    {
        if (!empty($this->pk)) {
            $pk = $this->pk;
        } else {
            $pk = $this->getTableInfo(is_array($options) ? $options['table'] : $options, 'pk');
        }
        return $pk;
    }
829869
public function saveIfExistsOrFail(array $options = []): bool
    {
        if ($this->exists === false) {
            return false;
        }

        return $this->saveOrFail($options);
    }
337950
public function save( array $options = [] )
    {
        if( $this->exists )
        {
            if( count( $this->getDirty() ) > 0 )
            {
                // If $this->exists and dirty, parent::save() has to return true. If not,
                // an error has occurred. Therefore we shouldn't save the translations.
                if( parent::save( $options ) )
                {
                    return $this->saveTranslations();
                }

                return false;
            }
            else
            {
                // If $this->exists and not dirty, parent::save() skips saving and returns
                // false. So we have to save the translations
                $saved = $this->saveTranslations();

                if( $saved )
                {
                    $this->fireModelEvent( 'saved', false );
                    $this->fireModelEvent( 'updated', false );
                }

                return $saved;
            }
        }
        elseif( parent::save( $options ) )
        {
            // We save the translations only if the instance is saved in the database.
            return $this->saveTranslations();
        }

        return false;
    }
285922
public function save($options = array())
    {

        if ($this->isEmbed()) {
            return false;
        }

        $this->processReferencesChanged();
        $this->processEmbedsChanged();

        /* if no changes then do nothing */

        if ($this->_exist && empty($this->dirtyData) && empty($this->unsetData)) return true;

        $this->__preSave();

        if ($this->_exist) {
            $this->__preUpdate();
            $updateQuery = array();

            if (!empty($this->dirtyData)) {
                $updateQuery['$set'] = self::mapFields($this->dirtyData);
            };

            if (!empty($this->unsetData)) {
                $updateQuery['$unset'] = self::mapFields($this->unsetData);
            }

            $success = $this->_connection->update($this->collectionName(), array('_id' => $this->getId()), $updateQuery, $options);
            $this->__postUpdate();

        } else {
            $this->__preInsert();
            $data = self::mapFields($this->cleanData);
            $insert = $this->_connection->insert($this->collectionName(), $data, $options);
            $success = !is_null($this->cleanData['_id'] = $insert['_id']);
            if ($success) {
                $this->_exist = true ;
                $this->__postInsert();
            }

        }

        $this->dirtyData = array();
        $this->unsetData = array();
        $this->__postSave();

        return $success;

    }
1102321
public function setOptions($options)
	{
	    if (!is_array($options) && !$options instanceof Traversable) {
	        throw new \InvalidArgumentException(sprintf(
                'Expected an array or Traversable; received "%s"',
                (is_object($options) ? get_class($options) : gettype($options))
	        ));
	    }

	    foreach ($options as $key => $value){

	        $key = strtolower($key);

	        if($key == 'loader'){
	            $this->setLoader($value);
	        }
	    }

	    return $this;
	}
972874
public function delete($options = [])
    {
        if (is_null($key = $this->getKeyName())) {
            throw new Exception('No primary key defined on model.');
        }

        // If the model doesn't exist, there is nothing to delete so we'll just return
        // immediately and not do anything else. Otherwise, we will continue with a
        // deletion process on the model, firing the proper events, and so forth.
        if (! $this->exists) {
            return;
        }

        if ($this->fireModelEvent('deleting') === false) {
            return false;
        }

        // Here, we'll touch the owning models, verifying these timestamps get updated
        // for the models. This will allow any caching to get broken on the parents
        // by the timestamp. Then we will go ahead and delete the model instance.
        $this->touchOwners();

        static::$client::delete($this->$key, $options, $this->attributes);

        $this->exists = false;

        // Once the model has been deleted, we will fire off the deleted event so that
        // the developers may hook into post-delete operations. We will then return
        // a boolean true as the delete is presumably successful on the database.
        $this->fireModelEvent('deleted', false);

        return true;
    }
1287655
public function setOptions($options, $group = null)
    {
        if ($group) {
            $options = [$group => $options];
        }

        $this->handleOptions(null, $options);

        return $this;
    }
818605
public function handle_options($options = null)
    {
        $this->opt = new pakeGetopt(self::$OPTIONS);
        $this->opt->parse($options);
        foreach ($this->opt->get_options() as $opt => $value) {
            $this->do_option($opt, $value);
        }
    }
82004
public function addOptions($options)
    {
        foreach ($options as $key => $value) {
            $this->addOption($key, $value);
        }

        return $this;
    }
117494
public function setCommandOptions(array $options)
    {
        foreach ($options as $name => $option) {
            if ((!$option instanceof Parameter\Option)) {
                throw new \Parable\Console\Exception(
                    "Options must be instances of Parameter\\Option. {$name} is not."
                );
            }
            $this->commandOptions[$option->getName()] = $option;
        }
        return $this;
    }
314097
protected function optionsApplyToControllerMethod(array $options)
    {
        if (empty($options)) {
            return true;
        } elseif (isset($options['only']) && in_array($this->controllerMethod,
                $this->explodeOnPipes($options['only']))) {
            return true;
        } elseif (isset($options['except'])) {
            return ! in_array($this->controllerMethod, $this->explodeOnPipes($options['except']));
        } elseif (in_array($this->controllerMethod, $this->explodeOnPipes($options))) {
            return true;
        }

        return false;
    }
172203
public function requiredOptions($options = [])
    {
        if (!count($options)) {
            return true;
        }
        foreach ($options as $option) {
            if (!$this->options()->get($option)) {
                return false;
            }
        }
        return true;
    }
711014
protected static function _unrelateHasAndBelongsToMany($options) {
        $modelA = $options['modelA'];
        $modelB = $options['modelB'];
        $keyA   = $options['keyA'];
        $keyB   = $options['keyB'];
        $ruleA  = $options['ruleA'];
        $ruleB  = $options['ruleB'];
        $bindingModel = !$options['bindingModel'] ? $modelA->getBindingModel($modelB) :
            $options['bindingModel'];

        /**
         * Warning: assumptions are made!
         * - at this point, we assume the bindingModel has no relationships
         *   to models other than modelA and modelB (so we don't need a rule or anything
         *   to find the right reference in the referenceMap)
         * - also, we assume the references can be found from the bindingModel. There will be
         *   no trying nor catching, if the reference is not here, we just crash the heck out of it.
         */
        $referenceA = $bindingModel->getReference(get_class($modelA), $ruleA);
        $referenceB = $bindingModel->getReference(get_class($modelB), $ruleB);

        // Construct WHERE clause
        $where = array();
        $createWhereBit = function ($reference, $values) {
            $w = array();
            foreach ($reference['columns'] as $i => $column) {
                $w[] = '`' . $column . '` = ' . $values[$i];
            }
            $w = implode(' AND ', $w);
            return '(' . $w . ')';
        };

        if ($keyA) {
            $where[] = $createWhereBit($referenceA, $keyA);
        }
        if ($keyB) {
            $where[] = $createWhereBit($referenceB, $keyB);
        }

        $where = '(' . implode(' AND ', $where) . ')';

        // Homophyllic relations can be deleted bidirectionally
        if ($options['bidirectional'] && $modelA->getName() == $modelB->getName()) {
            $homoWhere = array();
            if ($keyA) {
                $homoWhere[] = $createWhereBit($referenceB, $keyA);
            }
            if ($keyB) {
                $homoWhere[] = $createWhereBit($referenceA, $keyB);
            }

            $where .= ' OR (' . implode(' AND ', $homoWhere) . ')';
        }

        return $bindingModel->delete($where);
    }
1034610
public function setOptions($options)
    {
        if (!is_array($options) && !$options instanceof Traversable) {
            throw new Exception\InvalidArgumentException(sprintf(
                '"%s" expects an array or Traversable; received "%s"',
                __METHOD__,
                (is_object($options) ? get_class($options) : gettype($options))
            ));
        }

        foreach ($options as $key => $value) {
            if ($key == 'options') {
                $key = 'adapterOptions';
            }
            $method = 'set' . ucfirst($key);
            if (method_exists($this, $method)) {
                $this->$method($value);
            }
        }
        return $this;
    }
355407
protected function mergeOptions(array $defaulOptions, array $options = null)
    {
        if (is_null($options)) {
            $options = $defaulOptions;
        }

        foreach ($defaulOptions as $key => $value) {
            if (!isset($options[$key])) {
                $options[$key] = $value;
            }
            if (is_bool($options[$key])) {
                $options[$key] = ($options[$key]) ? 'true' : 'false';
            }
        }

        return $options;
    }