diff --git a/app/controllers/tests_controller.php b/app/controllers/tests_controller.php index 5211d2af9..ed276d991 100644 --- a/app/controllers/tests_controller.php +++ b/app/controllers/tests_controller.php @@ -46,6 +46,18 @@ class TestsController extends TestsHelper { $this->layout = null; require_once TESTS.'index.php'; } + + function groups () + { + $this->layout = null; + require_once TESTS.'index.php'; + } + + function cases () + { + $this->layout = null; + require_once TESTS.'index.php'; + } /** * Runs all library and application tests * diff --git a/config/tags.ini.php b/config/tags.ini.php index f94c1a50b..9f4d1f099 100644 --- a/config/tags.ini.php +++ b/config/tags.ini.php @@ -54,7 +54,7 @@ hidden = "" textarea = "" ; Tag template for a input type='checkbox ' tag. -checkbox = "" +checkbox = "" ; Tag template for a input type='radio' tag. radio = "" diff --git a/libs/controller.php b/libs/controller.php index a16edf07f..c44dae64f 100644 --- a/libs/controller.php +++ b/libs/controller.php @@ -2,9 +2,7 @@ /* SVN FILE: $Id$ */ /** - * Short description for file. - * - * Long description for file + * Base controller class. * * PHP versions 4 and 5 * @@ -18,7 +16,7 @@ * Licensed under The MIT License * Redistributions of files must retain the above copyright notice. * - * @filesource + * @filesource * @author CakePHP Authors/Developers * @copyright Copyright (c) 2005, CakePHP Authors/Developers * @link https://trac.cakephp.org/wiki/Authors Authors/Developers @@ -32,7 +30,7 @@ */ /** - * Enter description here... + * Include files */ uses('model', 'inflector', 'folder', 'view', 'helper'); @@ -40,9 +38,9 @@ uses('model', 'inflector', 'folder', 'view', 'helper'); /** * Controller * - * Application controller (controllers are where you put all the actual code) + * Application controller (controllers are where you put all the actual code) * Provides basic functionality, such as rendering views (aka displaying templates). - * Automatically selects model name from on singularized object class name + * Automatically selects model name from on singularized object class name * and creates the model object if proper class exists. * * @package cake @@ -115,7 +113,7 @@ class Controller extends Object var $_viewVars = array(); /** - * Enter description here... + * Web page title * * @var boolean * @access private @@ -140,7 +138,7 @@ class Controller extends Object var $base = null; /** - * Enter description here... + * Layout file to use (see /app/views/layouts/default.thtml) * * @var string * @access public @@ -148,7 +146,7 @@ class Controller extends Object var $layout = 'default'; /** - * Enter description here... + * Automatically render the view (the dispatcher checks for this variable before running render()) * * @var boolean * @access public @@ -164,13 +162,13 @@ class Controller extends Object var $autoLayout = true; /** - * Enter description here... + * Database configuration to use (see /config/database.php) * * @var string * @access public */ var $useDbConfig = 'default'; - + /** * Enter description here... * @@ -180,7 +178,7 @@ class Controller extends Object var $beforeFilter = null; /** - * Constructor. + * Constructor. * */ function __construct ($params=null) @@ -205,9 +203,9 @@ class Controller extends Object else { // Run a single before filter - } + } } - + parent::__construct(); } @@ -329,7 +327,8 @@ class Controller extends Object } /** - * Enter description here... + * Gets an instance of the view object & prepares it for rendering the output, then + * asks the view to actualy do the job. * * @param unknown_type $action * @param unknown_type $layout @@ -416,7 +415,7 @@ class Controller extends Object /** * Sets data for this view. Will set title if the key "title" is in given $data array. * - * @param array $data Array of + * @param array $data Array of * @access private */ function _setArray($data) @@ -442,11 +441,12 @@ class Controller extends Object } /** - * Enter description here... + * Shows a message to the user $time seconds, then redirects to $url + * Uses flash.thtml as a layout for the messages * - * @param unknown_type $message - * @param unknown_type $url - * @param unknown_type $time + * @param string $message Message to display to the user + * @param string $url Relative URL to redirect to after the time expires + * @param int $time Time to show the message */ function flash($message, $url, $time=1) { @@ -459,9 +459,14 @@ class Controller extends Object $this->render(null,false,VIEWS.'layouts'.DS.'flash.thtml'); } - + /** - * Enter description here... + * Shows a message to the user $time seconds, then redirects to $url + * Uses flash.thtml as a layout for the messages + * + * @param string $message Message to display to the user + * @param string $url URL to redirect to after the time expires + * @param int $time Time to show the message * * @param unknown_type $message * @param unknown_type $url @@ -478,18 +483,18 @@ class Controller extends Object $this->render(null,false,VIEWS.'layouts'.DS.'flash.thtml'); } - + /** * This function creates a $fieldNames array for the view to use. * @todo Map more database field types to html form fields. * @todo View the database field types from all the supported databases. * */ - function generateFieldNames( $data = null, $doCreateOptions = true ) + function generateFieldNames( $data = null, $doCreateOptions = true ) { // Initialize the list array $fieldNames = array(); - + // figure out what model and table we are working with $model = Inflector::pluralize($this->name); $table = Inflector::singularize($this->name); @@ -497,7 +502,7 @@ class Controller extends Object // get all of the column names. $classRegistry =& ClassRegistry::getInstance(); $objRegistryModel = $classRegistry->getObject($table); - + foreach ($objRegistryModel->_table_info as $tables) { foreach ($tables as $tabl) @@ -524,7 +529,7 @@ class Controller extends Object { $fieldNames[$tabl['name']]['prompt'] = 'Modified'; } - + // Now, set up some other attributes that will be useful for auto generating a form. //tagName is in the format table/field "post/title" $fieldNames[ $tabl['name']]['tagName'] = $table.'/'.$tabl['name']; @@ -536,14 +541,14 @@ class Controller extends Object { // Now, we know that this field has some validation set. // find out if it is a required field. - if( VALID_NOT_EMPTY == $validationFields[ $tabl['name'] ] ) + if( VALID_NOT_EMPTY == $validationFields[ $tabl['name'] ] ) { // this is a required field. $fieldNames[$tabl['name']]['required'] = true; $fieldNames[$tabl['name']]['errorMsg'] = "Required Field"; } } - + // now, determine what the input type should be for this database field. $lParenPos = strpos( $tabl['type'], '('); $rParenPos = strpos( $tabl['type'], ')'); @@ -559,7 +564,7 @@ class Controller extends Object switch( $type ) { case "text": - { + { $fieldNames[ $tabl['name']]['type'] = 'area'; //$fieldNames[ $tabl['name']]['size'] = $fieldLength; } @@ -571,21 +576,21 @@ class Controller extends Object $fieldNames[ $tabl['name']]['type'] = 'select'; // This is a foreign key select dropdown box. now, we have to add the options. $fieldNames[ $tabl['name']]['options'] = array(); - + // get the list of options from the other model. $registry =& ClassRegistry::getInstance(); $otherModel = $registry->getObject($fieldNames[ $tabl['name']]['model']); - - if( is_object($otherModel) ) + + if( is_object($otherModel) ) { if( $doCreateOptions ) { $otherDisplayField = $otherModel->getDisplayField(); foreach( $otherModel->findAll() as $pass ) { - foreach( $pass as $key=>$value ) + foreach( $pass as $key=>$value ) { - if( $key == $fieldNames[ $tabl['name']]['model'] && isset( $value['id'] ) && isset( $value[$otherDisplayField] ) ) + if( $key == $fieldNames[ $tabl['name']]['model'] && isset( $value['id'] ) && isset( $value[$otherDisplayField] ) ) { $fieldNames[ $tabl['name']]['options'][$value['id']] = $value[$otherDisplayField]; } @@ -595,12 +600,24 @@ class Controller extends Object $fieldNames[ $tabl['name']]['selected'] = $data[$table][$tabl['name']]; } } - else + else { $fieldNames[ $tabl['name']]['type'] = 'input'; } } break; + case "tinyint": + { + if( $fieldLength > 1 ) + { + $fieldNames[ $tabl['name']]['type'] = 'input'; + } + else + { + $fieldNames[ $tabl['name']]['type'] = 'checkbox'; + } + } + break; case "int": case "decimal": case "float": @@ -618,21 +635,21 @@ class Controller extends Object $fieldNames[ $tabl['name']]['type'] = 'select'; // This is a foreign key select dropdown box. now, we have to add the options. $fieldNames[ $tabl['name']]['options'] = array(); - + // get the list of options from the other model. $registry =& ClassRegistry::getInstance(); $otherModel = $registry->getObject($fieldNames[ $tabl['name']]['model']); - - if( is_object($otherModel) ) + + if( is_object($otherModel) ) { - if( $doCreateOptions ) + if( $doCreateOptions ) { $otherDisplayField = $otherModel->getDisplayField(); foreach( $otherModel->findAll() as $pass ) { - foreach( $pass as $key=>$value ) + foreach( $pass as $key=>$value ) { - if( $key == $fieldNames[ $tabl['name']]['model'] && isset( $value['id'] ) && isset( $value[$otherDisplayField] ) ) + if( $key == $fieldNames[ $tabl['name']]['model'] && isset( $value['id'] ) && isset( $value[$otherDisplayField] ) ) { $fieldNames[ $tabl['name']]['options'][$value['id']] = $value[$otherDisplayField]; } @@ -642,7 +659,7 @@ class Controller extends Object $fieldNames[ $tabl['name']]['selected'] = $data[$table][$tabl['name']]; } } - else + else { $fieldNames[ $tabl['name']]['type'] = 'input'; } @@ -654,10 +671,10 @@ class Controller extends Object $fieldNames[ $tabl['name']]['type'] = 'select'; // This is a foreign key select dropdown box. now, we have to add the options. $fieldNames[ $tabl['name']]['options'] = array(); - + $enumValues = split(',', $fieldLength ); $iCount = 1; - foreach ($enumValues as $enum ) + foreach ($enumValues as $enum ) { $enum = trim( $enum, "'" ); $fieldNames[$tabl['name']]['options'][$enum] = $enum; @@ -671,37 +688,37 @@ class Controller extends Object { if( 0 != strncmp( "created", $tabl['name'], 6 ) && 0 != strncmp("modified",$tabl['name'], 8) ) $fieldNames[ $tabl['name']]['type'] = $type; - } + } break; default: //sorry, this database field type is not yet set up. - break; + break; } // end switch } // now, add any necessary hasAndBelongsToMany list boxes // loop through the many to many relations to make a list box. - foreach( $objRegistryModel->_manyToMany as $relation ) + foreach( $objRegistryModel->_manyToMany as $relation ) { list($tableName, $field, $value, $joinTable, $key1, $key2) = $relation; $otherModelName = Inflector::singularize($tableName); $otherModel = new $otherModelName(); - - if( $doCreateOptions ) + + if( $doCreateOptions ) { $otherDisplayField = $otherModel->getDisplayField(); $fieldNames[$tableName]['model'] = $tableName; $fieldNames[$tableName]['prompt'] = "Related ".Inflector::humanize($tableName); $fieldNames[$tableName]['type'] = "selectMultiple"; $fieldNames[$tableName]['tagName'] = $otherModelName.'/'.$tableName; - + foreach( $otherModel->findAll() as $pass ) { - foreach( $pass as $key=>$value ) + foreach( $pass as $key=>$value ) { - if( $key == $otherModelName && isset( $value['id'] ) && isset( $value[$otherDisplayField] ) ) + if( $key == $otherModelName && isset( $value['id'] ) && isset( $value[$otherDisplayField] ) ) { $fieldNames[$tableName]['options'][$value['id']] = $value[$otherDisplayField]; } @@ -717,11 +734,11 @@ class Controller extends Object } } // end loop through manytomany relations. } - - + + return $fieldNames; - } + } } ?> \ No newline at end of file diff --git a/libs/helpers/form.php b/libs/helpers/form.php index 7066c0a5c..b069f9d4c 100644 --- a/libs/helpers/form.php +++ b/libs/helpers/form.php @@ -170,6 +170,43 @@ class FormHelper } +/** + * Returns a formatted INPUT tag for HTML FORMs. + * + * @param HtmlHelper $html The HtmlHelper object which is creating this form. + * @param string $tagName If field is to be used for CRUD, this should be modelName/fieldName + * @param string $prompt Text that will appear in the label field. + * @param bool $required True if this field is required. + * @param string $errorMsg Text that will appear if an error has occurred. + * @param int $size Size attribute for INPUT element + * @param array $htmlOptions + * @return string The formatted INPUT element + */ + function generateCheckboxDiv($html, $tagName, $prompt, $required=false, $errorMsg=null, $htmlOptions=null ) + { + $htmlOptions['class'] = "inputCheckbox"; + $str = $html->checkbox( $tagName, null, $htmlOptions ); + $strLabel = $this->labelTag( $tagName, $prompt ); + + $divClass = "optional"; + + if( $required ) + $divClass = "required"; + + $strError = ""; // initialize the error to empty. + + if( $this->isFieldError( $html, $tagName ) ) + { + // if it was an error that occured, then add the error message, and append " error" to the div tag. + $strError = $this->pTag( 'error', $errorMsg ); + $divClass = sprintf( "%s error", $divClass ); + } + $divTagInside = sprintf( "%s %s %s", $strError, $strLabel, $str ); + + return $this->divTag( $divClass, $divTagInside ); + + } + function generateDate($html, $tagName, $prompt, $required=false, $errorMsg=null, $size=20, $htmlOptions=null ) { $str = $html->dateTimeOptionTag( $tagName, 'MDY' , 'NONE' ); @@ -337,7 +374,10 @@ class FormHelper { $field['size'] = 40; } - $strFormFields = $strFormFields.$this->generateInputDiv( $html, $field['tagName'], $field['prompt'], $field['required'], $field['errorMsg'], $field['size'], $field['htmlOptions'] ); + $strFormFields = $strFormFields.$this->generateInputDiv( $html, $field['tagName'], $field['prompt'], $field['required'], $field['errorMsg'], $field['size'], $field['htmlOptions'] ); + break; + case "checkbox" : + $strFormFields = $strFormFields.$this->generateCheckboxDiv( $html, $field['tagName'], $field['prompt'], $field['required'], $field['errorMsg'], $field['htmlOptions'] ); break; case "select"; case "selectMultiple"; diff --git a/libs/helpers/html.php b/libs/helpers/html.php index 2e67291ed..7365432dc 100644 --- a/libs/helpers/html.php +++ b/libs/helpers/html.php @@ -191,22 +191,32 @@ class HtmlHelper extends Helper function link($title, $url = null, $htmlAttributes = null, $confirmMessage = false, $return = false) { + // prepare title for html display + $title = htmlspecialchars($title, ENT_QUOTES); + $url = $url? $url: $title; if ($confirmMessage) { + // prepare for html display (fix everything except quotes) + $confirmMessage = htmlspecialchars($confirmMessage, ENT_NOQUOTES); + // fix single quotes + $confirmMessage = str_replace("'", "\'", $confirmMessage); + // fix double quotes + $confirmMessage = str_replace('"', '"', $confirmMessage); + $htmlAttributes['onclick'] = "return confirm('{$confirmMessage}');"; } if (strpos($url, '://')) { $output = sprintf($this->tags['link'], $url, - $this->_parseAttributes($htmlAttributes), $title); + $this->_parseAttributes($htmlAttributes), $title); } else { $output = sprintf($this->tags['link'], $this->url($url, true), - $this->_parseAttributes($htmlAttributes), $title); + $this->_parseAttributes($htmlAttributes), $title); } return $this->output($output, $return); @@ -393,9 +403,11 @@ class HtmlHelper extends Helper function hidden($fieldName, $htmlAttributes = null, $return = false) { $this->setFormTag($fieldName); - $htmlAttributes['value'] = $value? $value: $this->tagValue($fieldName); + if(!isset($htmlAttributes['value'])) { + $htmlAttributes['value'] = $this->tagValue($fieldName); + } return $this->output(sprintf($this->tags['hidden'], $this->model, $this->field, - $this->_parseAttributes($htmlAttributes, null, '', ' ')), $return); + $this->_parseAttributes($htmlAttributes, null, ' ', ' ')), $return); } @@ -976,30 +988,39 @@ class HtmlHelper extends Helper * * @param string $fieldName Name attribute of the SELECT * @param array $option_elements Array of the OPTION elements (as 'value'=>'Text' pairs) to be used in the SELECT element + * @param boolean $show_empty Show/hide the empty select option * @param array $select_attr Array of HTML options for the opening SELECT element * @param array $optionAttr Array of HTML options for the enclosed OPTION elements * @return string Formatted SELECT element */ - function selectTag($fieldName, $option_elements, $selected=null, $select_attr=null, $optionAttr=null) + function selectTag($fieldName, $option_elements, $selected=null, $select_attr=null, $optionAttr=null, $show_empty=false) { $this->setFormTag($fieldName); - if (!is_array($option_elements) || !count($option_elements)) - return null; + + // do not display the select tag if no option elements are avaible + if (!is_array($option_elements) || count($option_elements) == 0) + { + return null; + } if( isset($select_attr) && array_key_exists( "multiple", $select_attr) ) { $select[] = sprintf($this->tags['selectmultiplestart'], $this->model, $this->field, $this->parseHtmlOptions($select_attr)); } - else + else { $select[] = sprintf($this->tags['selectstart'], $this->model, $this->field, $this->parseHtmlOptions($select_attr)); } - $select[] = sprintf($this->tags['selectempty'], $this->parseHtmlOptions($optionAttr)); + + if($show_empty == true) + { + $select[] = sprintf($this->tags['selectempty'], $this->parseHtmlOptions($optionAttr)); + } foreach ($option_elements as $name=>$title) { $options_here = $optionAttr; - if ($selected == $name) + if (!empty($selected) && ($selected == $name)) { $options_here['selected'] = 'selected'; } else if ( is_array($selected) && array_key_exists($name, $selected) ) @@ -1370,4 +1391,4 @@ class HtmlHelper extends Helper } } -?> \ No newline at end of file +?> diff --git a/libs/model.php b/libs/model.php index 3ac07c234..68cc22803 100644 --- a/libs/model.php +++ b/libs/model.php @@ -967,7 +967,7 @@ class Model extends Object foreach ($this->data as $n=>$v) { - if(isset($weHaveMulti) && $count > 0) + if(isset($weHaveMulti) && $count > 0 && !empty($this->_manyToMany)) { $joined = array($v); } @@ -1333,29 +1333,34 @@ class Model extends Object { foreach ($value1 as $key2 => $value2) { - if(!empty ($value2['id'])) - { - $select[$table] = $this->db->all("SELECT * FROM {$table} - JOIN {$joineTable} ON {$joineTable}.{$joinKey1} = '$value2[id]' - AND {$joineTable}.{$JoinKey2} = {$table} .id"); - } - if( is_array($select[$table]) && ($select[$table] != null)) - { - $newKey = Inflector::singularize($table); - foreach ($select[$table] as $key => $value) - { + if( 0 == strncmp($key2, $joinKey1, strlen($key2)) ) + { + if(!empty ($value2['id'])) + { + $tmpSQL = "SELECT * FROM {$table} + JOIN {$joineTable} ON {$joineTable}.{$joinKey1} = '$value2[id]' + AND {$joineTable}.{$JoinKey2} = {$table} .id"; + $select[$table] = $this->db->all($tmpSQL); + } + if( is_array($select[$table]) && ($select[$table] != null)) + { + $newKey = Inflector::singularize($table); + foreach ($select[$table] as $key => $value) + { $select1[$table][$key] = $value[$newKey]; - } - - $merged = array_merge_recursive($data[$count],$select1); - $newdata[$count] = $merged; - unset ($select1); - } - - if(!empty($newdata[$count])) - { - $original[$count] = $newdata[$count]; - } + } + + $merged = array_merge_recursive($data[$count],$select1); + $newdata[$count] = $merged; + unset ($select1); + unset( $select[$table] ); + } + + if(!empty($newdata[$count])) + { + $original[$count] = $newdata[$count]; + } + } } $count++; } diff --git a/libs/scaffold.php b/libs/scaffold.php index 584faf570..75348f221 100644 --- a/libs/scaffold.php +++ b/libs/scaffold.php @@ -162,8 +162,9 @@ class Scaffold extends Object { */ function scaffoldList($params) { + $model = $this->model; $this->controllerClass->set('fieldNames', $this->controllerClass->generateFieldNames(null,false) ); - $this->controllerClass->set('data', $this->controllerClass->models[$this->model]->findAll()); + $this->controllerClass->set('data', $this->controllerClass->models[$model]->findAll()); $this->controllerClass->render($this->actionView, '', LIBS.'controllers'.DS.'templates'.DS.'scaffolds'.DS.'list.thtml'); } @@ -201,7 +202,7 @@ class Scaffold extends Object { function scaffoldCreate($params) { $this->controllerClass->set('fieldNames', $this->controllerClass->generateFieldNames() ); - $this->cleanUpDateFields(); + $this->cleanUpFields(); if ($this->controllerClass->models[$this->model]->save($this->controllerClass->params['data'])) { @@ -223,7 +224,7 @@ class Scaffold extends Object { function scaffoldUpdate($params=array()) { // clean up the date fields - $this->cleanUpDateFields(); + $this->cleanUpFields(); $this->controllerClass->models[$this->model]->set($this->controllerClass->params['data']); if ( $this->controllerClass->models[$this->model]->save()) @@ -257,7 +258,7 @@ class Scaffold extends Object { } } - function cleanUpDateFields() + function cleanUpFields() { // clean up the date fields $objModel = $this->controllerClass->models[$this->model]; @@ -290,6 +291,18 @@ class Scaffold extends Object { $newDate = date( 'Y-m-d', $newDate ); $this->controllerClass->params['data'][$this->model][$field['name']] = $newDate; } + else if( 'tinyint(1)' == $field['type'] ) + { + if( isset( $this->controllerClass->params['data'][$this->model][$field['name']]) && + "on" == $this->controllerClass->params['data'][$this->model][$field['name']] ) + { + $this->controllerClass->params['data'][$this->model][$field['name']] = true; + } + else + { + $this->controllerClass->params['data'][$this->model][$field['name']] = false; + } + } } } } diff --git a/public/css/forms.css b/public/css/forms.css index 314f8cabd..0a098d095 100644 --- a/public/css/forms.css +++ b/public/css/forms.css @@ -197,12 +197,14 @@ form div input.inputCheckbox, form div input.inputRadio, input.inputCheckbox, in background-color: transparent; border-width: 0px; padding: 0px; - margin: 0px 0px 0px 140px; + margin: 0px 0px 0px 0px; } form div.submit { width: 214px; padding: 0px 0px 0px 140px; + clear:both; + display:block; } div.submit input { @@ -327,6 +329,10 @@ div.date select { width:auto; } +select.autoWidth { + width:auto; +} + option { padding-left:1em; } \ No newline at end of file diff --git a/public/css/scaffold.css b/public/css/scaffold.css index 0a7afc5c2..07d94af7a 100644 --- a/public/css/scaffold.css +++ b/public/css/scaffold.css @@ -16,6 +16,7 @@ font-size:1.7em; color: #383; clear: both; } + h3 { font-size:1.4em; color: #553; diff --git a/tests/index.php b/tests/index.php index 0b78cfa38..03f591c0e 100644 --- a/tests/index.php +++ b/tests/index.php @@ -71,6 +71,9 @@ echo $header; function CakePHPTestSuiteHeader() { + $groups = class_exists('Object') ? 'groups' : $_SERVER['PHP_SELF'].'?show=groups'; + $cases = class_exists('Object') ? 'cases' : $_SERVER['PHP_SELF'].'?show=cases'; + $suiteHeader = << -

Test Groups || Test Cases

+

Test Groups || Test Cases

EOD; echo $suiteHeader; } - function CakePHPTestSuiteFooter() { $footer = <<