Exemple #1
0
 /**
  * 
  * Given a class or object, add its vendor and its parent vendors to the 
  * stack; optionally, add a standard suffix base to the vendor name.
  * 
  * @param string|object $spec The class or object to find vendors of.
  * 
  * @param string $base The suffix base to append to each vendor name.
  * 
  * @return void
  * 
  */
 public function addByVendors($spec, $base = null)
 {
     // get the list of parents; retain Solar_Base
     $parents = Solar_Class::parents($spec, true);
     // if we have a suffix, put a separator on it
     if ($base) {
         $base = "_{$base}";
     }
     // look through vendor names
     $old = null;
     foreach ($parents as $class) {
         $new = Solar_Class::vendor($class);
         if ($new != $old) {
             // not the same, add the current vendor name and suffix
             $this->add("{$new}{$base}");
         }
         // retain old vendor for next loop
         $old = $new;
     }
 }
 /**
  * 
  * Returns the translated locale string for a class and key.
  * 
  * Loads translations as needed.
  * 
  * You can also pass an array of replacement values.  If the `$replace`
  * array is sequential, this method will use it with vsprintf(); if the
  * array is associative, this method will replace "{:key}" with the array
  * value.
  * 
  * For example:
  * 
  * {{code: php
  *     
  *     $locale = Solar_Registry('locale');
  *     
  *     $page  = 2;
  *     $pages = 10;
  *     
  *     // given a class of 'Solar_Example' with a locale string
  *     // TEXT_PAGES => 'Page %d of %d', uses vsprintf() internally:
  *     $replace = array($page, $pages);
  *     echo $locale->fetch('Solar_Example', 'TEXT_PAGES', $pages, $replace);
  *     // echo "Page 2 of 10"
  *     
  *     // given a class of 'Solar_Example' with a locale string
  *     // TEXT_PAGES => 'Page {:page} of {:pages}', uses str_replace()
  *     // internally:
  *     $replace = array('page' => $page, 'pages' => $pages);
  *     echo $locale->fetch('Solar_Example', 'TEXT_PAGES', $pages, $replace);
  *     // echo "Page 2 of 10"
  * }}
  * 
  * @param string|object $spec The class name (or object) for the translation.
  * 
  * @param string $key The translation key.
  * 
  * @param mixed $num Helps determine whether to get a singular
  * or plural translation.
  * 
  * @param array $replace An array of replacement values for the string.
  * 
  * @return string A translated locale string.
  * 
  * @see _trans()
  * 
  * @see Solar_Base::locale()
  * 
  * @see Manual::Solar/Using_locales
  * 
  */
 public function fetch($spec, $key, $num = 1, $replace = null)
 {
     // is the spec an object?
     if (is_object($spec)) {
         // yes, find its class
         $class = get_class($spec);
     } else {
         // no, assume the spec is a class name
         $class = (string) $spec;
     }
     // does the translation key exist for this class?
     // pre-empts the stack check.
     $string = $this->_trans($class, $key, $num, $replace);
     if ($string !== null) {
         return $string;
     }
     // find all parents of the class, including the class itself
     $parents = array_reverse(Solar_Class::parents($class, true));
     // add the vendor namespace to the stack for vendor-wide strings
     $vendor = Solar_Class::vendor($class);
     $parents[] = $vendor;
     // add Solar as the final fallback.
     if ($vendor != 'Solar') {
         $parents[] = 'Solar';
     }
     // go through all parents and find the first matching key
     foreach ($parents as $parent) {
         // do we need to load locale strings for the class?
         if (!array_key_exists($parent, $this->trans)) {
             $this->_load($parent);
         }
         // does the key exist for the parent?
         $string = $this->_trans($parent, $key, $num, $replace);
         if ($string !== null) {
             // save it for the class so we don't need to go through the
             // stack again, and then we're done.
             $this->trans[$class][$key] = $this->trans[$parent][$key];
             return $string;
         }
     }
     // never found a translation, return the requested key.
     return $key;
 }
 /**
  * 
  * Sets the class this app will extend from.
  * 
  * @param string $class The app class name.
  * 
  * @return void
  * 
  */
 protected function _setExtends($class)
 {
     // explicit as cli option?
     $extends = $this->_options['extends'];
     if ($extends) {
         $this->_extends = $extends;
         return;
     }
     // explicit as config value?
     if ($this->_model_name) {
         $extends = $this->_config['extends_model'];
     } else {
         $extends = $this->_config['extends'];
     }
     if ($extends) {
         $this->_extends = $extends;
         return;
     }
     // look at the vendor name and find a controller class
     $vendor = Solar_Class::vendor($class);
     if ($this->_model_name) {
         $name = "{$vendor}_Controller_Bread";
         $file = $this->_target . "{$vendor}/Controller/Bread.php";
     } else {
         $name = "{$vendor}_Controller_Page";
         $file = $this->_target . "{$vendor}/Controller/Page.php";
     }
     if (file_exists($file)) {
         $this->_extends = $name;
         return;
     }
     // final fallback: Solar_Controller_Page
     $this->_extends = 'Solar_Controller_Page';
     return;
 }
