/** * Construct association object * * @param string $assocName * @param array $options * @param object $model */ public function __construct($assocName, $options, Mad_Model_Base $model) { $valid = array('className', 'foreignKey', 'primaryKey', 'include', 'order', 'dependent' => 'nullify'); $this->_options = Mad_Support_Base::assertValidKeys($options, $valid); $this->_assocName = $assocName; $this->_model = $model; $this->_conn = $model->connection(); // get inflections $toMethod = Mad_Support_Inflector::camelize($this->_assocName, 'lower'); $toMethod = str_replace('/', '_', $toMethod); $toClass = ucfirst($toMethod); $this->_methods = array($toMethod => 'getObject', $toMethod . '=' => 'setObject', 'build' . $toClass => 'buildObject', 'create' . $toClass => 'createObject'); }
/** * Pluralize the $singular word unless $count is one. If $plural * form is not supplied, inflector will be used. * * @param integer $count Count determines singular or plural * @param string $singular Singular form * @param string|null $plural Plural form (optional) */ public function pluralize($count, $singular, $plural = null) { if ($count == '1') { $word = $singular; } else { if ($plural) { $word = $plural; } else { $word = Mad_Support_Inflector::pluralize($singular); } } return "{$count} {$word}"; }
/** * Construct association object * * @param string $assocName * @param array $options * @param object $model */ public function __construct($assocName, $options, Mad_Model_Base $model) { $valid = array('className', 'conditions', 'order', 'foreignKey', 'primaryKey', 'associationForeignKey', 'associationPrimaryKey', 'joinTable', 'uniq', 'include', 'finderSql', 'deleteSql', 'insertSql'); $this->_options = Mad_Support_Base::assertValidKeys($options, $valid); $this->_assocName = $assocName; $this->_model = $model; $this->_conn = $model->connection(); // get inflections $toMethod = Mad_Support_Inflector::camelize($this->_assocName, 'lower'); $toMethod = str_replace('/', '_', $toMethod); $singular = Mad_Support_Inflector::singularize($toMethod); $toClass = ucfirst($singular); $this->_methods = array($toMethod => 'getObjects', $toMethod . '=' => 'setObjects', $singular . 'Ids' => 'getObjectIds', $singular . 'Ids=' => 'setObjectIds', $singular . 'Count' => 'getObjectCount', 'add' . $toClass => 'addObject', Mad_Support_Inflector::pluralize('replace' . $toClass) => 'replaceObjects', Mad_Support_Inflector::pluralize('delete' . $toClass) => 'deleteObjects', Mad_Support_Inflector::pluralize('clear' . $toClass) => 'clearObjects', Mad_Support_Inflector::pluralize('find' . $toClass) => 'findObjects'); }
/** * Construct association object * * @param string $assocName * @param array $options */ public function __construct($assocName, $options, Mad_Model_Base $model) { $valid = array('className', 'foreignKey', 'associationForeignKey', 'primaryKey', 'associationPrimaryKey', 'include', 'select', 'conditions', 'order', 'finderSql', 'through', 'dependent' => 'nullify'); $this->_options = Mad_Support_Base::assertValidKeys($options, $valid); $this->_assocName = $assocName; $this->_model = $model; $this->_conn = $model->connection(); // throw fatal error if through option is invalid $this->_throughClass = Mad_Support_Inflector::classify($this->_options['through']); class_exists($this->_throughClass); // get inflections $toMethod = Mad_Support_Inflector::camelize($this->_assocName, 'lower'); $toMethod = str_replace('/', '_', $toMethod); $singular = Mad_Support_Inflector::singularize($toMethod); $toClass = ucfirst($singular); $this->_methods = array($toMethod => 'getObjects', $singular . 'Ids' => 'getObjectIds', $singular . 'Count' => 'getObjectCount', 'add' . $toClass => 'addObject', Mad_Support_Inflector::pluralize('delete' . $toClass) => 'deleteObjects', Mad_Support_Inflector::pluralize('clear' . $toClass) => 'clearObjects', Mad_Support_Inflector::pluralize('find' . $toClass) => 'findObjects'); }
/** * Given a status parameter, determine whether it needs to be converted * to a string. If it is an integer, use the $statusCodes hash to lookup * the default message. If it is a string, build $symbolToStatusCode * and convert it. * * interpret(404) => "404 Not Found" * interpret("notFound") => "404 Not Found" * * Differences from Rails: * - $status is camelized, not underscored. * - an unknown status raises an exception * * @param string|integer Status code or "symbol" * @return string Header */ public static function interpret($status) { // Status from integer or numeric string if (is_numeric($status)) { if (isset(self::$statusCodes[$status])) { return "{$status} " . self::$statusCodes[$status]; } else { $msg = "Unknown status code: {$status}"; throw new InvalidArgumentException($msg); } // Status from string } else { if (is_string($status)) { // Build a string-to-integer lookup for converting a symbol (like // 'created' or 'notImplemented') into its corresponding HTTP status // code (like 200 or 501). static $symbolToStatusCode = array(); if (empty($symbolToStatusCode)) { foreach (self::$statusCodes as $code => $message) { $symbol = Mad_Support_Inflector::camelize($message, $first = 'lower'); $symbolToStatusCode[$symbol] = $code; } } // Convert status symbol to integer code, return header if (isset($symbolToStatusCode[$status])) { return self::interpret($symbolToStatusCode[$status]); } // Error: Status symbol could not be converted to an integer code // Try to help if the developer mixed up underscore/camel $msg = "Unknown status: '{$status}'"; if (strpos($status, '_')) { $status = Mad_Support_Inflector::camelize($status, $first = 'lower'); if (isset($symbolToStatusCode[$status])) { $msg .= " (underscore), did you mean '{$status}' (camel)?"; } } throw new InvalidArgumentException($msg); // Status is an unknown type } else { $msg = '$status must be numeric or string, got ' . gettype($status); throw new InvalidArgumentException($msg); } } }
/** * Add associations specified via the <tt>:includes</tt> option. * Expects a block that takes as arguments: * +association+ - name of the association * +records+ - the association record(s) to be serialized * +opts+ - options for the association records */ public function addIncludes() { if (isset($this->_options['include'])) { $includeAssociations = (array) $this->_options['include']; unset($this->_options['include']); } if (empty($includeAssociations)) { return; } $baseOnlyOrExcept = array('except' => $this->_options['except'], 'only' => $this->_options['only']); // associative array includes have additional options $includeHasOptions = !is_int(key($includeAssociations)); $associations = $includeHasOptions ? array_keys($includeAssociations) : $includeAssociations; // find records for each association foreach ($associations as $association) { $assoc = $this->_record->reflectOnAssociation($association); $type = $assoc->getMacro(); $method = Mad_Support_Inflector::camelize($association, 'lower'); if ($type == 'hasMany' || $type == 'hasAndBelongsToMany') { $records = $this->_record->{$method}()->getCollection(); } elseif ($type == 'hasOne' || $type == 'belongsTo') { $records = $this->_record->{$method}(); } if ($records === null) { continue; } // options if ($includeHasOptions) { $associationOptions = $includeAssociations[$association]; } else { $associationOptions = $baseOnlyOrExcept; } // sub-records $opts = array_merge($this->_options, $associationOptions); $this->yieldRecords($association, $records, $opts); } $this->_options['include'] = $includeAssociations; }
/** * Generate mailer class stubs */ private function _generateMailerStubs() { $name = !empty($this->_args) ? array_shift($this->_args) : null; if (!$name) { $this->_exit("You did not specify the name of the Mailer to generate"); } $name = str_replace('Mailer', '', $name); $mailerName = Mad_Support_Inflector::camelize($name) . 'Mailer'; $this->_tpl->mailerName = $mailerName; $content = $this->_tpl->render('mailer.php'); $this->_createFile(MAD_ROOT . "/app/models/{$mailerName}.php", $content); // CREATE DIRECTORIES $this->_createDir(MAD_ROOT . '/app/views/' . $mailerName); }
/** * Proxy to parent Mad_Support_ArrayObject#toXml, except that * we know the explicit model type. */ public function toXml($options = array()) { if (!isset($options['root'])) { $options['root'] = Mad_Support_Inflector::pluralize(get_class($this->_model)); } return parent::toXml($options); }
public function getJsonClassName() { return '"' . Mad_Support_Inflector::underscore($this->_className) . '"'; }
/** * Set the value for an attribute in this object. * * @param string $name * @param mixed $value */ protected function _setAttribute($name, $value) { // check for writer proxy method $underscore = Mad_Support_Inflector::underscore("set_{$name}"); $methodName = Mad_Support_Inflector::camelize($underscore, 'lower'); if (method_exists($this, $methodName)) { $this->{$methodName}($value); } else { $property = "_{$name}"; if (property_exists($this, $property)) { $this->{$property} = $value; } else { $this->_attrValues[$name] = $value; } } }
/** * @param string $association * @param mixed $records * @param array $opts */ public function addAssociations($association, $records, $opts) { // association collection if (is_array($records)) { $name = $this->dasherize($association); if (empty($records)) { $this->getBuilder()->tag($name, '', array('type' => 'array')); } else { $tag = $this->getBuilder()->startTag($name, '', array('type' => 'array')); $associationName = Mad_Support_Inflector::singularize($association); foreach ($records as $record) { $type = get_class($record) == $associationName ? null : get_class($record); $options = array_merge($opts, array('root' => $associationName, 'type' => $type)); $record->toXml($options); } $tag->end(); } // single association } else { $records->toXml(array_merge($opts, array('root' => $association))); } }
/** * Actually return object, and not class * * @param string $migrationName * @param int $version * @return Mad_Model_Migration_Base */ protected function _getMigrationClass($migrationName, $version) { $className = Mad_Support_Inflector::camelize($migrationName); $migration = new $className(); $migration->version = $version; return $migration; }
public function testClearCache() { Mad_Support_Inflector::setCache('documents', 'singularize', 'document'); Mad_Support_Inflector::clearCache(); $this->assertEquals(false, Mad_Support_Inflector::getCache('documents', 'singularize')); }
/** * Divine the controller name from the functional test name, * since the controller or request may not be available at * the time the URL needs to be generated. */ protected function _getControllerNameFromTest() { $class = get_class($this); if (preg_match('/^(.*)ControllerTest$/', $class, $matches) == 0) { return null; } return Mad_Support_Inflector::underscore($matches[1]); }
/** * Render a response that has no content (merely headers). The options * argument is interpreted to be a hash of header names and values. * This allows you to easily return a response that consists only of * significant headers: * * head('created', array('location' => 'http://foo')) * head(array('status' => 'created', 'location' => 'http://foo')) * * @param integer|string|array $first Status code or options array * @param array $second Options array * @return void */ protected function head($first, $second = array()) { if (is_array($first)) { $options = $first; if (isset($options['status'])) { $status = $options['status']; unset($options['status']); } else { $status = 'ok'; } } else { $status = $first; $options = $second; } $status = $this->interpretStatus($status); foreach ($options as $key => $value) { $dashed = Mad_Support_Inflector::dasherize($key); $spaced = str_replace('-', ' ', $dashed); $spaced = ucwords($spaced); $dashed = str_replace(' ', '-', $spaced); $this->_response->setHeader("{$dashed}: {$value}", $replace = true); } $this->_response->setStatus($status); $this->render(array('nothing' => true)); }
/** * Get the join table for hasAndBelongsToMany associations. Default to * tablename1_tablename2 by alpha (briefcases_documents) * * Example: * <code> * class Binder * ... * $this->hasAndBelongsToMany('Documents'); * ... * // returns 'briefcases_documents' (by default) * </code> * * @return string */ public function getJoinTable() { if (!isset($this->_joinTable)) { $macro = $this->getMacro(); // join table was given in options if (!empty($this->_options['joinTable'])) { $this->_joinTable = $this->_options['joinTable']; // join table from through association } elseif (!empty($this->_options['through'])) { $class = Mad_Support_Inflector::classify($this->_options['through']); $model = new $class(); $this->_joinTable = $model->tableName(); // determine table name by convention from DO data } elseif ($macro == 'hasAndBelongsToMany') { $tbls = array($this->_model->tableName(), $this->getAssocTable()); sort($tbls); $this->_joinTable = implode('_', $tbls); // no join table } else { $this->_joinTable = null; } } return $this->_joinTable; }
/** * Load fixture(s) data into the database. * * <code> * <?php * ... * // single * $this->fixtures('briefcases'); * * // multiple * $this->fixtures(array('briefcases', 'md_metadata')); * * // 'only' for given test methods * $this->fixtures('briefcases', array('only' => array('testMethod1', 'testMethod2'))); * * // all test methods 'except' given * $this->fixtures('briefcases', array('except' => array('testMethod1', 'testMethod2'))); * ... * ?> * </code> * * @param string|array $ymlFiles * @param array $options */ public function fixtures($args) { $ymlFiles = func_get_args(); $last = end($ymlFiles); $options = is_array($last) ? array_pop($ymlFiles) : array(); // don't load fixtures for these methods if (isset($options['except'])) { if (in_array($this->getName(), $options['except'])) { return; } } // only load fixtures for these methods if (isset($options['only'])) { if (!in_array($this->getName(), $options['only'])) { return; } } // Add fixtures to the existing fixtures when called more than once if (empty($this->_fixtures)) { $this->_fixtures = new Mad_Test_Fixture_Collection($this->_conn, $ymlFiles); } else { $this->_fixtures->addFixture($ymlFiles); } // Build models from fixture records foreach ($this->_fixtures->getFixtures() as $fixture) { $name = $fixture->getYmlName(); if (isset($this->_fixtureClassNames[$name])) { $class = $this->_fixtureClassNames[$name]; } else { $table = $fixture->getTableName(); $class = Mad_Support_Inflector::classify($table); } // skip building model if class doesn't exist if (!Mad_Support_Base::modelExists($class)) { break; } $model = new $class(); $this->_records[$name] = array(); foreach ($fixture->getRecords() as $recordName => $attrs) { $this->_records[$name][$recordName] = $model->instantiate($attrs); } } // @deprecated - assign public properties based on fixture names foreach ($this->_fixtures->getRecords() as $recordName => $values) { if (isset($this->{$recordName})) { $this->{$recordName} = array_merge($this->{$recordName}, $values); } else { $this->{$recordName} = $values; } // make all values strings foreach ($this->{$recordName} as &$value) { $value = (string) $value; } } }
/** * Convert array collection to XML * @param array $array * @param array $options */ public function arrayToXml($array, $options = array()) { $firstElt = current($array); $firstType = is_object($firstElt) ? get_class($firstElt) : gettype($firstElt); $sameTypes = true; foreach ($array as $element) { // either an array or object with toXml method if (!is_array($element) && !is_callable(array($element, 'toXml'))) { throw new Mad_Support_Exception("Not all elements respond to toXml"); } if (get_class($element) != $firstType) { $sameTypes = false; } } if (!isset($options['root'])) { if ($sameTypes && count($array) > 0) { $options['root'] = Mad_Support_Inflector::pluralize($firstType); } else { $options['root'] = 'records'; } } if (!isset($options['children'])) { $options['children'] = Mad_Support_Inflector::singularize($options['root']); } if (!isset($options['indent'])) { $options['indent'] = 2; } if (!isset($options['skipTypes'])) { $options['skipTypes'] = false; } if (empty($options['builder'])) { $options['builder'] = new Mad_Support_Builder(array('indent' => $options['indent'])); } $root = $options['root']; unset($options['root']); $children = $options['children']; unset($options['children']); if (!array_key_exists('dasherize', $options) || !empty($options['dasherize'])) { $root = Mad_Support_Inflector::dasherize($root); } if (empty($options['skipInstruct'])) { $options['builder']->instruct(); } $opts = array_merge($options, array('root' => $children)); $builder = $options['builder']; $attrs = $options['skipTypes'] ? array() : array('type' => 'array'); // no elements in array if (count($array) == 0) { $builder->tag($root, '', $attrs); // build xml from elements } else { $tag = $builder->startTag($root, '', $attrs); $opts['skipInstruct'] = true; foreach ($array as $element) { // associative array if (is_array($element) && !is_int(key($element))) { $this->hashToXml($element, $opts); // array } elseif (is_array($element)) { $this->arrayToXml($element, $opts); // object } else { $element->toXml($opts); } } $tag->end(); } return $builder->__toString(); }
/** * Serialize the collection to XML. */ public function toXml($options = array()) { if (!isset($options['root'])) { $options['root'] = Mad_Support_Inflector::pluralize(get_class($this->_model)); } $conversion = new Mad_Support_ArrayConversion(); return $conversion->toXml($this, $options); }
/** * Stale the cache of inflection data */ public static function clearCache() { self::$_inflections = array(); }
public function humanAttributeName($attr) { $attr = Mad_Support_Inflector::underscore($attr); return ucfirst(str_replace('_', ' ', $attr)); }
/** * Take the $matchdata returned by a Horde_Routes_Mapper match and add * in :controller and :action that are used by the rest of the framework. * * Format controller names: my_stuff => MyStuffController * Format action names: action_name => actionName * * @param array $matchdata * @return mixed false | array */ public function formatMatchdata($matchdata) { $ret = array(); foreach ($matchdata as $key => $val) { if ($key == 'controller') { $ret['controller'] = $val; $ret[':controller'] = Mad_Support_Inflector::camelize($val) . 'Controller'; } elseif ($key == 'action') { // Horde_Routes_Mapper->resource() and Python Routes are inconsistent // with Rails by using "delete" instead of "destroy". if ($val == 'delete') { $val = 'destroy'; } $ret['action'] = $val; $ret[':action'] = Mad_Support_Inflector::camelize($val, 'lower'); } else { $ret[$key] = $val; } } return !empty($ret) && isset($ret['controller']) ? $ret : false; }
/** * Construct associations for model from record/row * * @param object $record * @param object $join * @param array $row */ protected function _constructAssociation(Mad_Model_Base $record, Mad_Model_Join_Base $join, $row) { // set that we've loaded this association $record->setAssociationLoaded($join->reflection()->getAssocName()); if ($record->id != $join->parent()->recordId($row) || empty($row[$join->aliasedPrimaryKey()])) { return; } $association = $join->instantiate($row); $macro = $join->reflection()->getMacro(); $singular = Mad_Support_Inflector::singularize($join->reflection()->getAssocName()); if ($macro == 'hasAndBelongsToMany' || $macro == 'hasMany' || $macro == 'hasManyThrough') { $addMethod = Mad_Support_Inflector::camelize('add' . ucfirst($singular), 'lower'); $addMethod = str_replace('/', '_', $addMethod); // make sure object isn't already included $getter = Mad_Support_Inflector::camelize($join->reflection()->getAssocName(), 'lower'); $getter = str_replace('/', '_', $getter); $exists = array(); foreach ($record->{$getter} as $val) { $exists[] = $val->id; } if (!in_array($association->id, $exists)) { $record->{$addMethod}($association); } } elseif ($macro == 'belongsTo' || $macro == 'hasOne') { $assignMethod = Mad_Support_Inflector::camelize($singular, 'lower'); $record->{$assignMethod} = $association; } return $association; }
/** * Construct association object - simple factory * @param string $macro (format|length|numericality|presence|uniqueness) * @param string $attributes * @param array $options */ public static function factory($macro, $attribute, $options) { $className = "Mad_Model_Validation_" . Mad_Support_Inflector::camelize($macro); return new $className($attribute, $options); }
/** * Initialize the default helpers for use in the views */ private function _initViewHelpers() { $controllerHelper = Mad_Support_Inflector::classify($this->_shortName . 'Helper'); $this->_view->addHelper(new $controllerHelper($this->_view)); }