Exemple #4
0
 /**
  * 
  * Public interface to execute the command.
  * 
  * This method...
  * 
  * - populates and validates the option values
  * - calls _preExec()
  * - calls _exec() with the numeric parameters from the options
  * - calls _postExec()
  * 
  * @param array $argv The command-line arguments from the user.
  * 
  * @return void
  * 
  * @todo Accept a Getopt object in addition to $argv array?
  * 
  */
 public function exec($argv = null)
 {
     // get the command-line arguments
     if ($argv === null) {
         // use the $_SERVER values
         $argv = $this->_request->server['argv'];
         // remove the argument pointing to this command
         array_shift($argv);
     } else {
         $argv = (array) $argv;
     }
     // set options, populate values, and validate parameters
     $this->_getopt->populate($argv);
     if (!$this->_getopt->validate()) {
         // need a better way to throw exceptions with specific error
         // messages
         throw $this->_exception('ERR_INVALID_OPTIONS', array('invalid' => $this->_getopt->getInvalid(), 'options' => $this->_getopt->options));
     }
     // retain the option values, minus the numeric params
     $this->_options = $this->_getopt->values();
     $params = array();
     foreach ($this->_options as $key => $val) {
         if (is_int($key)) {
             $params[] = $val;
             unset($this->_options[$key]);
         }
     }
     // special behavior for -V/--version
     if ($this->_options['version']) {
         $vendor = Solar_Class::vendor($this);
         $this->_out("{$vendor} command-line tool, Solar version ");
         $this->_outln(Solar::apiVersion() . '.');
         return;
     }
     // call pre-exec
     $skip_exec = $this->_preExec();
     // should we skip the main execution?
     if ($skip_exec !== true) {
         // call _exec() with the numeric params from getopt
         call_user_func_array(array($this, '_exec'), $params);
     }
     // call post-exec
     $this->_postExec();
     // done, return terminal to normal colors
     $this->_out("%n");
 }
Exemple #5
0
 /**
  * 
  * Generates a simple exception, but does not throw it.
  * 
  * This method attempts to automatically load an exception class
  * based on the error code, falling back to parent exceptions
  * when no specific exception classes exist.  For example, if a
  * class named 'Vendor_Example' extended from 'Vendor_Base' throws an
  * exception or error coded as 'ERR_FILE_NOT_FOUND', the method will
  * attempt to return these exception classes in this order ...
  * 
  * 1. Vendor_Example_Exception_FileNotFound (class specific)
  * 
  * 2. Vendor_Base_Exception_FileNotFound (parent specific)
  * 
  * 3. Vendor_Example_Exception (class generic)
  * 
  * 4. Vendor_Base_Exception (parent generic)
  * 
  * 5. Vendor_Exception (generic for all of vendor)
  * 
  * The final fallback is always the generic Solar_Exception class.
  * 
  * Note that this method only generates the object; it does not
  * throw the exception.
  * 
  * {{code: php
  *     $class = 'My_Example_Class';
  *     $code = 'ERR_SOMETHING_WRONG';
  *     $text = 'Something is wrong.';
  *     $info = array('foo' => 'bar');
  *     $exception = Solar::exception($class, $code, $text, $info);
  *     throw $exception;
  * }}
  * 
  * In general, you shouldn't need to use this directly in classes
  * extended from [[Class::Solar_Base]].  Instead, use
  * [[Solar_Base::_exception() | $this->_exception()]] for automated
  * picking of the right exception class from the $code, and
  * automated translation of the error message.
  * 
  * @param string|object $spec The class name (or object) that generated 
  * the exception.
  * 
  * @param mixed $code A scalar error code, generally a string.
  * 
  * @param string $text Any error message text.
  * 
  * @param array $info Additional error information in an associative
  * array.
  * 
  * @return Solar_Exception
  * 
  */
 public static function exception($spec, $code, $text = '', $info = array())
 {
     // is the spec an object?
     if (is_object($spec)) {
         // yes, find its class
         $class = get_class($spec);
     } else {
         // no, assume the spec is a class name
         $class = (string) $spec;
     }
     // drop 'ERR_' and 'EXCEPTION_' prefixes from the code
     // to get a suffix for the exception class
     $suffix = $code;
     if (strpos($suffix, 'ERR_') === 0) {
         $suffix = substr($suffix, 4);
     } elseif (strpos($suffix, 'EXCEPTION_') === 0) {
         $suffix = substr($suffix, 10);
     }
     // convert "STUDLY_CAP_SUFFIX" to "Studly Cap Suffix" ...
     $suffix = ucwords(strtolower(str_replace('_', ' ', $suffix)));
     // ... then convert to "StudlyCapSuffix"
     $suffix = str_replace(' ', '', $suffix);
     // build config array from params
     $config = array('class' => $class, 'code' => $code, 'text' => $text, 'info' => (array) $info);
     // get all parent classes, including the class itself
     $stack = array_reverse(Solar_Class::parents($class, true));
     // add the vendor namespace to the stack as a fallback, even though
     // it's not strictly part of the hierarchy, for generic vendor-wide
     // exceptions.
     $vendor = Solar_Class::vendor($class);
     if ($vendor != 'Solar') {
         $stack[] = $vendor;
     }
     // add Solar as the final fallback
     $stack[] = 'Solar';
     // track through class stack and look for specific exceptions
     foreach ($stack as $class) {
         try {
             $obj = Solar::factory("{$class}_Exception_{$suffix}", $config);
             return $obj;
         } catch (Exception $e) {
             // do nothing
         }
     }
     // track through class stack and look for generic exceptions
     foreach ($stack as $class) {
         try {
             $obj = Solar::factory("{$class}_Exception", $config);
             return $obj;
         } catch (Exception $e) {
             // do nothing
         }
     }
     // last resort: a generic Solar exception
     return Solar::factory('Solar_Exception', $config);
 }
Exemple #6
0
 /**
  * 
  * Sets the model stack.
  * 
  * @param array $classes An array of class prefixes to use for the model
  * stack.
  * 
  * @return void
  * 
  */
 protected function _setStack($classes)
 {
     if (!$classes) {
         // add per the vendor on this catalog and its inheritance
         $parents = Solar_Class::parents(get_class($this), true);
         array_shift($parents);
         // Solar_Base
         $old_vendor = false;
         foreach ($parents as $class) {
             $new_vendor = Solar_Class::vendor($class);
             if ($new_vendor != $old_vendor) {
                 $classes[] = "{$new_vendor}_Model";
             }
             $old_vendor = $new_vendor;
         }
     }
     // build the class stack
     $this->_stack = Solar::factory('Solar_Class_Stack');
     $this->_stack->add($classes);
 }
Exemple #7
0
 /**
  * 
  * Sets the class this model will extend from.
  * 
  * @param string $class The model class name.
  * 
  * @return void
  * 
  */
 protected function _setExtends($class)
 {
     // explicit as cli option?
     $extends = $this->_options['extends'];
     if ($extends) {
         $this->_extends = $extends;
         return;
     }
     // explicit as config value?
     $extends = $this->_config['extends'];
     if ($extends) {
         $this->_extends = $this->_config['extends'];
         return;
     }
     // look at the class name and find a Vendor_Sql_Model class
     $vendor = Solar_Class::vendor($class);
     $file = $this->_target . "{$vendor}/Sql/Model.php";
     if (file_exists($file)) {
         $this->_extends = "{$vendor}_Sql_Model";
         return;
     }
     // final fallback: Solar_Sql_Model
     $this->_extends = 'Solar_Sql_Model';
     return;
 }
Exemple #8
0
 /**
  * 
  * Finds the config file for a test case.
  * 
  * The order of precedence is:
  * 
  * 1. Use the value of --test-config when not empty.
  * 
  * 2. Look for `$system/config/test/Vendor.config.php` and use that if it
  *    exists.
  * 
  * 3. Look for `$system/source/vendor/tests/config.php` and use that if it
  *    exists.
  * 
  * 4. No config for the test case.
  * 
  * @param string $class The test case class to find configs for.
  * 
  * @return string The config file location for the test case.
  * 
  */
 protected function _fetchTestCaseConfig($class)
 {
     // explicit test-config
     if ($this->_config['test_config']) {
         return $this->_config['test_config'];
     }
     // convenience var
     $system = Solar::$system;
     // strip the 'Test_' prefix, then get the vendor name
     $vendor = Solar_Class::vendor(substr($class, 5));
     // look for a config/test/Vendor.config.php file
     $path = "{$system}/config/test/{$vendor}.config.php";
     $file = Solar_File::exists($path);
     if ($file) {
         return $file;
     }
     // look for a source/vendor/tests/config.php file
     $dash = Solar_Registry::get('inflect')->camelToDashes($vendor);
     $path = "{$system}/source/{$dash}/tests/config.php";
     $file = Solar_File::exists($path);
     if ($file) {
         return $file;
     }
     // no test config
     return null;
 }
Exemple #9
0
 /**
  * 
  * Find the vendors of a given class or object and its parents.
  * 
  * @param mixed $spec An object, or a class name.
  * 
  * @return array The vendor names of the class or object hierarchy.
  * 
  */
 public static function vendors($spec)
 {
     // vendor listing
     $stack = array();
     // get the list of parents
     $parents = Solar_Class::parents($spec, true);
     // look through vendor names
     $old = null;
     foreach ($parents as $class) {
         $new = Solar_Class::vendor($class);
         if ($new != $old) {
             // not the same, add the current vendor name and suffix
             $stack[] = $new;
         }
         // retain old vendor for next loop
         $old = $new;
     }
     return $stack;
 }
Exemple #10
0
 /**
  * 
  * Sets the class this app will extend from.
  * 
  * @param string $class The app class name.
  * 
  * @return void
  * 
  */
 protected function _setExtends($class)
 {
     // explicit as cli option?
     $extends = $this->_options['extends'];
     if ($extends) {
         $this->_extends = $extends;
         return;
     }
     // explicit as a config value?
     $extends = $this->_config['extends'];
     if ($extends) {
         $this->_extends = $extends;
         return;
     }
     // look at the vendor name and find a controller class
     $vendor = Solar_Class::vendor($class);
     $name = "{$vendor}_Controller_Command";
     $file = $this->_target . "{$vendor}/Controller/Command.php";
     if (file_exists($file)) {
         $this->_extends = $name;
         return;
     }
     // final fallback: Solar_Controller_Command
     $this->_extends = 'Solar_Controller_Command';
 }