From 6ec0afcf5d813382964798944893ee5db7f0574c Mon Sep 17 00:00:00 2001 From: Ceeram Date: Mon, 25 Jun 2012 17:34:30 +0200 Subject: [PATCH 001/256] Add CakeNumber::fromReadableSize() and Validation::filesize() --- .../Console/Command/Task/ModelTaskTest.php | 4 +- lib/Cake/Test/Case/Utility/CakeNumberTest.php | 39 +++++++++++++++++++ lib/Cake/Test/Case/Utility/ValidationTest.php | 21 +++++++++- lib/Cake/Utility/CakeNumber.php | 22 +++++++++++ lib/Cake/Utility/Validation.php | 22 +++++++++++ 5 files changed, 105 insertions(+), 3 deletions(-) diff --git a/lib/Cake/Test/Case/Console/Command/Task/ModelTaskTest.php b/lib/Cake/Test/Case/Console/Command/Task/ModelTaskTest.php index 2e3c5d9d1..9f7479d29 100644 --- a/lib/Cake/Test/Case/Console/Command/Task/ModelTaskTest.php +++ b/lib/Cake/Test/Case/Console/Command/Task/ModelTaskTest.php @@ -315,7 +315,7 @@ class ModelTaskTest extends CakeTestCase { $this->Task->initValidations(); $this->Task->interactive = true; $this->Task->expects($this->any())->method('in') - ->will($this->onConsecutiveCalls('23', 'y', '17', 'n')); + ->will($this->onConsecutiveCalls('24', 'y', '18', 'n')); $result = $this->Task->fieldValidation('text', array('type' => 'string', 'length' => 10, 'null' => false)); $expected = array('notempty' => 'notempty', 'maxlength' => 'maxlength'); @@ -333,7 +333,7 @@ class ModelTaskTest extends CakeTestCase { $this->Task->interactive = true; $this->Task->expects($this->any())->method('in') - ->will($this->onConsecutiveCalls('999999', '23', 'n')); + ->will($this->onConsecutiveCalls('999999', '24', 'n')); $this->Task->expects($this->at(10))->method('out') ->with($this->stringContains('make a valid')); diff --git a/lib/Cake/Test/Case/Utility/CakeNumberTest.php b/lib/Cake/Test/Case/Utility/CakeNumberTest.php index bcae41d85..25737679f 100644 --- a/lib/Cake/Test/Case/Utility/CakeNumberTest.php +++ b/lib/Cake/Test/Case/Utility/CakeNumberTest.php @@ -523,4 +523,43 @@ class CakeNumberTest extends CakeTestCase { $this->assertEquals($expected, $result); } +/** + * testFromReadableSize + * + * @dataProvider filesizes + * @return void + */ + public function testFromReadableSize($size, $expected) { + $result = $this->Number->fromReadableSize($size); + $this->assertEquals($expected, $result); + } + +/** + * testFromReadableSize + * + * @expectedException CakeException + * @return void + */ + public function testFromReadableSizeException() { + $result = $this->Number->fromReadableSize('bogus'); + } + +/** + * filesizes dataprovider + * + * @return array + */ + public function filesizes() { + return array( + array('512B', 512), + array('1KB', 1024), + array('1.5KB', 1536), + array('1MB', 1048576), + array('1.5MB', 1572864), + array('1GB', 1073741824), + array('1.5GB', 1610612736), + array('512', 512), + ); + } + } diff --git a/lib/Cake/Test/Case/Utility/ValidationTest.php b/lib/Cake/Test/Case/Utility/ValidationTest.php index a3f98f9fd..887123cd4 100644 --- a/lib/Cake/Test/Case/Utility/ValidationTest.php +++ b/lib/Cake/Test/Case/Utility/ValidationTest.php @@ -2203,7 +2203,7 @@ class ValidationTest extends CakeTestCase { } /** - * testMimeType method + * testUploadError method * * @return void */ @@ -2214,4 +2214,23 @@ class ValidationTest extends CakeTestCase { $this->assertFalse(Validation::uploadError(2)); $this->assertFalse(Validation::uploadError(array('error' => 2))); } + +/** + * testFileSize method + * + * @return void + */ + public function testFileSize() { + $image = CORE_PATH . 'Cake' . DS . 'Test' . DS . 'test_app' . DS . 'webroot' . DS . 'img' . DS . 'cake.power.gif'; + $this->assertTrue(Validation::fileSize($image, '<', 1024)); + $this->assertTrue(Validation::fileSize(array('tmp_name' => $image), 'isless', 1024)); + $this->assertTrue(Validation::fileSize($image, '<', '1KB')); + $this->assertTrue(Validation::fileSize($image, '>=', 200)); + $this->assertTrue(Validation::fileSize($image, '==', 201)); + $this->assertTrue(Validation::fileSize($image, '==', '201B')); + + $this->assertFalse(Validation::fileSize($image, 'isgreater', 1024)); + $this->assertFalse(Validation::fileSize(array('tmp_name' => $image), '>', '1KB')); + } + } diff --git a/lib/Cake/Utility/CakeNumber.php b/lib/Cake/Utility/CakeNumber.php index 3b21cbc36..d12b4f90a 100644 --- a/lib/Cake/Utility/CakeNumber.php +++ b/lib/Cake/Utility/CakeNumber.php @@ -101,6 +101,28 @@ class CakeNumber { } } +/** + * Converts filesize from human readable string to bytes + * + * @param string $size Size in human readable string like '5MB' + * @return integer Bytes + */ + public static function fromReadableSize($size) { + if (ctype_digit($size)) { + return $size * 1; + } + $units = array('KB', 'MB', 'GB', 'TB', 'PB'); + foreach ($units as $i => $unit) { + if ($unit == substr($size, -2)) { + return $size * pow(1024, $i + 1); + } + } + if (substr($size, -1) == 'B' && ctype_digit(substr($size, 0, strlen($size) - 1))) { + return $size * 1; + } + throw new CakeException(__d('cake_dev', 'No unit type.')); + } + /** * Formats a number into a percentage string. * diff --git a/lib/Cake/Utility/Validation.php b/lib/Cake/Utility/Validation.php index d08c227ae..9a3805626 100644 --- a/lib/Cake/Utility/Validation.php +++ b/lib/Cake/Utility/Validation.php @@ -19,6 +19,7 @@ App::uses('Multibyte', 'I18n'); App::uses('File', 'Utility'); +App::uses('CakeNumber', 'Utility'); // Load multibyte if the extension is missing. if (!function_exists('mb_strlen')) { class_exists('Multibyte'); @@ -881,6 +882,27 @@ class Validation { return in_array($mime, $mimeTypes); } +/** + * Checks the filesize + * + * @param string|array $check + * @param integer|string $size Size in bytes or human readable string like '5MB' + * @param string $operator See `Validation::comparison()` + * @return boolean Success + */ + public static function fileSize($check, $operator = null, $size = null) { + if (is_array($check) && isset($check['tmp_name'])) { + $check = $check['tmp_name']; + } + + if (is_string($size)) { + $size = CakeNumber::fromReadableSize($size); + } + $filesize = filesize($check); + + return self::comparison($filesize, $operator, $size); + } + /** * Checking for upload errors * From 4db909bd2daeef826d371108474f16b65f50c19e Mon Sep 17 00:00:00 2001 From: Ceeram Date: Mon, 2 Jul 2012 12:19:00 +0200 Subject: [PATCH 002/256] update version.txt to 2.3.0-dev --- lib/Cake/VERSION.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/VERSION.txt b/lib/Cake/VERSION.txt index e7ba0f1cc..012deb2ad 100644 --- a/lib/Cake/VERSION.txt +++ b/lib/Cake/VERSION.txt @@ -17,4 +17,4 @@ // @license MIT License (http://www.opensource.org/licenses/mit-license.php) // +--------------------------------------------------------------------------------------------+ // //////////////////////////////////////////////////////////////////////////////////////////////////// -2.2.0-RC2 +2.3.0-dev From 8a09b3d454886e97d6f13dc57f6a1694469b31a7 Mon Sep 17 00:00:00 2001 From: AD7six Date: Tue, 3 Jul 2012 16:07:57 +0200 Subject: [PATCH 003/256] update mimetype map References: http://www.iana.org/assignments/media-types/application/index.html http://www.iana.org/assignments/media-types/audio/index.html https://github.com/h5bp/html5-boilerplate/blob/master/.htaccess#L86 --- lib/Cake/Network/CakeResponse.php | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/Cake/Network/CakeResponse.php b/lib/Cake/Network/CakeResponse.php index a763705bc..81bcb9191 100644 --- a/lib/Cake/Network/CakeResponse.php +++ b/lib/Cake/Network/CakeResponse.php @@ -114,10 +114,10 @@ class CakeResponse { '7z' => 'application/x-7z-compressed', 'hdf' => 'application/x-hdf', 'hqx' => 'application/mac-binhex40', - 'ico' => 'image/vnd.microsoft.icon', + 'ico' => 'image/x-icon', 'ips' => 'application/x-ipscript', 'ipx' => 'application/x-ipix', - 'js' => 'text/javascript', + 'js' => 'application/javascript', 'latex' => 'application/x-latex', 'lha' => 'application/octet-stream', 'lsp' => 'application/x-lisp', @@ -169,6 +169,7 @@ class CakeResponse { 'texinfo' => 'application/x-texinfo', 'tr' => 'application/x-troff', 'tsp' => 'application/dsptype', + 'ttc' => 'font/ttf', 'ttf' => 'font/ttf', 'unv' => 'application/i-deas', 'ustar' => 'application/x-ustar', @@ -234,6 +235,12 @@ class CakeResponse { 'ogv' => 'video/ogg', 'webm' => 'video/webm', 'mp4' => 'video/mp4', + 'm4v' => 'video/mp4', + 'f4v' => 'video/mp4', + 'f4p' => 'video/mp4', + 'm4a' => 'audio/mp4', + 'f4a' => 'audio/mp4', + 'f4b' => 'audio/mp4', 'gif' => 'image/gif', 'ief' => 'image/ief', 'jpe' => 'image/jpeg', @@ -262,7 +269,7 @@ class CakeResponse { 'mime' => 'www/mime', 'pdb' => 'chemical/x-pdb', 'xyz' => 'chemical/x-pdb', - 'javascript' => 'text/javascript', + 'javascript' => 'application/javascript', 'form' => 'application/x-www-form-urlencoded', 'file' => 'multipart/form-data', 'xhtml' => array('application/xhtml+xml', 'application/xhtml', 'text/xhtml'), @@ -273,6 +280,19 @@ class CakeResponse { 'wml' => 'text/vnd.wap.wml', 'wmlscript' => 'text/vnd.wap.wmlscript', 'wbmp' => 'image/vnd.wap.wbmp', + 'woff' => 'application/x-font-woff', + 'webp' => 'image/webp', + 'appcache' => 'text/cache-manifest', + 'manifest' => 'text/cache-manifest', + 'htc' => 'text/x-component', + 'rdf' => 'application/xml', + 'crx' => 'application/x-chrome-extension', + 'oex' => 'application/x-opera-extension', + 'xpi' => 'application/x-xpinstall', + 'safariextz' => 'application/octet-stream', + 'webapp' => 'application/x-web-app-manifest+json', + 'vcf' => 'text/x-vcard', + 'vtt' => 'text/vtt', ); /** From 90ae2df38ea85fea1a52aaeb83c917085dda5a7f Mon Sep 17 00:00:00 2001 From: AD7six Date: Tue, 3 Jul 2012 16:12:48 +0200 Subject: [PATCH 004/256] sort the mimeTypes map alphabetically except for html which is at the top. Easier maintainance --- lib/Cake/Network/CakeResponse.php | 230 +++++++++++++++--------------- 1 file changed, 115 insertions(+), 115 deletions(-) diff --git a/lib/Cake/Network/CakeResponse.php b/lib/Cake/Network/CakeResponse.php index 81bcb9191..835a80d24 100644 --- a/lib/Cake/Network/CakeResponse.php +++ b/lib/Cake/Network/CakeResponse.php @@ -81,18 +81,31 @@ class CakeResponse { */ protected $_mimeTypes = array( 'html' => array('text/html', '*/*'), - 'json' => 'application/json', - 'xml' => array('application/xml', 'text/xml'), - 'rss' => 'application/rss+xml', + '7z' => 'application/x-7z-compressed', + 'aac' => 'audio/aac', 'ai' => 'application/postscript', + 'aif' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'amf' => 'application/x-amf', + 'appcache' => 'text/cache-manifest', + 'asc' => 'text/plain', + 'atom' => 'application/atom+xml', + 'au' => 'audio/basic', + 'avi' => 'video/x-msvideo', 'bcpio' => 'application/x-bcpio', 'bin' => 'application/octet-stream', + 'bz2' => 'application/x-bzip', + 'c' => 'text/plain', + 'cc' => 'text/plain', 'ccad' => 'application/clariscad', 'cdf' => 'application/x-netcdf', 'class' => 'application/octet-stream', 'cpio' => 'application/x-cpio', 'cpt' => 'application/mac-compactpro', + 'crx' => 'application/x-chrome-extension', 'csh' => 'application/x-csh', + 'css' => 'text/css', 'csv' => array('text/csv', 'application/vnd.ms-excel', 'text/plain'), 'dcr' => 'application/x-director', 'dir' => 'application/x-director', @@ -105,44 +118,111 @@ class CakeResponse { 'dxr' => 'application/x-director', 'eot' => 'application/vnd.ms-fontobject', 'eps' => 'application/postscript', + 'etx' => 'text/x-setext', 'exe' => 'application/octet-stream', 'ez' => 'application/andrew-inset', + 'f' => 'text/plain', + 'f4a' => 'audio/mp4', + 'f4b' => 'audio/mp4', + 'f4p' => 'video/mp4', + 'f4v' => 'video/mp4', + 'f90' => 'text/plain', + 'file' => 'multipart/form-data', + 'fli' => 'video/x-fli', 'flv' => 'video/x-flv', + 'form' => 'application/x-www-form-urlencoded', + 'gif' => 'image/gif', 'gtar' => 'application/x-gtar', 'gz' => 'application/x-gzip', - 'bz2' => 'application/x-bzip', - '7z' => 'application/x-7z-compressed', + 'h' => 'text/plain', 'hdf' => 'application/x-hdf', + 'hh' => 'text/plain', 'hqx' => 'application/mac-binhex40', + 'htc' => 'text/x-component', + 'htm' => array('text/html', '*/*'), + 'ice' => 'x-conference/x-cooltalk', 'ico' => 'image/x-icon', + 'ics' => 'text/calendar', + 'ief' => 'image/ief', + 'iges' => 'model/iges', + 'igs' => 'model/iges', 'ips' => 'application/x-ipscript', 'ipx' => 'application/x-ipix', + 'javascript' => 'application/javascript', + 'jpe' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', 'js' => 'application/javascript', + 'json' => 'application/json', + 'kar' => 'audio/midi', 'latex' => 'application/x-latex', 'lha' => 'application/octet-stream', 'lsp' => 'application/x-lisp', 'lzh' => 'application/octet-stream', + 'm' => 'text/plain', + 'm4a' => 'audio/mp4', + 'm4v' => 'video/mp4', 'man' => 'application/x-troff-man', + 'manifest' => 'text/cache-manifest', 'me' => 'application/x-troff-me', + 'mesh' => 'model/mesh', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', 'mif' => 'application/vnd.mif', + 'mime' => 'www/mime', + 'mov' => 'video/quicktime', + 'movie' => 'video/x-sgi-movie', + 'mp2' => 'audio/mpeg', + 'mp3' => 'audio/mpeg', + 'mp4' => 'video/mp4', + 'mpe' => 'video/mpeg', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'mpga' => 'audio/mpeg', 'ms' => 'application/x-troff-ms', + 'msh' => 'model/mesh', 'nc' => 'application/x-netcdf', 'oda' => 'application/oda', + 'oex' => 'application/x-opera-extension', + 'oga' => 'audio/ogg', + 'ogg' => 'audio/ogg', + 'ogv' => 'video/ogg', 'otf' => 'font/otf', + 'pbm' => 'image/x-portable-bitmap', + 'pdb' => 'chemical/x-pdb', 'pdf' => 'application/pdf', + 'pgm' => 'image/x-portable-graymap', 'pgn' => 'application/x-chess-pgn', + 'png' => 'image/png', + 'pnm' => 'image/x-portable-anymap', 'pot' => 'application/mspowerpoint', + 'ppm' => 'image/x-portable-pixmap', 'pps' => 'application/mspowerpoint', 'ppt' => 'application/mspowerpoint', 'ppz' => 'application/mspowerpoint', 'pre' => 'application/x-freelance', 'prt' => 'application/pro_eng', 'ps' => 'application/postscript', + 'qt' => 'video/quicktime', + 'ra' => 'audio/x-realaudio', + 'ram' => 'audio/x-pn-realaudio', + 'ras' => 'image/cmu-raster', + 'rdf' => 'application/xml', + 'rgb' => 'image/x-rgb', + 'rm' => 'audio/x-pn-realaudio', 'roff' => 'application/x-troff', + 'rpm' => 'audio/x-pn-realaudio-plugin', + 'rss' => 'application/rss+xml', + 'rtf' => 'text/rtf', + 'rtx' => 'text/richtext', + 'safariextz' => 'application/octet-stream', 'scm' => 'application/x-lotusscreencam', 'set' => 'application/set', + 'sgm' => 'text/sgml', + 'sgml' => 'text/sgml', 'sh' => 'application/x-sh', 'shar' => 'application/x-shar', + 'silo' => 'model/mesh', 'sit' => 'application/x-stuffit', 'skd' => 'application/x-koan', 'skm' => 'application/x-koan', @@ -150,8 +230,10 @@ class CakeResponse { 'skt' => 'application/x-koan', 'smi' => 'application/smil', 'smil' => 'application/smil', + 'snd' => 'audio/basic', 'sol' => 'application/solids', 'spl' => 'application/x-futuresplash', + 'spx' => 'audio/ogg', 'src' => 'application/x-wais-source', 'step' => 'application/STEP', 'stl' => 'application/SLA', @@ -167,132 +249,50 @@ class CakeResponse { 'tex' => 'application/x-tex', 'texi' => 'application/x-texinfo', 'texinfo' => 'application/x-texinfo', + 'text' => 'text/plain', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'tpl' => 'text/template', 'tr' => 'application/x-troff', + 'tsi' => 'audio/TSP-audio', 'tsp' => 'application/dsptype', + 'tsv' => 'text/tab-separated-values', 'ttc' => 'font/ttf', 'ttf' => 'font/ttf', + 'txt' => 'text/plain', 'unv' => 'application/i-deas', 'ustar' => 'application/x-ustar', 'vcd' => 'application/x-cdlink', + 'vcf' => 'text/x-vcard', 'vda' => 'application/vda', + 'viv' => 'video/vnd.vivo', + 'vivo' => 'video/vnd.vivo', + 'vrml' => 'model/vrml', + 'vtt' => 'text/vtt', + 'wap' => array('text/vnd.wap.wml', 'text/vnd.wap.wmlscript', 'image/vnd.wap.wbmp'), + 'wav' => 'audio/x-wav', + 'wbmp' => 'image/vnd.wap.wbmp', + 'webapp' => 'application/x-web-app-manifest+json', + 'webm' => 'video/webm', + 'webp' => 'image/webp', + 'wml' => 'text/vnd.wap.wml', + 'wmlscript' => 'text/vnd.wap.wmlscript', + 'woff' => 'application/x-font-woff', + 'wrl' => 'model/vrml', + 'xbm' => 'image/x-xbitmap', + 'xhtml' => array('application/xhtml+xml', 'application/xhtml', 'text/xhtml'), + 'xhtml-mobile' => 'application/vnd.wap.xhtml+xml', 'xlc' => 'application/vnd.ms-excel', 'xll' => 'application/vnd.ms-excel', 'xlm' => 'application/vnd.ms-excel', 'xls' => 'application/vnd.ms-excel', 'xlw' => 'application/vnd.ms-excel', - 'zip' => 'application/zip', - 'aif' => 'audio/x-aiff', - 'aifc' => 'audio/x-aiff', - 'aiff' => 'audio/x-aiff', - 'au' => 'audio/basic', - 'kar' => 'audio/midi', - 'mid' => 'audio/midi', - 'midi' => 'audio/midi', - 'mp2' => 'audio/mpeg', - 'mp3' => 'audio/mpeg', - 'mpga' => 'audio/mpeg', - 'ogg' => 'audio/ogg', - 'oga' => 'audio/ogg', - 'spx' => 'audio/ogg', - 'ra' => 'audio/x-realaudio', - 'ram' => 'audio/x-pn-realaudio', - 'rm' => 'audio/x-pn-realaudio', - 'rpm' => 'audio/x-pn-realaudio-plugin', - 'snd' => 'audio/basic', - 'tsi' => 'audio/TSP-audio', - 'wav' => 'audio/x-wav', - 'aac' => 'audio/aac', - 'asc' => 'text/plain', - 'c' => 'text/plain', - 'cc' => 'text/plain', - 'css' => 'text/css', - 'etx' => 'text/x-setext', - 'f' => 'text/plain', - 'f90' => 'text/plain', - 'h' => 'text/plain', - 'hh' => 'text/plain', - 'htm' => array('text/html', '*/*'), - 'ics' => 'text/calendar', - 'm' => 'text/plain', - 'rtf' => 'text/rtf', - 'rtx' => 'text/richtext', - 'sgm' => 'text/sgml', - 'sgml' => 'text/sgml', - 'tsv' => 'text/tab-separated-values', - 'tpl' => 'text/template', - 'txt' => 'text/plain', - 'text' => 'text/plain', - 'avi' => 'video/x-msvideo', - 'fli' => 'video/x-fli', - 'mov' => 'video/quicktime', - 'movie' => 'video/x-sgi-movie', - 'mpe' => 'video/mpeg', - 'mpeg' => 'video/mpeg', - 'mpg' => 'video/mpeg', - 'qt' => 'video/quicktime', - 'viv' => 'video/vnd.vivo', - 'vivo' => 'video/vnd.vivo', - 'ogv' => 'video/ogg', - 'webm' => 'video/webm', - 'mp4' => 'video/mp4', - 'm4v' => 'video/mp4', - 'f4v' => 'video/mp4', - 'f4p' => 'video/mp4', - 'm4a' => 'audio/mp4', - 'f4a' => 'audio/mp4', - 'f4b' => 'audio/mp4', - 'gif' => 'image/gif', - 'ief' => 'image/ief', - 'jpe' => 'image/jpeg', - 'jpeg' => 'image/jpeg', - 'jpg' => 'image/jpeg', - 'pbm' => 'image/x-portable-bitmap', - 'pgm' => 'image/x-portable-graymap', - 'png' => 'image/png', - 'pnm' => 'image/x-portable-anymap', - 'ppm' => 'image/x-portable-pixmap', - 'ras' => 'image/cmu-raster', - 'rgb' => 'image/x-rgb', - 'tif' => 'image/tiff', - 'tiff' => 'image/tiff', - 'xbm' => 'image/x-xbitmap', + 'xml' => array('application/xml', 'text/xml'), + 'xpi' => 'application/x-xpinstall', 'xpm' => 'image/x-xpixmap', 'xwd' => 'image/x-xwindowdump', - 'ice' => 'x-conference/x-cooltalk', - 'iges' => 'model/iges', - 'igs' => 'model/iges', - 'mesh' => 'model/mesh', - 'msh' => 'model/mesh', - 'silo' => 'model/mesh', - 'vrml' => 'model/vrml', - 'wrl' => 'model/vrml', - 'mime' => 'www/mime', - 'pdb' => 'chemical/x-pdb', 'xyz' => 'chemical/x-pdb', - 'javascript' => 'application/javascript', - 'form' => 'application/x-www-form-urlencoded', - 'file' => 'multipart/form-data', - 'xhtml' => array('application/xhtml+xml', 'application/xhtml', 'text/xhtml'), - 'xhtml-mobile' => 'application/vnd.wap.xhtml+xml', - 'atom' => 'application/atom+xml', - 'amf' => 'application/x-amf', - 'wap' => array('text/vnd.wap.wml', 'text/vnd.wap.wmlscript', 'image/vnd.wap.wbmp'), - 'wml' => 'text/vnd.wap.wml', - 'wmlscript' => 'text/vnd.wap.wmlscript', - 'wbmp' => 'image/vnd.wap.wbmp', - 'woff' => 'application/x-font-woff', - 'webp' => 'image/webp', - 'appcache' => 'text/cache-manifest', - 'manifest' => 'text/cache-manifest', - 'htc' => 'text/x-component', - 'rdf' => 'application/xml', - 'crx' => 'application/x-chrome-extension', - 'oex' => 'application/x-opera-extension', - 'xpi' => 'application/x-xpinstall', - 'safariextz' => 'application/octet-stream', - 'webapp' => 'application/x-web-app-manifest+json', - 'vcf' => 'text/x-vcard', - 'vtt' => 'text/vtt', + 'zip' => 'application/zip', ); /** From ca9ff0283ce6d994cc4fafaeda4a6b104d29c5a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Kr=C3=A4mer?= Date: Wed, 4 Jul 2012 11:48:10 +0200 Subject: [PATCH 005/256] Refactoring View::element() --- lib/Cake/View/View.php | 109 ++++++++++++++++++++++++++--------------- 1 file changed, 69 insertions(+), 40 deletions(-) diff --git a/lib/Cake/View/View.php b/lib/Cake/View/View.php index 59ce0aca4..906434efa 100644 --- a/lib/Cake/View/View.php +++ b/lib/Cake/View/View.php @@ -219,6 +219,14 @@ class View extends Object { */ public $elementCache = 'default'; +/** + * Element cache settings + * + * @see View::_elementCache(); + * @see View::_renderElement + */ + public $elementCacheSettings = array(); + /** * List of variables to collect from the associated controller. * @@ -375,62 +383,28 @@ class View extends Object { * `Plugin.element_name` instead. */ public function element($name, $data = array(), $options = array()) { - $file = $plugin = $key = null; - $callbacks = false; + $file = $plugin = null; if (isset($options['plugin'])) { $name = Inflector::camelize($options['plugin']) . '.' . $name; } - if (isset($options['callbacks'])) { - $callbacks = $options['callbacks']; + if (!isset($options['callbacks'])) { + $options['callbacks'] = false; } if (isset($options['cache'])) { - $underscored = null; - if ($plugin) { - $underscored = Inflector::underscore($plugin); - } - $keys = array_merge(array($underscored, $name), array_keys($options), array_keys($data)); - $caching = array( - 'config' => $this->elementCache, - 'key' => implode('_', $keys) - ); - if (is_array($options['cache'])) { - $defaults = array( - 'config' => $this->elementCache, - 'key' => $caching['key'] - ); - $caching = array_merge($defaults, $options['cache']); - } - $key = 'element_' . $caching['key']; - $contents = Cache::read($key, $caching['config']); + $contents = $this->_elementCache($name, $plugin, $options); if ($contents !== false) { return $contents; } } $file = $this->_getElementFilename($name); - if ($file) { - if (!$this->_helpersLoaded) { - $this->loadHelpers(); - } - if ($callbacks) { - $this->getEventManager()->dispatch(new CakeEvent('View.beforeRender', $this, array($file))); - } - - $this->_currentType = self::TYPE_ELEMENT; - $element = $this->_render($file, array_merge($this->viewVars, $data)); - - if ($callbacks) { - $this->getEventManager()->dispatch(new CakeEvent('View.afterRender', $this, array($file, $element))); - } - if (isset($options['cache'])) { - Cache::write($key, $element, $caching['config']); - } - return $element; + return $this->_renderElement($file, $data, $options); } + $file = 'Elements' . DS . $name . $this->ext; if (Configure::read('debug') > 0) { @@ -1126,4 +1100,59 @@ class View extends Object { return $this->_paths = $paths; } +/** + * Checks if an element is cached and returns the cached data if present + * + * @param string $name Element name + * @param string $plugin Plugin name + * @param array $options Element options + */ + protected function _elementCache($name, $plugin, $options) { + $underscored = null; + if ($plugin) { + $underscored = Inflector::underscore($plugin); + } + $keys = array_merge(array($underscored, $name), array_keys($options), array_keys($data)); + $this->elementCacheSettings = array( + 'config' => $this->elementCache, + 'key' => implode('_', $keys) + ); + if (is_array($options['cache'])) { + $defaults = array( + 'config' => $this->elementCache, + 'key' => $this->elementCacheSettings['key'] + ); + $this->elementCacheSettings = array_merge($defaults, $options['cache']); + } + $key = 'element_' . $this->elementCacheSettings['key']; + return = Cache::read($key, $this->elementCacheSettings['config']); + } + +/** + * Renders an element and fires the before and afterRender callbacks for it + * and writes to the cache if a cache is used + * + * @param string $file Element file path + * @param array $data Data to render + * @param array $options Element options + */ + protected function _renderElement($file, $data, $options) { + if (!$this->_helpersLoaded) { + $this->loadHelpers(); + } + if ($callbacks) { + $this->getEventManager()->dispatch(new CakeEvent('View.beforeRender', $this, array($file))); + } + + $this->_currentType = self::TYPE_ELEMENT; + $element = $this->_render($file, array_merge($this->viewVars, $data)); + + if (isset($options['callbacks'])) { + $this->getEventManager()->dispatch(new CakeEvent('View.afterRender', $this, array($file, $element))); + } + if (isset($options['cache'])) { + Cache::write($key, $element, $this->elementCacheSettings['config']); + } + return $element; + } } From b2bb7bf2ae32b12f958e556524aa7fee5890723c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Kr=C3=A4mer?= Date: Fri, 6 Jul 2012 00:22:39 +0200 Subject: [PATCH 006/256] Fixing a few issues within the new methods --- lib/Cake/View/View.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/Cake/View/View.php b/lib/Cake/View/View.php index 906434efa..e6deab5ca 100644 --- a/lib/Cake/View/View.php +++ b/lib/Cake/View/View.php @@ -394,7 +394,7 @@ class View extends Object { } if (isset($options['cache'])) { - $contents = $this->_elementCache($name, $plugin, $options); + $contents = $this->_elementCache($name, $plugin, $data, $options); if ($contents !== false) { return $contents; } @@ -1107,7 +1107,7 @@ class View extends Object { * @param string $plugin Plugin name * @param array $options Element options */ - protected function _elementCache($name, $plugin, $options) { + protected function _elementCache($name, $plugin, $data, $options) { $underscored = null; if ($plugin) { $underscored = Inflector::underscore($plugin); @@ -1124,8 +1124,8 @@ class View extends Object { ); $this->elementCacheSettings = array_merge($defaults, $options['cache']); } - $key = 'element_' . $this->elementCacheSettings['key']; - return = Cache::read($key, $this->elementCacheSettings['config']); + $this->elementCacheSettings['key'] = 'element_' . $this->elementCacheSettings['key']; + return Cache::read($this->elementCacheSettings['key'], $this->elementCacheSettings['config']); } /** @@ -1140,7 +1140,7 @@ class View extends Object { if (!$this->_helpersLoaded) { $this->loadHelpers(); } - if ($callbacks) { + if ($options['callbacks']) { $this->getEventManager()->dispatch(new CakeEvent('View.beforeRender', $this, array($file))); } @@ -1151,7 +1151,7 @@ class View extends Object { $this->getEventManager()->dispatch(new CakeEvent('View.afterRender', $this, array($file, $element))); } if (isset($options['cache'])) { - Cache::write($key, $element, $this->elementCacheSettings['config']); + Cache::write($this->elementCacheSettings['key'], $element, $this->elementCacheSettings['config']); } return $element; } From 83903cd5b493056d1f27ba364eae01d717c34639 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Florian=20Kr=C3=A4mer?= Date: Fri, 6 Jul 2012 02:13:34 +0200 Subject: [PATCH 007/256] Changing the signature of View::_elementCache() --- lib/Cake/View/View.php | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/lib/Cake/View/View.php b/lib/Cake/View/View.php index e6deab5ca..2a65709ea 100644 --- a/lib/Cake/View/View.php +++ b/lib/Cake/View/View.php @@ -394,7 +394,7 @@ class View extends Object { } if (isset($options['cache'])) { - $contents = $this->_elementCache($name, $plugin, $data, $options); + $contents = $this->_elementCache($name, $data, $options); if ($contents !== false) { return $contents; } @@ -1107,7 +1107,10 @@ class View extends Object { * @param string $plugin Plugin name * @param array $options Element options */ - protected function _elementCache($name, $plugin, $data, $options) { + protected function _elementCache($name, $data, $options) { + $plugin = null; + list($plugin, $name) = $this->pluginSplit($name); + $underscored = null; if ($plugin) { $underscored = Inflector::underscore($plugin); From 790a53d7945a57f22876d907cbb835043cf54fc0 Mon Sep 17 00:00:00 2001 From: AD7six Date: Fri, 6 Jul 2012 12:23:20 +0200 Subject: [PATCH 008/256] Revert "sort the mimeTypes map alphabetically" This reverts commit 90ae2df38ea85fea1a52aaeb83c917085dda5a7f. The mime type is used by CakeResponse::mapType to determine which mime type maps to which alias. As this is done in the order of the mimetype map the mimetype map is order sensitive. --- lib/Cake/Network/CakeResponse.php | 230 +++++++++++++++--------------- 1 file changed, 115 insertions(+), 115 deletions(-) diff --git a/lib/Cake/Network/CakeResponse.php b/lib/Cake/Network/CakeResponse.php index 835a80d24..81bcb9191 100644 --- a/lib/Cake/Network/CakeResponse.php +++ b/lib/Cake/Network/CakeResponse.php @@ -81,31 +81,18 @@ class CakeResponse { */ protected $_mimeTypes = array( 'html' => array('text/html', '*/*'), - '7z' => 'application/x-7z-compressed', - 'aac' => 'audio/aac', + 'json' => 'application/json', + 'xml' => array('application/xml', 'text/xml'), + 'rss' => 'application/rss+xml', 'ai' => 'application/postscript', - 'aif' => 'audio/x-aiff', - 'aifc' => 'audio/x-aiff', - 'aiff' => 'audio/x-aiff', - 'amf' => 'application/x-amf', - 'appcache' => 'text/cache-manifest', - 'asc' => 'text/plain', - 'atom' => 'application/atom+xml', - 'au' => 'audio/basic', - 'avi' => 'video/x-msvideo', 'bcpio' => 'application/x-bcpio', 'bin' => 'application/octet-stream', - 'bz2' => 'application/x-bzip', - 'c' => 'text/plain', - 'cc' => 'text/plain', 'ccad' => 'application/clariscad', 'cdf' => 'application/x-netcdf', 'class' => 'application/octet-stream', 'cpio' => 'application/x-cpio', 'cpt' => 'application/mac-compactpro', - 'crx' => 'application/x-chrome-extension', 'csh' => 'application/x-csh', - 'css' => 'text/css', 'csv' => array('text/csv', 'application/vnd.ms-excel', 'text/plain'), 'dcr' => 'application/x-director', 'dir' => 'application/x-director', @@ -118,111 +105,44 @@ class CakeResponse { 'dxr' => 'application/x-director', 'eot' => 'application/vnd.ms-fontobject', 'eps' => 'application/postscript', - 'etx' => 'text/x-setext', 'exe' => 'application/octet-stream', 'ez' => 'application/andrew-inset', - 'f' => 'text/plain', - 'f4a' => 'audio/mp4', - 'f4b' => 'audio/mp4', - 'f4p' => 'video/mp4', - 'f4v' => 'video/mp4', - 'f90' => 'text/plain', - 'file' => 'multipart/form-data', - 'fli' => 'video/x-fli', 'flv' => 'video/x-flv', - 'form' => 'application/x-www-form-urlencoded', - 'gif' => 'image/gif', 'gtar' => 'application/x-gtar', 'gz' => 'application/x-gzip', - 'h' => 'text/plain', + 'bz2' => 'application/x-bzip', + '7z' => 'application/x-7z-compressed', 'hdf' => 'application/x-hdf', - 'hh' => 'text/plain', 'hqx' => 'application/mac-binhex40', - 'htc' => 'text/x-component', - 'htm' => array('text/html', '*/*'), - 'ice' => 'x-conference/x-cooltalk', 'ico' => 'image/x-icon', - 'ics' => 'text/calendar', - 'ief' => 'image/ief', - 'iges' => 'model/iges', - 'igs' => 'model/iges', 'ips' => 'application/x-ipscript', 'ipx' => 'application/x-ipix', - 'javascript' => 'application/javascript', - 'jpe' => 'image/jpeg', - 'jpeg' => 'image/jpeg', - 'jpg' => 'image/jpeg', 'js' => 'application/javascript', - 'json' => 'application/json', - 'kar' => 'audio/midi', 'latex' => 'application/x-latex', 'lha' => 'application/octet-stream', 'lsp' => 'application/x-lisp', 'lzh' => 'application/octet-stream', - 'm' => 'text/plain', - 'm4a' => 'audio/mp4', - 'm4v' => 'video/mp4', 'man' => 'application/x-troff-man', - 'manifest' => 'text/cache-manifest', 'me' => 'application/x-troff-me', - 'mesh' => 'model/mesh', - 'mid' => 'audio/midi', - 'midi' => 'audio/midi', 'mif' => 'application/vnd.mif', - 'mime' => 'www/mime', - 'mov' => 'video/quicktime', - 'movie' => 'video/x-sgi-movie', - 'mp2' => 'audio/mpeg', - 'mp3' => 'audio/mpeg', - 'mp4' => 'video/mp4', - 'mpe' => 'video/mpeg', - 'mpeg' => 'video/mpeg', - 'mpg' => 'video/mpeg', - 'mpga' => 'audio/mpeg', 'ms' => 'application/x-troff-ms', - 'msh' => 'model/mesh', 'nc' => 'application/x-netcdf', 'oda' => 'application/oda', - 'oex' => 'application/x-opera-extension', - 'oga' => 'audio/ogg', - 'ogg' => 'audio/ogg', - 'ogv' => 'video/ogg', 'otf' => 'font/otf', - 'pbm' => 'image/x-portable-bitmap', - 'pdb' => 'chemical/x-pdb', 'pdf' => 'application/pdf', - 'pgm' => 'image/x-portable-graymap', 'pgn' => 'application/x-chess-pgn', - 'png' => 'image/png', - 'pnm' => 'image/x-portable-anymap', 'pot' => 'application/mspowerpoint', - 'ppm' => 'image/x-portable-pixmap', 'pps' => 'application/mspowerpoint', 'ppt' => 'application/mspowerpoint', 'ppz' => 'application/mspowerpoint', 'pre' => 'application/x-freelance', 'prt' => 'application/pro_eng', 'ps' => 'application/postscript', - 'qt' => 'video/quicktime', - 'ra' => 'audio/x-realaudio', - 'ram' => 'audio/x-pn-realaudio', - 'ras' => 'image/cmu-raster', - 'rdf' => 'application/xml', - 'rgb' => 'image/x-rgb', - 'rm' => 'audio/x-pn-realaudio', 'roff' => 'application/x-troff', - 'rpm' => 'audio/x-pn-realaudio-plugin', - 'rss' => 'application/rss+xml', - 'rtf' => 'text/rtf', - 'rtx' => 'text/richtext', - 'safariextz' => 'application/octet-stream', 'scm' => 'application/x-lotusscreencam', 'set' => 'application/set', - 'sgm' => 'text/sgml', - 'sgml' => 'text/sgml', 'sh' => 'application/x-sh', 'shar' => 'application/x-shar', - 'silo' => 'model/mesh', 'sit' => 'application/x-stuffit', 'skd' => 'application/x-koan', 'skm' => 'application/x-koan', @@ -230,10 +150,8 @@ class CakeResponse { 'skt' => 'application/x-koan', 'smi' => 'application/smil', 'smil' => 'application/smil', - 'snd' => 'audio/basic', 'sol' => 'application/solids', 'spl' => 'application/x-futuresplash', - 'spx' => 'audio/ogg', 'src' => 'application/x-wais-source', 'step' => 'application/STEP', 'stl' => 'application/SLA', @@ -249,50 +167,132 @@ class CakeResponse { 'tex' => 'application/x-tex', 'texi' => 'application/x-texinfo', 'texinfo' => 'application/x-texinfo', - 'text' => 'text/plain', - 'tif' => 'image/tiff', - 'tiff' => 'image/tiff', - 'tpl' => 'text/template', 'tr' => 'application/x-troff', - 'tsi' => 'audio/TSP-audio', 'tsp' => 'application/dsptype', - 'tsv' => 'text/tab-separated-values', 'ttc' => 'font/ttf', 'ttf' => 'font/ttf', - 'txt' => 'text/plain', 'unv' => 'application/i-deas', 'ustar' => 'application/x-ustar', 'vcd' => 'application/x-cdlink', - 'vcf' => 'text/x-vcard', 'vda' => 'application/vda', - 'viv' => 'video/vnd.vivo', - 'vivo' => 'video/vnd.vivo', - 'vrml' => 'model/vrml', - 'vtt' => 'text/vtt', - 'wap' => array('text/vnd.wap.wml', 'text/vnd.wap.wmlscript', 'image/vnd.wap.wbmp'), - 'wav' => 'audio/x-wav', - 'wbmp' => 'image/vnd.wap.wbmp', - 'webapp' => 'application/x-web-app-manifest+json', - 'webm' => 'video/webm', - 'webp' => 'image/webp', - 'wml' => 'text/vnd.wap.wml', - 'wmlscript' => 'text/vnd.wap.wmlscript', - 'woff' => 'application/x-font-woff', - 'wrl' => 'model/vrml', - 'xbm' => 'image/x-xbitmap', - 'xhtml' => array('application/xhtml+xml', 'application/xhtml', 'text/xhtml'), - 'xhtml-mobile' => 'application/vnd.wap.xhtml+xml', 'xlc' => 'application/vnd.ms-excel', 'xll' => 'application/vnd.ms-excel', 'xlm' => 'application/vnd.ms-excel', 'xls' => 'application/vnd.ms-excel', 'xlw' => 'application/vnd.ms-excel', - 'xml' => array('application/xml', 'text/xml'), - 'xpi' => 'application/x-xpinstall', + 'zip' => 'application/zip', + 'aif' => 'audio/x-aiff', + 'aifc' => 'audio/x-aiff', + 'aiff' => 'audio/x-aiff', + 'au' => 'audio/basic', + 'kar' => 'audio/midi', + 'mid' => 'audio/midi', + 'midi' => 'audio/midi', + 'mp2' => 'audio/mpeg', + 'mp3' => 'audio/mpeg', + 'mpga' => 'audio/mpeg', + 'ogg' => 'audio/ogg', + 'oga' => 'audio/ogg', + 'spx' => 'audio/ogg', + 'ra' => 'audio/x-realaudio', + 'ram' => 'audio/x-pn-realaudio', + 'rm' => 'audio/x-pn-realaudio', + 'rpm' => 'audio/x-pn-realaudio-plugin', + 'snd' => 'audio/basic', + 'tsi' => 'audio/TSP-audio', + 'wav' => 'audio/x-wav', + 'aac' => 'audio/aac', + 'asc' => 'text/plain', + 'c' => 'text/plain', + 'cc' => 'text/plain', + 'css' => 'text/css', + 'etx' => 'text/x-setext', + 'f' => 'text/plain', + 'f90' => 'text/plain', + 'h' => 'text/plain', + 'hh' => 'text/plain', + 'htm' => array('text/html', '*/*'), + 'ics' => 'text/calendar', + 'm' => 'text/plain', + 'rtf' => 'text/rtf', + 'rtx' => 'text/richtext', + 'sgm' => 'text/sgml', + 'sgml' => 'text/sgml', + 'tsv' => 'text/tab-separated-values', + 'tpl' => 'text/template', + 'txt' => 'text/plain', + 'text' => 'text/plain', + 'avi' => 'video/x-msvideo', + 'fli' => 'video/x-fli', + 'mov' => 'video/quicktime', + 'movie' => 'video/x-sgi-movie', + 'mpe' => 'video/mpeg', + 'mpeg' => 'video/mpeg', + 'mpg' => 'video/mpeg', + 'qt' => 'video/quicktime', + 'viv' => 'video/vnd.vivo', + 'vivo' => 'video/vnd.vivo', + 'ogv' => 'video/ogg', + 'webm' => 'video/webm', + 'mp4' => 'video/mp4', + 'm4v' => 'video/mp4', + 'f4v' => 'video/mp4', + 'f4p' => 'video/mp4', + 'm4a' => 'audio/mp4', + 'f4a' => 'audio/mp4', + 'f4b' => 'audio/mp4', + 'gif' => 'image/gif', + 'ief' => 'image/ief', + 'jpe' => 'image/jpeg', + 'jpeg' => 'image/jpeg', + 'jpg' => 'image/jpeg', + 'pbm' => 'image/x-portable-bitmap', + 'pgm' => 'image/x-portable-graymap', + 'png' => 'image/png', + 'pnm' => 'image/x-portable-anymap', + 'ppm' => 'image/x-portable-pixmap', + 'ras' => 'image/cmu-raster', + 'rgb' => 'image/x-rgb', + 'tif' => 'image/tiff', + 'tiff' => 'image/tiff', + 'xbm' => 'image/x-xbitmap', 'xpm' => 'image/x-xpixmap', 'xwd' => 'image/x-xwindowdump', + 'ice' => 'x-conference/x-cooltalk', + 'iges' => 'model/iges', + 'igs' => 'model/iges', + 'mesh' => 'model/mesh', + 'msh' => 'model/mesh', + 'silo' => 'model/mesh', + 'vrml' => 'model/vrml', + 'wrl' => 'model/vrml', + 'mime' => 'www/mime', + 'pdb' => 'chemical/x-pdb', 'xyz' => 'chemical/x-pdb', - 'zip' => 'application/zip', + 'javascript' => 'application/javascript', + 'form' => 'application/x-www-form-urlencoded', + 'file' => 'multipart/form-data', + 'xhtml' => array('application/xhtml+xml', 'application/xhtml', 'text/xhtml'), + 'xhtml-mobile' => 'application/vnd.wap.xhtml+xml', + 'atom' => 'application/atom+xml', + 'amf' => 'application/x-amf', + 'wap' => array('text/vnd.wap.wml', 'text/vnd.wap.wmlscript', 'image/vnd.wap.wbmp'), + 'wml' => 'text/vnd.wap.wml', + 'wmlscript' => 'text/vnd.wap.wmlscript', + 'wbmp' => 'image/vnd.wap.wbmp', + 'woff' => 'application/x-font-woff', + 'webp' => 'image/webp', + 'appcache' => 'text/cache-manifest', + 'manifest' => 'text/cache-manifest', + 'htc' => 'text/x-component', + 'rdf' => 'application/xml', + 'crx' => 'application/x-chrome-extension', + 'oex' => 'application/x-opera-extension', + 'xpi' => 'application/x-xpinstall', + 'safariextz' => 'application/octet-stream', + 'webapp' => 'application/x-web-app-manifest+json', + 'vcf' => 'text/x-vcard', + 'vtt' => 'text/vtt', ); /** From 2967a4db233594c2e47b333678e19301f636a68f Mon Sep 17 00:00:00 2001 From: AD7six Date: Fri, 6 Jul 2012 13:17:15 +0200 Subject: [PATCH 009/256] text/javascript is not the correct mime for js --- .../Controller/Component/RequestHandlerComponentTest.php | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php b/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php index fb6c431e6..0840c64d3 100644 --- a/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php @@ -178,7 +178,7 @@ class RequestHandlerComponentTest extends CakeTestCase { * @return void */ public function testInitializeContentTypeWithjQueryAccept() { - $_SERVER['HTTP_ACCEPT'] = 'application/json, text/javascript, */*; q=0.01'; + $_SERVER['HTTP_ACCEPT'] = 'application/json, application/javascript, */*; q=0.01'; $this->assertNull($this->RequestHandler->ext); Router::parseExtensions('json'); @@ -193,7 +193,7 @@ class RequestHandlerComponentTest extends CakeTestCase { * @return void */ public function testInitializeContentTypeWithjQueryAcceptAndMultiplesExtensions() { - $_SERVER['HTTP_ACCEPT'] = 'application/json, text/javascript, */*; q=0.01'; + $_SERVER['HTTP_ACCEPT'] = 'application/json, application/javascript, */*; q=0.01'; $this->assertNull($this->RequestHandler->ext); Router::parseExtensions('rss', 'json'); @@ -221,7 +221,7 @@ class RequestHandlerComponentTest extends CakeTestCase { * @return void */ public function testInitializeNoContentTypeWithMultipleAcceptedTypes() { - $_SERVER['HTTP_ACCEPT'] = 'application/json, text/javascript, application/xml, */*; q=0.01'; + $_SERVER['HTTP_ACCEPT'] = 'application/json, application/javascript, application/xml, */*; q=0.01'; $this->assertNull($this->RequestHandler->ext); Router::parseExtensions('xml', 'json'); @@ -630,7 +630,7 @@ class RequestHandlerComponentTest extends CakeTestCase { $this->assertEquals('text/vnd.wap.wml', $result); $result = $this->RequestHandler->mapAlias(array('xml', 'js', 'json')); - $expected = array('application/xml', 'text/javascript', 'application/json'); + $expected = array('application/xml', 'application/javascript', 'application/json'); $this->assertEquals($expected, $result); } From 369bbcc964741a26139290683dc075e8b9d357f8 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 7 Jul 2012 01:08:39 -0400 Subject: [PATCH 010/256] Fix failing tests. * New properties on view caused fails in Debugger. * Element cache keys have changed with the new refactoring. --- lib/Cake/Test/Case/Utility/DebuggerTest.php | 1 + lib/Cake/Test/Case/View/ViewTest.php | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/Cake/Test/Case/Utility/DebuggerTest.php b/lib/Cake/Test/Case/Utility/DebuggerTest.php index 6d7d9eca9..645a52349 100644 --- a/lib/Cake/Test/Case/Utility/DebuggerTest.php +++ b/lib/Cake/Test/Case/Utility/DebuggerTest.php @@ -327,6 +327,7 @@ object(View) { request => object(CakeRequest) {} response => object(CakeResponse) {} elementCache => 'default' + elementCacheSettings => array() int => (int) 2 float => (float) 1.333 } diff --git a/lib/Cake/Test/Case/View/ViewTest.php b/lib/Cake/Test/Case/View/ViewTest.php index 33c0ceb90..3cb1f02e3 100644 --- a/lib/Cake/Test/Case/View/ViewTest.php +++ b/lib/Cake/Test/Case/View/ViewTest.php @@ -661,7 +661,7 @@ class ViewTest extends CakeTestCase { * */ public function testElementCallbacks() { - $this->getMock('HtmlHelper', array(), array($this->View), 'ElementCallbackMockHtmlHelper'); + $this->getMock('Helper', array(), array($this->View), 'ElementCallbackMockHtmlHelper'); $this->View->helpers = array('ElementCallbackMockHtml'); $this->View->loadHelpers(); @@ -725,13 +725,13 @@ class ViewTest extends CakeTestCase { $expected = 'this is the test element'; $this->assertEquals($expected, $result); - $result = Cache::read('element__test_element_cache', 'test_view'); + $result = Cache::read('element__test_element_cache_callbacks', 'test_view'); $this->assertEquals($expected, $result); $result = $View->element('test_element', array('param' => 'one', 'foo' => 'two'), array('cache' => true)); $this->assertEquals($expected, $result); - $result = Cache::read('element__test_element_cache_param_foo', 'test_view'); + $result = Cache::read('element__test_element_cache_callbacks_param_foo', 'test_view'); $this->assertEquals($expected, $result); $result = $View->element('test_element', array( @@ -750,7 +750,7 @@ class ViewTest extends CakeTestCase { ), array( 'cache' => array('config' => 'test_view'), )); - $result = Cache::read('element__test_element_cache_param_foo', 'test_view'); + $result = Cache::read('element__test_element_cache_callbacks_param_foo', 'test_view'); $this->assertEquals($expected, $result); Cache::clear(true, 'test_view'); From c5d12604219ac1d6fa0f7d8ff4be98c8a3eee0da Mon Sep 17 00:00:00 2001 From: ADmad Date: Fri, 15 Jun 2012 18:33:02 +0530 Subject: [PATCH 011/256] Added CakeResponse::file() for serving files as response --- lib/Cake/Network/CakeResponse.php | 150 +++++++- .../Test/Case/Network/CakeResponseTest.php | 359 ++++++++++++++++++ 2 files changed, 508 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Network/CakeResponse.php b/lib/Cake/Network/CakeResponse.php index 81bcb9191..102ede09d 100644 --- a/lib/Cake/Network/CakeResponse.php +++ b/lib/Cake/Network/CakeResponse.php @@ -17,6 +17,8 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('File', 'Utility'); + /** * CakeResponse is responsible for managing the response text, status and headers of a HTTP response. * @@ -331,6 +333,13 @@ class CakeResponse { */ protected $_body = null; +/** + * File object for file to be read out as response + * + * @var File + */ + protected $_file = null; + /** * The charset the response body is encoded with * @@ -397,7 +406,12 @@ class CakeResponse { foreach ($this->_headers as $header => $value) { $this->_sendHeader($header, $value); } - $this->_sendContent($this->_body); + if ($this->_file) { + $this->_sendFile($this->_file); + $this->_file = null; + } else { + $this->_sendContent($this->_body); + } } /** @@ -1171,4 +1185,138 @@ class CakeResponse { $this->_cookies[$options['name']] = $options; } +/** + * Setup for display or download the given file + * + * @param string $path Path to file + * @param array $options Options + * ### Options keys + * - name: Alternate download name + * - download: If `true` sets download header and forces file to be downloaded rather than displayed in browser + * @return void + * @throws NotFoundException + */ + public function file($path, $options = array()) { + $options += array( + 'name' => null, + 'download' => null + ); + + if (!is_file($path)) { + $path = APP . $path; + } + + $file = new File($path); + if (!$file->exists() || !$file->readable()) { + if (Configure::read('debug')) { + throw new NotFoundException(__d('cake_dev', 'The requested file %s was not found or not readable', $path)); + } + throw new NotFoundException(__d('cake', 'The requested file was not found')); + } + + $extension = strtolower($file->ext()); + $download = $options['download']; + if ((!$extension || $this->type($extension) === false) && is_null($download)) { + $download = true; + } + + $fileSize = $file->size(); + if ($download) { + $agent = env('HTTP_USER_AGENT'); + + if (preg_match('%Opera(/| )([0-9].[0-9]{1,2})%', $agent)) { + $contentType = 'application/octetstream'; + } elseif (preg_match('/MSIE ([0-9].[0-9]{1,2})/', $agent)) { + $contentType = 'application/force-download'; + } + + if (!empty($contentType)) { + $this->type($contentType); + } + if (is_null($options['name'])) { + $name = $file->name; + } else { + $name = $options['name']; + } + $this->download($name); + $this->header('Accept-Ranges', 'bytes'); + + $httpRange = env('HTTP_RANGE'); + if (isset($httpRange)) { + list($toss, $range) = explode('=', $httpRange); + + $size = $fileSize - 1; + $length = $fileSize - $range; + + $this->header(array( + 'Content-Length' => $length, + 'Content-Range' => 'bytes ' . $range . $size . '/' . $fileSize + )); + + $this->statusCode(206); + $file->open('rb', true); + $file->offset($range); + } else { + $this->header('Content-Length', $fileSize); + } + } else { + $this->header('Content-Length', $fileSize); + } + $this->_clearBuffer(); + + $this->_file = $file; + } + +/** + * Reads out a file, and echos the content to the client. + * + * @param File $file File object + * @return boolean True is whole file is echoed successfully or false if client connection is lost in between + */ + protected function _sendFile($file) { + $compress = $this->outputCompressed(); + $file->open('rb'); + while (!feof($file->handle)) { + if (!$this->_isActive()) { + $file->close(); + return false; + } + set_time_limit(0); + echo fread($file->handle, 8192); + if (!$compress) { + $this->_flushBuffer(); + } + } + $file->close(); + return true; + } + +/** + * Returns true if connection is still active + * + * @return boolean + */ + protected function _isActive() { + return connection_status() === CONNECTION_NORMAL && !connection_aborted(); + } + +/** + * Clears the contents of the topmost output buffer and discards them + * + * @return boolean + */ + protected function _clearBuffer() { + return @ob_end_clean(); + } + +/** + * Flushes the contents of the output buffer + * + * @return void + */ + protected function _flushBuffer() { + @flush(); + @ob_flush(); + } + } diff --git a/lib/Cake/Test/Case/Network/CakeResponseTest.php b/lib/Cake/Test/Case/Network/CakeResponseTest.php index 9f601b1b4..d3253ddd2 100644 --- a/lib/Cake/Test/Case/Network/CakeResponseTest.php +++ b/lib/Cake/Test/Case/Network/CakeResponseTest.php @@ -1006,4 +1006,363 @@ class CakeResponseTest extends CakeTestCase { $this->assertEquals($expected, $result); } +/** + * testFileNotFound + * + * @expectedException NotFoundException + * @return void + */ + public function testFileNotFound() { + $response = new CakeResponse(); + $response->file('/some/missing/folder/file.jpg'); + } + +/** + * testFile method + * + * @return void + */ + public function testFile() { + $response = $this->getMock('CakeResponse', array( + 'header', + 'type', + '_sendHeader', + '_setContentType', + '_isActive', + '_clearBuffer', + '_flushBuffer' + )); + + $response->expects($this->exactly(1)) + ->method('type') + ->with('css') + ->will($this->returnArgument(0)); + + $response->expects($this->at(1)) + ->method('header') + ->with('Content-Length', 31); + + $response->expects($this->once())->method('_clearBuffer'); + $response->expects($this->once())->method('_flushBuffer'); + + $response->expects($this->exactly(1)) + ->method('_isActive') + ->will($this->returnValue(true)); + + $response->file(CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'css' . DS . 'test_asset.css'); + + ob_start(); + $result = $response->send(); + $output = ob_get_clean(); + $this->assertEquals('this is the test asset css file', $output); + $this->assertTrue($result !== false); + } + +/** + * testFileWithUnknownFileTypeGeneric method + * + * @return void + */ + public function testFileWithUnknownFileTypeGeneric() { + $currentUserAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null; + $_SERVER['HTTP_USER_AGENT'] = 'Some generic browser'; + + $response = $this->getMock('CakeResponse', array( + 'header', + 'type', + 'download', + '_sendHeader', + '_setContentType', + '_isActive', + '_clearBuffer', + '_flushBuffer' + )); + + $response->expects($this->exactly(1)) + ->method('type') + ->with('ini') + ->will($this->returnValue(false)); + + $response->expects($this->once()) + ->method('download') + ->with('no_section.ini'); + + $response->expects($this->at(2)) + ->method('header') + ->with('Accept-Ranges', 'bytes'); + + $response->expects($this->at(3)) + ->method('header') + ->with('Content-Length', 35); + + $response->expects($this->once())->method('_clearBuffer'); + $response->expects($this->once())->method('_flushBuffer'); + + $response->expects($this->exactly(1)) + ->method('_isActive') + ->will($this->returnValue(true)); + + $response->file(CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS . 'no_section.ini'); + + ob_start(); + $result = $response->send(); + $output = ob_get_clean(); + $this->assertEquals("some_key = some_value\nbool_key = 1\n", $output); + $this->assertTrue($result !== false); + if ($currentUserAgent !== null) { + $_SERVER['HTTP_USER_AGENT'] = $currentUserAgent; + } + } + +/** + * testFileWithUnknownFileTypeOpera method + * + * @return void + */ + public function testFileWithUnknownFileTypeOpera() { + $currentUserAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null; + $_SERVER['HTTP_USER_AGENT'] = 'Opera/9.80 (Windows NT 6.0; U; en) Presto/2.8.99 Version/11.10'; + + $response = $this->getMock('CakeResponse', array( + 'header', + 'type', + 'download', + '_sendHeader', + '_setContentType', + '_isActive', + '_clearBuffer', + '_flushBuffer' + )); + + $response->expects($this->at(0)) + ->method('type') + ->with('ini') + ->will($this->returnValue(false)); + + $response->expects($this->at(1)) + ->method('type') + ->with('application/octetstream') + ->will($this->returnValue(false)); + + $response->expects($this->once()) + ->method('download') + ->with('no_section.ini'); + + $response->expects($this->at(3)) + ->method('header') + ->with('Accept-Ranges', 'bytes'); + + $response->expects($this->at(4)) + ->method('header') + ->with('Content-Length', 35); + + $response->expects($this->once())->method('_clearBuffer'); + $response->expects($this->once())->method('_flushBuffer'); + $response->expects($this->exactly(1)) + ->method('_isActive') + ->will($this->returnValue(true)); + + $response->file(CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS . 'no_section.ini'); + + ob_start(); + $result = $response->send(); + $output = ob_get_clean(); + $this->assertEquals("some_key = some_value\nbool_key = 1\n", $output); + $this->assertTrue($result !== false); + if ($currentUserAgent !== null) { + $_SERVER['HTTP_USER_AGENT'] = $currentUserAgent; + } + } + +/** + * testFileWithUnknownFileTypeIE method + * + * @return void + */ + public function testFileWithUnknownFileTypeIE() { + $currentUserAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null; + $_SERVER['HTTP_USER_AGENT'] = 'Mozilla/5.0 (compatible; MSIE 8.0; Windows NT 5.2; Trident/4.0; Media Center PC 4.0; SLCC1; .NET CLR 3.0.04320)'; + + $response = $this->getMock('CakeResponse', array( + 'header', + 'type', + 'download', + '_sendHeader', + '_setContentType', + '_isActive', + '_clearBuffer', + '_flushBuffer' + )); + + $response->expects($this->at(0)) + ->method('type') + ->with('ini') + ->will($this->returnValue(false)); + + $response->expects($this->at(1)) + ->method('type') + ->with('application/force-download') + ->will($this->returnValue(false)); + + $response->expects($this->once()) + ->method('download') + ->with('config.ini'); + + $response->expects($this->at(3)) + ->method('header') + ->with('Accept-Ranges', 'bytes'); + + $response->expects($this->at(4)) + ->method('header') + ->with('Content-Length', 35); + + $response->expects($this->once())->method('_clearBuffer'); + $response->expects($this->once())->method('_flushBuffer'); + $response->expects($this->exactly(1)) + ->method('_isActive') + ->will($this->returnValue(true)); + + $response->file(CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS . 'no_section.ini', array( + 'name' => 'config.ini' + )); + + ob_start(); + $result = $response->send(); + $output = ob_get_clean(); + $this->assertEquals("some_key = some_value\nbool_key = 1\n", $output); + $this->assertTrue($result !== false); + if ($currentUserAgent !== null) { + $_SERVER['HTTP_USER_AGENT'] = $currentUserAgent; + } + } +/** + * testFileWithUnknownFileNoDownload method + * + * @return void + */ + public function testFileWithUnknownFileNoDownload() { + $currentUserAgent = isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null; + $_SERVER['HTTP_USER_AGENT'] = 'Some generic browser'; + + $response = $this->getMock('CakeResponse', array( + 'header', + 'type', + 'download', + '_sendHeader', + '_setContentType', + '_isActive', + '_clearBuffer', + '_flushBuffer' + )); + + $response->expects($this->exactly(1)) + ->method('type') + ->with('ini') + ->will($this->returnValue(false)); + + $response->expects($this->never()) + ->method('download'); + + $response->file(CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS . 'no_section.ini', array( + 'download' => false + )); + + if ($currentUserAgent !== null) { + $_SERVER['HTTP_USER_AGENT'] = $currentUserAgent; + } + } + +/** + * testConnectionAbortedOnBuffering method + * + * @return void + */ + public function testConnectionAbortedOnBuffering() { + $response = $this->getMock('CakeResponse', array( + 'header', + 'type', + 'download', + '_sendHeader', + '_setContentType', + '_isActive', + '_clearBuffer', + '_flushBuffer' + )); + + $response->expects($this->any()) + ->method('type') + ->with('css') + ->will($this->returnArgument(0)); + + $response->expects($this->at(0)) + ->method('_isActive') + ->will($this->returnValue(false)); + + $response->expects($this->once())->method('_clearBuffer'); + $response->expects($this->never())->method('_flushBuffer'); + + $response->file(CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'css' . DS . 'test_asset.css'); + + $result = $response->send(); + $this->assertNull($result); + } + +/** + * Test downloading files with UPPERCASE extensions. + * + * @return void + */ + public function testFileUpperExtension() { + $response = $this->getMock('CakeResponse', array( + 'header', + 'type', + 'download', + '_sendHeader', + '_setContentType', + '_isActive', + '_clearBuffer', + '_flushBuffer' + )); + + $response->expects($this->any()) + ->method('type') + ->with('jpg') + ->will($this->returnArgument(0)); + + $response->expects($this->at(0)) + ->method('_isActive') + ->will($this->returnValue(true)); + + $response->file(CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'img' . DS . 'test_2.JPG'); + } + +/** + * Test downloading files with extension not explicitly set. + * + * @return void + */ + public function testFileExtensionNotSet() { + $response = $this->getMock('CakeResponse', array( + 'header', + 'type', + 'download', + '_sendHeader', + '_setContentType', + '_isActive', + '_clearBuffer', + '_flushBuffer' + )); + + $response->expects($this->any()) + ->method('type') + ->with('jpg') + ->will($this->returnArgument(0)); + + $response->expects($this->at(0)) + ->method('_isActive') + ->will($this->returnValue(true)); + + $response->file(CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'img' . DS . 'test_2.JPG'); + } + } From 69eba678f49e804846191d884d3e6ed761c4b447 Mon Sep 17 00:00:00 2001 From: ADmad Date: Wed, 11 Jul 2012 01:33:40 +0530 Subject: [PATCH 012/256] Deprecated MediaView and updated MediaView::render() to use CakeResponse::file() --- lib/Cake/Test/Case/View/MediaViewTest.php | 204 ++++++++-------------- lib/Cake/View/MediaView.php | 163 ++--------------- 2 files changed, 86 insertions(+), 281 deletions(-) diff --git a/lib/Cake/Test/Case/View/MediaViewTest.php b/lib/Cake/Test/Case/View/MediaViewTest.php index 3b723c0bf..4f9c1348e 100644 --- a/lib/Cake/Test/Case/View/MediaViewTest.php +++ b/lib/Cake/Test/Case/View/MediaViewTest.php @@ -35,8 +35,15 @@ class MediaViewTest extends CakeTestCase { */ public function setUp() { parent::setUp(); - $this->MediaView = $this->getMock('MediaView', array('_isActive', '_clearBuffer', '_flushBuffer')); - $this->MediaView->response = $this->getMock('CakeResponse'); + $this->MediaView = new MediaView(); + $this->MediaView->response = $this->getMock('CakeResponse', array( + '_isActive', + '_clearBuffer', + '_flushBuffer', + 'type', + 'header', + 'download' + )); } /** @@ -71,10 +78,10 @@ class MediaViewTest extends CakeTestCase { public function testRender() { $this->MediaView->viewVars = array( 'path' => CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'css' . DS, - 'id' => 'test_asset.css', - 'extension' => 'css', + 'id' => 'test_asset.css' ); - $this->MediaView->expects($this->exactly(2)) + + $this->MediaView->response->expects($this->exactly(1)) ->method('_isActive') ->will($this->returnValue(true)); @@ -83,23 +90,23 @@ class MediaViewTest extends CakeTestCase { ->with('css') ->will($this->returnArgument(0)); - $this->MediaView->response->expects($this->at(1)) + $this->MediaView->response->expects($this->at(0)) ->method('header') ->with(array( - 'Date' => gmdate('D, d M Y H:i:s', time()) . ' GMT', - 'Expires' => '0', - 'Cache-Control' => 'private, must-revalidate, post-check=0, pre-check=0', - 'Pragma' => 'no-cache' + 'Expires' => 'Mon, 26 Jul 1997 05:00:00 GMT', + 'Cache-Control' => 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0', + 'Last-Modified' => gmdate('D, d M Y H:i:s', time()) . ' GMT' )); $this->MediaView->response->expects($this->at(2)) ->method('header') - ->with(array( - 'Content-Length' => 31 - )); - $this->MediaView->response->expects($this->once())->method('send'); - $this->MediaView->expects($this->once())->method('_clearBuffer'); - $this->MediaView->expects($this->once())->method('_flushBuffer'); + ->with('Content-Length', 31); + + $this->MediaView->response->expects($this->once())->method('_clearBuffer'); + $this->MediaView->response->expects($this->exactly(1)) + ->method('_isActive') + ->will($this->returnValue(true)); + $this->MediaView->response->expects($this->once())->method('_flushBuffer'); ob_start(); $result = $this->MediaView->render(); @@ -118,25 +125,20 @@ class MediaViewTest extends CakeTestCase { $_SERVER['HTTP_USER_AGENT'] = 'Some generic browser'; $this->MediaView->viewVars = array( 'path' => CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS, - 'id' => 'no_section.ini', - 'extension' => 'ini', + 'id' => 'no_section.ini' ); - $this->MediaView->expects($this->exactly(2)) - ->method('_isActive') - ->will($this->returnValue(true)); $this->MediaView->response->expects($this->exactly(1)) ->method('type') ->with('ini') ->will($this->returnValue(false)); - $this->MediaView->response->expects($this->at(1)) + $this->MediaView->response->expects($this->at(0)) ->method('header') ->with(array( - 'Date' => gmdate('D, d M Y H:i:s', time()) . ' GMT', - 'Expires' => '0', - 'Cache-Control' => 'private, must-revalidate, post-check=0, pre-check=0', - 'Pragma' => 'no-cache' + 'Expires' => 'Mon, 26 Jul 1997 05:00:00 GMT', + 'Cache-Control' => 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0', + 'Last-Modified' => gmdate('D, d M Y H:i:s', time()) . ' GMT' )); $this->MediaView->response->expects($this->once()) @@ -145,17 +147,17 @@ class MediaViewTest extends CakeTestCase { $this->MediaView->response->expects($this->at(3)) ->method('header') - ->with(array( - 'Accept-Ranges' => 'bytes' - )); + ->with('Accept-Ranges', 'bytes'); $this->MediaView->response->expects($this->at(4)) ->method('header') ->with('Content-Length', 35); - $this->MediaView->response->expects($this->once())->method('send'); - $this->MediaView->expects($this->once())->method('_clearBuffer'); - $this->MediaView->expects($this->once())->method('_flushBuffer'); + $this->MediaView->response->expects($this->once())->method('_clearBuffer'); + $this->MediaView->response->expects($this->exactly(1)) + ->method('_isActive') + ->will($this->returnValue(true)); + $this->MediaView->response->expects($this->once())->method('_flushBuffer'); ob_start(); $result = $this->MediaView->render(); @@ -178,48 +180,43 @@ class MediaViewTest extends CakeTestCase { $this->MediaView->viewVars = array( 'path' => CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS, 'id' => 'no_section.ini', - 'extension' => 'ini', ); - $this->MediaView->expects($this->exactly(2)) - ->method('_isActive') - ->will($this->returnValue(true)); $this->MediaView->response->expects($this->at(0)) + ->method('header') + ->with(array( + 'Expires' => 'Mon, 26 Jul 1997 05:00:00 GMT', + 'Cache-Control' => 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0', + 'Last-Modified' => gmdate('D, d M Y H:i:s', time()) . ' GMT' + )); + + $this->MediaView->response->expects($this->at(1)) ->method('type') ->with('ini') ->will($this->returnValue(false)); - $this->MediaView->response->expects($this->at(1)) - ->method('header') - ->with(array( - 'Date' => gmdate('D, d M Y H:i:s', time()) . ' GMT', - 'Expires' => '0', - 'Cache-Control' => 'private, must-revalidate, post-check=0, pre-check=0', - 'Pragma' => 'no-cache' - )); - $this->MediaView->response->expects($this->at(2)) ->method('type') ->with('application/octetstream') ->will($this->returnValue(false)); - $this->MediaView->response->expects($this->once()) + $this->MediaView->response->expects($this->at(3)) ->method('download') ->with('no_section.ini'); $this->MediaView->response->expects($this->at(4)) ->method('header') - ->with(array( - 'Accept-Ranges' => 'bytes' - )); + ->with('Accept-Ranges', 'bytes'); $this->MediaView->response->expects($this->at(5)) ->method('header') ->with('Content-Length', 35); - $this->MediaView->response->expects($this->once())->method('send'); - $this->MediaView->expects($this->once())->method('_clearBuffer'); - $this->MediaView->expects($this->once())->method('_flushBuffer'); + $this->MediaView->response->expects($this->once())->method('_clearBuffer'); + $this->MediaView->response->expects($this->exactly(1)) + ->method('_isActive') + ->will($this->returnValue(true)); + $this->MediaView->response->expects($this->once())->method('_flushBuffer'); ob_start(); $result = $this->MediaView->render(); @@ -242,49 +239,44 @@ class MediaViewTest extends CakeTestCase { $this->MediaView->viewVars = array( 'path' => CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS, 'id' => 'no_section.ini', - 'extension' => 'ini', 'name' => 'config' ); - $this->MediaView->expects($this->exactly(2)) - ->method('_isActive') - ->will($this->returnValue(true)); $this->MediaView->response->expects($this->at(0)) + ->method('header') + ->with(array( + 'Expires' => 'Mon, 26 Jul 1997 05:00:00 GMT', + 'Cache-Control' => 'no-store, no-cache, must-revalidate, post-check=0, pre-check=0', + 'Last-Modified' => gmdate('D, d M Y H:i:s', time()) . ' GMT' + )); + + $this->MediaView->response->expects($this->at(1)) ->method('type') ->with('ini') ->will($this->returnValue(false)); - $this->MediaView->response->expects($this->at(1)) - ->method('header') - ->with(array( - 'Date' => gmdate('D, d M Y H:i:s', time()) . ' GMT', - 'Expires' => '0', - 'Cache-Control' => 'private, must-revalidate, post-check=0, pre-check=0', - 'Pragma' => 'no-cache' - )); - $this->MediaView->response->expects($this->at(2)) ->method('type') ->with('application/force-download') ->will($this->returnValue(false)); - $this->MediaView->response->expects($this->once()) + $this->MediaView->response->expects($this->at(3)) ->method('download') ->with('config.ini'); $this->MediaView->response->expects($this->at(4)) ->method('header') - ->with(array( - 'Accept-Ranges' => 'bytes' - )); + ->with('Accept-Ranges', 'bytes'); $this->MediaView->response->expects($this->at(5)) ->method('header') ->with('Content-Length', 35); - $this->MediaView->response->expects($this->once())->method('send'); - $this->MediaView->expects($this->once())->method('_clearBuffer'); - $this->MediaView->expects($this->once())->method('_flushBuffer'); + $this->MediaView->response->expects($this->once())->method('_clearBuffer'); + $this->MediaView->response->expects($this->exactly(1)) + ->method('_isActive') + ->will($this->returnValue(true)); + $this->MediaView->response->expects($this->once())->method('_flushBuffer'); ob_start(); $result = $this->MediaView->render(); @@ -296,29 +288,6 @@ class MediaViewTest extends CakeTestCase { } } -/** - * testConnectionAborted method - * - * @return void - */ - public function testConnectionAborted() { - $this->MediaView->viewVars = array( - 'path' => CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'css' . DS, - 'id' => 'test_asset.css', - 'extension' => 'css', - ); - - $this->MediaView->expects($this->once()) - ->method('_isActive') - ->will($this->returnValue(false)); - - $this->MediaView->response->expects($this->never()) - ->method('type'); - - $result = $this->MediaView->render(); - $this->assertFalse($result); - } - /** * testConnectionAbortedOnBuffering method * @@ -327,29 +296,22 @@ class MediaViewTest extends CakeTestCase { public function testConnectionAbortedOnBuffering() { $this->MediaView->viewVars = array( 'path' => CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'css' . DS, - 'id' => 'test_asset.css', - 'extension' => 'css', + 'id' => 'test_asset.css' ); - $this->MediaView->expects($this->at(0)) - ->method('_isActive') - ->will($this->returnValue(true)); - $this->MediaView->response->expects($this->any()) ->method('type') ->with('css') ->will($this->returnArgument(0)); - $this->MediaView->expects($this->at(1)) + $this->MediaView->response->expects($this->at(1)) ->method('_isActive') ->will($this->returnValue(false)); - $this->MediaView->response->expects($this->once())->method('send'); - $this->MediaView->expects($this->once())->method('_clearBuffer'); - $this->MediaView->expects($this->never())->method('_flushBuffer'); + $this->MediaView->response->expects($this->once())->method('_clearBuffer'); + $this->MediaView->response->expects($this->never())->method('_flushBuffer'); - $result = $this->MediaView->render(); - $this->assertFalse($result); + $this->MediaView->render(); } /** @@ -360,8 +322,7 @@ class MediaViewTest extends CakeTestCase { public function testRenderUpperExtension() { $this->MediaView->viewVars = array( 'path' => CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'img' . DS, - 'id' => 'test_2.JPG', - 'extension' => 'JPG', + 'id' => 'test_2.JPG' ); $this->MediaView->response->expects($this->any()) @@ -369,30 +330,7 @@ class MediaViewTest extends CakeTestCase { ->with('jpg') ->will($this->returnArgument(0)); - $this->MediaView->expects($this->at(0)) - ->method('_isActive') - ->will($this->returnValue(true)); - - $this->MediaView->render(); - } - -/** - * Test downloading files with extension not explicitly set. - * - * @return void - */ - public function testRenderExtensionNotSet() { - $this->MediaView->viewVars = array( - 'path' => CAKE . 'Test' . DS . 'test_app' . DS . 'Vendor' . DS . 'img' . DS, - 'id' => 'test_2.JPG', - ); - - $this->MediaView->response->expects($this->any()) - ->method('type') - ->with('jpg') - ->will($this->returnArgument(0)); - - $this->MediaView->expects($this->at(0)) + $this->MediaView->response->expects($this->at(0)) ->method('_isActive') ->will($this->returnValue(true)); diff --git a/lib/Cake/View/MediaView.php b/lib/Cake/View/MediaView.php index 49a3140a8..e4e6ea7e9 100644 --- a/lib/Cake/View/MediaView.php +++ b/lib/Cake/View/MediaView.php @@ -15,6 +15,7 @@ * @package Cake.View * @since CakePHP(tm) v 1.2.0.5714 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) + * @deprecated Deprecated since version 2.3, use CakeResponse::file() instead */ App::uses('View', 'View'); @@ -31,8 +32,6 @@ App::uses('CakeRequest', 'Network'); * - `id` The filename on the server's filesystem, including extension. * - `name` The filename that will be sent to the user, specified without the extension. * - `download` Set to true to set a `Content-Disposition` header. This is ideal for file downloads. - * - `extension` The extension of the file being served. This is used to set the mimetype. - * If not provided its extracted from filename provided as `id`. * - `path` The absolute path, including the trailing / on the server's filesystem to `id`. * - `mimeType` The mime type of the file if CakeResponse doesn't know about it. * Must be an associative array with extension as key and mime type as value eg. array('ini' => 'text/plain') @@ -59,23 +58,15 @@ App::uses('CakeRequest', 'Network'); */ class MediaView extends View { -/** - * Indicates whether response gzip compression was enabled for this class - * - * @var boolean - */ - protected $_compressionEnabled = false; - /** * Display or download the given file * * @param string $view Not used * @param string $layout Not used - * @return mixed - * @throws NotFoundException + * @return boolean */ public function render($view = null, $layout = null) { - $name = $download = $extension = $id = $modified = $path = $cache = $mimeType = $compress = null; + $name = $download = $id = $modified = $path = $cache = $mimeType = $compress = null; extract($this->viewVars, EXTR_OVERWRITE); if (is_dir($path)) { @@ -84,155 +75,31 @@ class MediaView extends View { $path = APP . $path . $id; } - if (!is_file($path)) { - if (Configure::read('debug')) { - throw new NotFoundException(sprintf('The requested file %s was not found', $path)); - } - throw new NotFoundException('The requested file was not found'); - } - if (is_array($mimeType)) { $this->response->type($mimeType); } - if (!isset($extension)) { - $extension = pathinfo($id, PATHINFO_EXTENSION); - } - - if ($this->_isActive()) { - $extension = strtolower($extension); - $chunkSize = 8192; - $buffer = ''; - $fileSize = @filesize($path); - $handle = fopen($path, 'rb'); - - if ($handle === false) { - return false; - } + if ($cache) { if (!empty($modified) && !is_numeric($modified)) { $modified = strtotime($modified, time()); } else { $modified = time(); } - if (!$extension || $this->response->type($extension) === false) { - $download = true; - } - - if ($cache) { - $this->response->cache($modified, $cache); - } else { - $this->response->header(array( - 'Date' => gmdate('D, d M Y H:i:s', time()) . ' GMT', - 'Expires' => '0', - 'Cache-Control' => 'private, must-revalidate, post-check=0, pre-check=0', - 'Pragma' => 'no-cache' - )); - } - - if ($download) { - $agent = env('HTTP_USER_AGENT'); - - if (preg_match('%Opera(/| )([0-9].[0-9]{1,2})%', $agent)) { - $contentType = 'application/octetstream'; - } elseif (preg_match('/MSIE ([0-9].[0-9]{1,2})/', $agent)) { - $contentType = 'application/force-download'; - } - - if (!empty($contentType)) { - $this->response->type($contentType); - } - if (is_null($name)) { - $name = $id; - } elseif ($extension) { - $name .= '.' . $extension; - } - $this->response->download($name); - $this->response->header(array('Accept-Ranges' => 'bytes')); - - $httpRange = env('HTTP_RANGE'); - if (isset($httpRange)) { - list($toss, $range) = explode('=', $httpRange); - - $size = $fileSize - 1; - $length = $fileSize - $range; - - $this->response->header(array( - 'Content-Length' => $length, - 'Content-Range' => 'bytes ' . $range . $size . '/' . $fileSize - )); - - $this->response->statusCode(206); - fseek($handle, $range); - } else { - $this->response->header('Content-Length', $fileSize); - } - } else { - $this->response->header(array( - 'Content-Length' => $fileSize - )); - } - $this->_clearBuffer(); - if ($compress) { - $this->_compressionEnabled = $this->response->compress(); - } - - $this->response->send(); - return $this->_sendFile($handle); + $this->response->cache($modified, $cache); + } else { + $this->response->disableCache(); } - return false; - } - -/** - * Reads out a file handle, and echos the content to the client. - * - * @param resource $handle A file handle or stream - * @return void - */ - protected function _sendFile($handle) { - $chunkSize = 8192; - $buffer = ''; - while (!feof($handle)) { - if (!$this->_isActive()) { - fclose($handle); - return false; - } - set_time_limit(0); - $buffer = fread($handle, $chunkSize); - echo $buffer; - if (!$this->_compressionEnabled) { - $this->_flushBuffer(); - } + if ($name !== null) { + $name .= '.' . pathinfo($id, PATHINFO_EXTENSION); } - fclose($handle); - } + $this->response->file($path, compact('name', 'download')); -/** - * Returns true if connection is still active - * - * @return boolean - */ - protected function _isActive() { - return connection_status() == 0 && !connection_aborted(); - } - -/** - * Clears the contents of the topmost output buffer and discards them - * - * @return boolean - */ - protected function _clearBuffer() { - return @ob_end_clean(); - } - -/** - * Flushes the contents of the output buffer - * - * @return void - */ - protected function _flushBuffer() { - @flush(); - @ob_flush(); + if ($compress) { + $this->response->compress(); + } + $this->response->send(); + return true; } } From dd524c96e19c6f7df7aafcb8132ae93cc5990d8b Mon Sep 17 00:00:00 2001 From: shin1x1 Date: Fri, 13 Jul 2012 02:29:42 +0900 Subject: [PATCH 013/256] Added ServerShell for PHP Built-in Server. --- app/webroot/index.php | 5 + lib/Cake/Console/Command/ServerShell.php | 165 ++++++++++++++++++ .../Console/Templates/skel/webroot/index.php | 5 + 3 files changed, 175 insertions(+) create mode 100644 lib/Cake/Console/Command/ServerShell.php diff --git a/app/webroot/index.php b/app/webroot/index.php index e125e09da..936bc9a00 100644 --- a/app/webroot/index.php +++ b/app/webroot/index.php @@ -70,6 +70,11 @@ if (!defined('WWW_ROOT')) { define('WWW_ROOT', dirname(__FILE__) . DS); } +// for built-in server +if (php_sapi_name() == 'cli-server') { + $_SERVER['PHP_SELF'] = '/'.basename(__FILE__); +} + if (!defined('CAKE_CORE_INCLUDE_PATH')) { if (function_exists('ini_set')) { ini_set('include_path', ROOT . DS . 'lib' . PATH_SEPARATOR . ini_get('include_path')); diff --git a/lib/Cake/Console/Command/ServerShell.php b/lib/Cake/Console/Command/ServerShell.php new file mode 100644 index 000000000..99c18231d --- /dev/null +++ b/lib/Cake/Console/Command/ServerShell.php @@ -0,0 +1,165 @@ +_host = self::DEFAULT_HOST; + $this->_port = self::DEFAULT_PORT; + $this->_documentRoot = WWW_ROOT; + } + +/** + * Starts up the Shell and displays the welcome message. + * Allows for checking and configuring prior to command or main execution + * + * Override this method if you want to remove the welcome information, + * or otherwise modify the pre-command flow. + * + * @return void + * @link http://book.cakephp.org/2.0/en/console-and-shells.html#Shell::startup + */ + public function startup() { + if (!empty($this->params['host'])) { + $this->_host = $this->params['host']; + } + if (!empty($this->params['port'])) { + $this->_port = $this->params['port']; + } + if (!empty($this->params['document_root'])) { + $this->_documentRoot = $this->params['document_root']; + } + + // for windows + if (substr($this->_documentRoot, -1, 1) == DIRECTORY_SEPARATOR) { + $this->_documentRoot = substr($this->_documentRoot, 0, strlen($this->_documentRoot) - 1); + } + if (preg_match("/^([a-z]:)[\\\]+(.+)$/i", $this->_documentRoot, $m)) { + $this->_documentRoot = $m[1].'\\'.$m[2]; + } + + parent::startup(); + } + +/** + * Displays a header for the shell + * + * @return void + */ + protected function _welcome() { + $this->out(); + $this->out(__d('cake_console', 'Welcome to CakePHP %s Console', 'v' . Configure::version())); + $this->hr(); + $this->out(__d('cake_console', 'App : %s', APP_DIR)); + $this->out(__d('cake_console', 'Path: %s', APP)); + $this->out(__d('cake_console', 'DocumentRoot: %s', $this->_documentRoot)); + $this->hr(); + } + +/** + * Override main() to handle action + * + * @return void + */ + public function main() { + if (version_compare(PHP_VERSION, '5.4.0') < 0) { + $this->out(__d('cake_console', 'This command is available on PHP5.4 or above')); + return; + } + + $command = sprintf("php -S %s:%d -t %s", + $this->_host, + $this->_port, + $this->_documentRoot + ); + + $port = ($this->_port == self::DEFAULT_PORT) ? '' : ':'.$this->_port; + $this->out(__d('cake_console', 'built-in server is running in http://%s%s/', $this->_host, $port)); + $ret = system($command); + } + +/** + * Get and configure the optionparser. + * + * @return ConsoleOptionParser + */ + public function getOptionParser() { + $parser = parent::getOptionParser(); + + $parser->addOption('host', array( + 'short' => 'H', + 'help' => __d('cake_console', 'ServerHost') + )); + $parser->addOption('port', array( + 'short' => 'p', + 'help' => __d('cake_console', 'ListenPort') + )); + $parser->addOption('document_root', array( + 'short' => 'd', + 'help' => __d('cake_console', 'DocumentRoot') + )); + + $parser->description(array( + __d('cake_console', 'PHP Built-in Server for CakePHP'), + __d('cake_console', '[WARN] Don\'t use this at the production environment'), + )); + + return $parser; + } +} diff --git a/lib/Cake/Console/Templates/skel/webroot/index.php b/lib/Cake/Console/Templates/skel/webroot/index.php index fd482f8c8..be4797877 100644 --- a/lib/Cake/Console/Templates/skel/webroot/index.php +++ b/lib/Cake/Console/Templates/skel/webroot/index.php @@ -72,6 +72,11 @@ if (!defined('WWW_ROOT')) { define('WWW_ROOT', dirname(__FILE__) . DS); } +// for built-in server +if (php_sapi_name() == 'cli-server') { + $_SERVER['PHP_SELF'] = '/'.basename(__FILE__); +} + if (!defined('CAKE_CORE_INCLUDE_PATH')) { if (function_exists('ini_set')) { ini_set('include_path', ROOT . DS . 'lib' . PATH_SEPARATOR . ini_get('include_path')); From 32d5f113d31e2d8acc4056c1093bfdc91585ff60 Mon Sep 17 00:00:00 2001 From: shin1x1 Date: Sat, 14 Jul 2012 16:47:33 +0900 Subject: [PATCH 014/256] fixed phpcs errors. --- lib/Cake/Console/Command/ServerShell.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Console/Command/ServerShell.php b/lib/Cake/Console/Command/ServerShell.php index 99c18231d..d19a70789 100644 --- a/lib/Cake/Console/Command/ServerShell.php +++ b/lib/Cake/Console/Command/ServerShell.php @@ -91,7 +91,7 @@ class ServerShell extends AppShell { $this->_documentRoot = substr($this->_documentRoot, 0, strlen($this->_documentRoot) - 1); } if (preg_match("/^([a-z]:)[\\\]+(.+)$/i", $this->_documentRoot, $m)) { - $this->_documentRoot = $m[1].'\\'.$m[2]; + $this->_documentRoot = $m[1] . '\\' . $m[2]; } parent::startup(); @@ -129,7 +129,7 @@ class ServerShell extends AppShell { $this->_documentRoot ); - $port = ($this->_port == self::DEFAULT_PORT) ? '' : ':'.$this->_port; + $port = ($this->_port == self::DEFAULT_PORT) ? '' : ':' . $this->_port; $this->out(__d('cake_console', 'built-in server is running in http://%s%s/', $this->_host, $port)); $ret = system($command); } From 2f7f5e13224537eaa4da6b825b1d106bebc35d05 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 15 Jul 2012 09:11:27 -0400 Subject: [PATCH 015/256] Use file cache as the default cache engine. Too many people had issues using APC by default as its often configured in strange ways, and works poorly on inexpensive hosting. Fixes #2995 --- app/Config/core.php | 9 ++++----- lib/Cake/Console/Templates/skel/Config/core.php | 12 +++++++----- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/app/Config/core.php b/app/Config/core.php index 4bbfabe6e..84983b622 100644 --- a/app/Config/core.php +++ b/app/Config/core.php @@ -232,17 +232,16 @@ //date_default_timezone_set('UTC'); /** - * Pick the caching engine to use. If APC is enabled use it. - * If running via cli - apc is disabled by default. ensure it's available and enabled in this case + * Configure the cache handlers that CakePHP will use for internal + * metadata like class maps, and model schema. + * + * By default File is used, but for improved performance you should use APC. * * Note: 'default' and other application caches should be configured in app/Config/bootstrap.php. * Please check the comments in boostrap.php for more info on the cache engines available * and their setttings. */ $engine = 'File'; -if (extension_loaded('apc') && function_exists('apc_dec') && (php_sapi_name() !== 'cli' || ini_get('apc.enable_cli'))) { - $engine = 'Apc'; -} // In development mode, caches should expire quickly. $duration = '+999 days'; diff --git a/lib/Cake/Console/Templates/skel/Config/core.php b/lib/Cake/Console/Templates/skel/Config/core.php index c53e2fd02..4069c7897 100644 --- a/lib/Cake/Console/Templates/skel/Config/core.php +++ b/lib/Cake/Console/Templates/skel/Config/core.php @@ -293,14 +293,16 @@ */ /** - * Pick the caching engine to use. If APC is enabled use it. - * If running via cli - apc is disabled by default. ensure it's available and enabled in this case + * Configure the cache handlers that CakePHP will use for internal + * metadata like class maps, and model schema. * + * By default File is used, but for improved performance you should use APC. + * + * Note: 'default' and other application caches should be configured in app/Config/bootstrap.php. + * Please check the comments in boostrap.php for more info on the cache engines available + * and their setttings. */ $engine = 'File'; -if (extension_loaded('apc') && function_exists('apc_dec') && (php_sapi_name() !== 'cli' || ini_get('apc.enable_cli'))) { - $engine = 'Apc'; -} // In development mode, caches should expire quickly. $duration = '+999 days'; From 70ac1c7e331fc43dceb20b8a732ab4f3152ac149 Mon Sep 17 00:00:00 2001 From: AD7six Date: Mon, 16 Jul 2012 16:54:02 +0200 Subject: [PATCH 016/256] Adding symlink resolution to app/Console/cake Otherwise, if you symlink to app/Console/cake the app path gets set to 2 folders above wherever the symlink is defined. --- app/Console/cake | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/Console/cake b/app/Console/cake index b7e38259c..cd2430ead 100755 --- a/app/Console/cake +++ b/app/Console/cake @@ -17,7 +17,8 @@ # @license MIT License (http://www.opensource.org/licenses/mit-license.php) # ################################################################################ -LIB=$(cd -P -- "$(dirname -- "$0")" && pwd -P) && LIB=$LIB/$(basename -- "$0") +ME=$(readlink -f $0) +LIB=$(cd -P -- "$(dirname -- "$ME")" && pwd -P) && LIB=$LIB/$(basename -- "$ME") while [ -h "$LIB" ]; do DIR=$(dirname -- "$LIB") @@ -26,8 +27,9 @@ while [ -h "$LIB" ]; do done LIB=$(dirname -- "$LIB")/ -APP=$(dirname $(cd $(dirname $0) && pwd)) +APP=$(dirname $(cd $(dirname $ME) && pwd)) +echo $APP exec php -q "$LIB"cake.php -working "$APP" "$@" exit; From 760cf33ce377ae8e4f1548fb69891f078677ee53 Mon Sep 17 00:00:00 2001 From: euromark Date: Tue, 17 Jul 2012 10:47:20 +0200 Subject: [PATCH 017/256] make sure a missing validation rule always triggers a warning (in productive mode this will be logged in the log files) --- lib/Cake/Model/Validator/CakeValidationRule.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Model/Validator/CakeValidationRule.php b/lib/Cake/Model/Validator/CakeValidationRule.php index 8ebf82589..1c153e1f9 100644 --- a/lib/Cake/Model/Validator/CakeValidationRule.php +++ b/lib/Cake/Model/Validator/CakeValidationRule.php @@ -274,7 +274,7 @@ class CakeValidationRule { $this->_valid = call_user_func_array(array('Validation', $this->_rule), $this->_ruleParams); } elseif (is_string($validator['rule'])) { $this->_valid = preg_match($this->_rule, $data[$field]); - } elseif (Configure::read('debug') > 0) { + } else { trigger_error(__d('cake_dev', 'Could not find validation handler %s for %s', $this->_rule, $field), E_USER_WARNING); return false; } From e1357ca8aa7f5ef85c12f686d6c9eeca3a240603 Mon Sep 17 00:00:00 2001 From: euromark Date: Wed, 18 Jul 2012 03:24:55 +0200 Subject: [PATCH 018/256] indentation in templates --- .../Templates/default/classes/controller.ctp | 50 +++++++++---------- .../Templates/default/classes/model.ctp | 6 +-- 2 files changed, 28 insertions(+), 28 deletions(-) diff --git a/lib/Cake/Console/Templates/default/classes/controller.ctp b/lib/Cake/Console/Templates/default/classes/controller.ctp index 6e27d0d19..545fee3ac 100644 --- a/lib/Cake/Console/Templates/default/classes/controller.ctp +++ b/lib/Cake/Console/Templates/default/classes/controller.ctp @@ -49,33 +49,33 @@ class Controller extends App } diff --git a/lib/Cake/Console/Templates/default/classes/model.ctp b/lib/Cake/Console/Templates/default/classes/model.ctp index f7895da2b..739f09314 100644 --- a/lib/Cake/Console/Templates/default/classes/model.ctp +++ b/lib/Cake/Console/Templates/default/classes/model.ctp @@ -48,9 +48,9 @@ class extends AppModel { From 3945c0e6a8e1cb6635cdf2dd8b80519e618d77c5 Mon Sep 17 00:00:00 2001 From: euromark Date: Wed, 18 Jul 2012 03:55:29 +0200 Subject: [PATCH 019/256] rtim files --- lib/Cake/Cache/CacheEngine.php | 2 +- lib/Cake/Cache/Engine/FileEngine.php | 2 +- .../Console/Command/Task/TemplateTask.php | 2 +- lib/Cake/Console/Command/TestShell.php | 4 +-- .../Console/Templates/skel/Config/core.php | 4 +-- lib/Cake/Controller/Component.php | 2 +- lib/Cake/Controller/Component/Acl/IniAcl.php | 2 +- lib/Cake/Controller/Component/Acl/PhpAcl.php | 34 +++++++++---------- .../Component/Auth/DigestAuthenticate.php | 2 +- .../Controller/Component/CookieComponent.php | 2 +- .../Component/SecurityComponent.php | 2 +- .../Controller/Component/SessionComponent.php | 4 +-- lib/Cake/Core/CakePlugin.php | 2 +- lib/Cake/Core/Configure.php | 6 ++-- lib/Cake/Event/CakeEvent.php | 2 +- lib/Cake/Event/CakeEventManager.php | 6 ++-- .../Model/Behavior/ContainableBehavior.php | 4 +-- lib/Cake/Model/ConnectionManager.php | 2 +- lib/Cake/Model/Datasource/DataSource.php | 2 +- .../Model/Datasource/Database/Sqlserver.php | 2 +- .../Model/Validator/CakeValidationRule.php | 2 +- lib/Cake/Network/Email/CakeEmail.php | 6 ++-- .../Test/Case/Cache/Engine/FileEngineTest.php | 2 +- .../Case/Console/Command/TestShellTest.php | 16 ++++----- .../Test/Case/Event/CakeEventManagerTest.php | 2 +- .../Case/Model/Datasource/DataSourceTest.php | 2 +- .../Case/TestSuite/CakeTestFixtureTest.php | 2 +- .../Test/Case/TestSuite/CakeTestSuiteTest.php | 8 ++--- .../TestSuite/Fixture/CakeTestFixture.php | 2 +- lib/Cake/TestSuite/templates/header.php | 2 +- lib/Cake/Utility/File.php | 2 +- .../View/Elements/exception_stack_trace.ctp | 2 +- lib/Cake/View/Helper/SessionHelper.php | 2 +- lib/Cake/View/JsonView.php | 12 +++---- lib/Cake/View/ViewBlock.php | 2 +- 35 files changed, 76 insertions(+), 76 deletions(-) diff --git a/lib/Cake/Cache/CacheEngine.php b/lib/Cake/Cache/CacheEngine.php index 6994701f4..9daf4d7c0 100644 --- a/lib/Cake/Cache/CacheEngine.php +++ b/lib/Cake/Cache/CacheEngine.php @@ -65,7 +65,7 @@ abstract class CacheEngine { * Garbage collection * * Permanently remove all expired and deleted data - * + * * @param integer $expires [optional] An expires timestamp, invalidataing all data before. * @return void */ diff --git a/lib/Cake/Cache/Engine/FileEngine.php b/lib/Cake/Cache/Engine/FileEngine.php index 9388fafb9..da68c398c 100644 --- a/lib/Cake/Cache/Engine/FileEngine.php +++ b/lib/Cake/Cache/Engine/FileEngine.php @@ -93,7 +93,7 @@ class FileEngine extends CacheEngine { /** * Garbage collection. Permanently remove all expired and deleted data - * + * * @param integer $expires [optional] An expires timestamp, invalidataing all data before. * @return boolean True if garbage collection was successful, false on failure */ diff --git a/lib/Cake/Console/Command/Task/TemplateTask.php b/lib/Cake/Console/Command/Task/TemplateTask.php index ffe993ce0..69b4cdd39 100644 --- a/lib/Cake/Console/Command/Task/TemplateTask.php +++ b/lib/Cake/Console/Command/Task/TemplateTask.php @@ -56,7 +56,7 @@ class TemplateTask extends AppShell { * * Bake themes are directories not named `skel` inside a `Console/Templates` path. * They are listed in this order: app -> plugin -> default - * + * * @return array Array of bake themes that are installed. */ protected function _findThemes() { diff --git a/lib/Cake/Console/Command/TestShell.php b/lib/Cake/Console/Command/TestShell.php index 0d0127ac7..01d6363dd 100644 --- a/lib/Cake/Console/Command/TestShell.php +++ b/lib/Cake/Console/Command/TestShell.php @@ -335,8 +335,8 @@ class TestShell extends Shell { * Find the test case for the passed file. The file could itself be a test. * * @param string $file - * @param string $category - * @param boolean $throwOnMissingFile + * @param string $category + * @param boolean $throwOnMissingFile * @access protected * @return array(type, case) * @throws Exception diff --git a/lib/Cake/Console/Templates/skel/Config/core.php b/lib/Cake/Console/Templates/skel/Config/core.php index 4069c7897..72fb0c99c 100644 --- a/lib/Cake/Console/Templates/skel/Config/core.php +++ b/lib/Cake/Console/Templates/skel/Config/core.php @@ -226,7 +226,7 @@ Configure::write('Acl.database', 'default'); /** - * Uncomment this line and correct your server timezone to fix + * Uncomment this line and correct your server timezone to fix * any date & time related errors. */ //date_default_timezone_set('UTC'); @@ -299,7 +299,7 @@ * By default File is used, but for improved performance you should use APC. * * Note: 'default' and other application caches should be configured in app/Config/bootstrap.php. - * Please check the comments in boostrap.php for more info on the cache engines available + * Please check the comments in boostrap.php for more info on the cache engines available * and their setttings. */ $engine = 'File'; diff --git a/lib/Cake/Controller/Component.php b/lib/Cake/Controller/Component.php index 876174e8c..42815e534 100644 --- a/lib/Cake/Controller/Component.php +++ b/lib/Cake/Controller/Component.php @@ -120,7 +120,7 @@ class Component extends Object { } /** - * Called before the Controller::beforeRender(), and before + * Called before the Controller::beforeRender(), and before * the view class is loaded, and before Controller::render() * * @param Controller $controller Controller with components to beforeRender diff --git a/lib/Cake/Controller/Component/Acl/IniAcl.php b/lib/Cake/Controller/Component/Acl/IniAcl.php index 8810668cc..d915443fb 100644 --- a/lib/Cake/Controller/Component/Acl/IniAcl.php +++ b/lib/Cake/Controller/Component/Acl/IniAcl.php @@ -143,7 +143,7 @@ class IniAcl extends Object implements AclInterface { } /** - * Parses an INI file and returns an array that reflects the + * Parses an INI file and returns an array that reflects the * INI file's section structure. Double-quote friendly. * * @param string $filename File diff --git a/lib/Cake/Controller/Component/Acl/PhpAcl.php b/lib/Cake/Controller/Component/Acl/PhpAcl.php index 28b3b941f..6540b935b 100644 --- a/lib/Cake/Controller/Component/Acl/PhpAcl.php +++ b/lib/Cake/Controller/Component/Acl/PhpAcl.php @@ -18,7 +18,7 @@ */ /** - * PhpAcl implements an access control system using a plain PHP configuration file. + * PhpAcl implements an access control system using a plain PHP configuration file. * An example file can be found in app/Config/acl.php * * @package Cake.Controller.Component.Acl @@ -46,7 +46,7 @@ class PhpAcl extends Object implements AclInterface { /** * Aco Object - * + * * @var PhpAco */ public $Aco = null; @@ -65,8 +65,8 @@ class PhpAcl extends Object implements AclInterface { /** * Initialize method - * - * @param AclComponent $Component Component instance + * + * @param AclComponent $Component Component instance * @return void */ public function initialize(Component $Component) { @@ -199,7 +199,7 @@ class PhpAco { /** * map modifiers for ACO paths to their respective PCRE pattern - * + * * @var array */ public static $modifiers = array( @@ -263,7 +263,7 @@ class PhpAco { /** * allow/deny ARO access to ARO * - * @return void + * @return void */ public function access($aro, $aco, $action, $type = 'deny') { $aco = $this->resolve($aco); @@ -315,7 +315,7 @@ class PhpAco { * * @param array $allow ACO allow rules * @param array $deny ACO deny rules - * @return void + * @return void */ public function build(array $allow, array $deny = array()) { $stack = array(); @@ -349,7 +349,7 @@ class PhpAco { class PhpAro { /** - * role to resolve to when a provided ARO is not listed in + * role to resolve to when a provided ARO is not listed in * the internal tree * * @var string @@ -359,12 +359,12 @@ class PhpAro { /** * map external identifiers. E.g. if * - * array('User' => array('username' => 'jeff', 'role' => 'editor')) + * array('User' => array('username' => 'jeff', 'role' => 'editor')) * - * is passed as an ARO to one of the methods of AclComponent, PhpAcl + * is passed as an ARO to one of the methods of AclComponent, PhpAcl * will check if it can be resolved to an User or a Role defined in the - * configuration file. - * + * configuration file. + * * @var array * @see app/Config/acl.php */ @@ -375,7 +375,7 @@ class PhpAro { /** * aliases to map - * + * * @var array */ public $aliases = array(); @@ -400,9 +400,9 @@ class PhpAro { * From the perspective of the given ARO, walk down the tree and * collect all inherited AROs levelwise such that AROs from different * branches with equal distance to the requested ARO will be collected at the same - * index. The resulting array will contain a prioritized list of (list of) roles ordered from + * index. The resulting array will contain a prioritized list of (list of) roles ordered from * the most distant AROs to the requested one itself. - * + * * @param string|array $aro An ARO identifier * @return array prioritized AROs */ @@ -427,7 +427,7 @@ class PhpAro { /** * resolve an ARO identifier to an internal ARO string using - * the internal mapping information. + * the internal mapping information. * * @param string|array $aro ARO identifier (User.jeff, array('User' => ...), etc) * @return string internal aro string (e.g. User/jeff, Role/default) @@ -529,7 +529,7 @@ class PhpAro { * build an ARO tree structure for internal processing * * @param array $aros array of AROs as key and their inherited AROs as values - * @return void + * @return void */ public function build(array $aros) { $this->_tree = array(); diff --git a/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php b/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php index bdea7d8aa..5e0fb0ee5 100644 --- a/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php +++ b/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php @@ -68,7 +68,7 @@ class DigestAuthenticate extends BaseAuthenticate { * - `realm` The realm authentication is for, Defaults to the servername. * - `nonce` A nonce used for authentication. Defaults to `uniqid()`. * - `qop` Defaults to auth, no other values are supported at this time. - * - `opaque` A string that must be returned unchanged by clients. + * - `opaque` A string that must be returned unchanged by clients. * Defaults to `md5($settings['realm'])` * * @var array diff --git a/lib/Cake/Controller/Component/CookieComponent.php b/lib/Cake/Controller/Component/CookieComponent.php index 9f0879f92..45551a8af 100644 --- a/lib/Cake/Controller/Component/CookieComponent.php +++ b/lib/Cake/Controller/Component/CookieComponent.php @@ -155,7 +155,7 @@ class CookieComponent extends Component { /** * A reference to the Controller's CakeResponse object - * + * * @var CakeResponse */ protected $_response = null; diff --git a/lib/Cake/Controller/Component/SecurityComponent.php b/lib/Cake/Controller/Component/SecurityComponent.php index 1a2043895..72d9067e6 100644 --- a/lib/Cake/Controller/Component/SecurityComponent.php +++ b/lib/Cake/Controller/Component/SecurityComponent.php @@ -23,7 +23,7 @@ App::uses('Hash', 'Utility'); App::uses('Security', 'Utility'); /** - * The Security Component creates an easy way to integrate tighter security in + * The Security Component creates an easy way to integrate tighter security in * your application. It provides methods for various tasks like: * * - Restricting which HTTP methods your application accepts. diff --git a/lib/Cake/Controller/Component/SessionComponent.php b/lib/Cake/Controller/Component/SessionComponent.php index ed42bff24..0bcdb7fa6 100644 --- a/lib/Cake/Controller/Component/SessionComponent.php +++ b/lib/Cake/Controller/Component/SessionComponent.php @@ -21,8 +21,8 @@ App::uses('Component', 'Controller'); App::uses('CakeSession', 'Model/Datasource'); /** - * The CakePHP SessionComponent provides a way to persist client data between - * page requests. It acts as a wrapper for the `$_SESSION` as well as providing + * The CakePHP SessionComponent provides a way to persist client data between + * page requests. It acts as a wrapper for the `$_SESSION` as well as providing * convenience methods for several `$_SESSION` related functions. * * @package Cake.Controller.Component diff --git a/lib/Cake/Core/CakePlugin.php b/lib/Cake/Core/CakePlugin.php index 5242c9f98..814f36b32 100644 --- a/lib/Cake/Core/CakePlugin.php +++ b/lib/Cake/Core/CakePlugin.php @@ -18,7 +18,7 @@ */ /** - * CakePlugin is responsible for loading and unloading plugins. It also can + * CakePlugin is responsible for loading and unloading plugins. It also can * retrieve plugin paths and load their bootstrap and routes files. * * @package Cake.Core diff --git a/lib/Cake/Core/Configure.php b/lib/Cake/Core/Configure.php index ad241254c..c914ad9d2 100644 --- a/lib/Cake/Core/Configure.php +++ b/lib/Cake/Core/Configure.php @@ -286,7 +286,7 @@ class Configure { /** * Dump data currently in Configure into $filename. The serialization format * is decided by the config reader attached as $config. For example, if the - * 'default' adapter is a PhpReader, the generated file will be a PHP + * 'default' adapter is a PhpReader, the generated file will be a PHP * configuration file loadable by the PhpReader. * * ## Usage @@ -303,7 +303,7 @@ class Configure { * @param string $key The identifier to create in the config adapter. * This could be a filename or a cache key depending on the adapter being used. * @param string $config The name of the configured adapter to dump data with. - * @param array $keys The name of the top-level keys you want to dump. + * @param array $keys The name of the top-level keys you want to dump. * This allows you save only some data stored in Configure. * @return boolean success * @throws ConfigureException if the adapter does not implement a `dump` method. @@ -381,7 +381,7 @@ class Configure { } /** * Set the error and exception handlers. - * + * * @param array $error The Error handling configuration. * @param array $exception The exception handling configuration. * @return void diff --git a/lib/Cake/Event/CakeEvent.php b/lib/Cake/Event/CakeEvent.php index 52de3cf23..c70d4f816 100644 --- a/lib/Cake/Event/CakeEvent.php +++ b/lib/Cake/Event/CakeEvent.php @@ -27,7 +27,7 @@ class CakeEvent { /** * Name of the event - * + * * @var string $name */ protected $_name = null; diff --git a/lib/Cake/Event/CakeEventManager.php b/lib/Cake/Event/CakeEventManager.php index 252364d4c..aacd537c9 100644 --- a/lib/Cake/Event/CakeEventManager.php +++ b/lib/Cake/Event/CakeEventManager.php @@ -50,7 +50,7 @@ class CakeEventManager { protected $_listeners = array(); /** - * Internal flag to distinguish a common manager from the sigleton + * Internal flag to distinguish a common manager from the sigleton * * @var boolean */ @@ -64,7 +64,7 @@ class CakeEventManager { * * If called with a first params, it will be set as the globally available instance * - * @param CakeEventManager $manager + * @param CakeEventManager $manager * @return CakeEventManager the global event manager */ public static function instance($manager = null) { @@ -80,7 +80,7 @@ class CakeEventManager { } /** - * Adds a new listener to an event. Listeners + * Adds a new listener to an event. Listeners * * @param callback|CakeEventListener $callable PHP valid callback type or instance of CakeEventListener to be called * when the event named with $eventKey is triggered. If a CakeEventListener instances is passed, then the `implementedEvents` diff --git a/lib/Cake/Model/Behavior/ContainableBehavior.php b/lib/Cake/Model/Behavior/ContainableBehavior.php index bb33eaf46..98c067468 100644 --- a/lib/Cake/Model/Behavior/ContainableBehavior.php +++ b/lib/Cake/Model/Behavior/ContainableBehavior.php @@ -20,8 +20,8 @@ */ /** - * Behavior to allow for dynamic and atomic manipulation of a Model's associations - * used for a find call. Most useful for limiting the amount of associations and + * Behavior to allow for dynamic and atomic manipulation of a Model's associations + * used for a find call. Most useful for limiting the amount of associations and * data returned. * * @package Cake.Model.Behavior diff --git a/lib/Cake/Model/ConnectionManager.php b/lib/Cake/Model/ConnectionManager.php index edbcfa5eb..4edd0ac77 100644 --- a/lib/Cake/Model/ConnectionManager.php +++ b/lib/Cake/Model/ConnectionManager.php @@ -24,7 +24,7 @@ App::uses('DataSource', 'Model/Datasource'); /** * Manages loaded instances of DataSource objects * - * Provides an interface for loading and enumerating connections defined in + * Provides an interface for loading and enumerating connections defined in * app/Config/database.php * * @package Cake.Model diff --git a/lib/Cake/Model/Datasource/DataSource.php b/lib/Cake/Model/Datasource/DataSource.php index e5e665fe9..1240ce2bc 100644 --- a/lib/Cake/Model/Datasource/DataSource.php +++ b/lib/Cake/Model/Datasource/DataSource.php @@ -418,7 +418,7 @@ class DataSource extends Object { /** * Closes a connection. Override in subclasses - * + * * @return boolean * @access public */ diff --git a/lib/Cake/Model/Datasource/Database/Sqlserver.php b/lib/Cake/Model/Datasource/Database/Sqlserver.php index b23e59a16..3700ca2d0 100644 --- a/lib/Cake/Model/Datasource/Database/Sqlserver.php +++ b/lib/Cake/Model/Datasource/Database/Sqlserver.php @@ -636,7 +636,7 @@ class Sqlserver extends DboSource { /** * Generate a database-native column schema string * - * @param array $column An array structured like the + * @param array $column An array structured like the * following: array('name'=>'value', 'type'=>'value'[, options]), * where options can be 'default', 'length', or 'key'. * @return string diff --git a/lib/Cake/Model/Validator/CakeValidationRule.php b/lib/Cake/Model/Validator/CakeValidationRule.php index 8ebf82589..8f81ecf7e 100644 --- a/lib/Cake/Model/Validator/CakeValidationRule.php +++ b/lib/Cake/Model/Validator/CakeValidationRule.php @@ -246,7 +246,7 @@ class CakeValidationRule { * If called with no parameters it will return whether this rule * is configured for update operations or not. * - * @return boolean + * @return boolean **/ public function isUpdate($exists = null) { if ($exists === null) { diff --git a/lib/Cake/Network/Email/CakeEmail.php b/lib/Cake/Network/Email/CakeEmail.php index 9e5ed09b8..8beac4c74 100644 --- a/lib/Cake/Network/Email/CakeEmail.php +++ b/lib/Cake/Network/Email/CakeEmail.php @@ -1035,7 +1035,7 @@ class CakeEmail { /** * Send an email using the specified content, template and layout - * + * * @param string|array $content String with message or array with messages * @return array * @throws SocketException @@ -1337,7 +1337,7 @@ class CakeEmail { /** * Attach non-embedded files by adding file contents inside boundaries. * - * @param string $boundary Boundary to use. If null, will default to $this->_boundary + * @param string $boundary Boundary to use. If null, will default to $this->_boundary * @return array An array of lines to add to the message */ protected function _attachFiles($boundary = null) { @@ -1380,7 +1380,7 @@ class CakeEmail { /** * Attach inline/embedded files to the message. * - * @param string $boundary Boundary to use. If null, will default to $this->_boundary + * @param string $boundary Boundary to use. If null, will default to $this->_boundary * @return array An array of lines to add to the message */ protected function _attachInlineFiles($boundary = null) { diff --git a/lib/Cake/Test/Case/Cache/Engine/FileEngineTest.php b/lib/Cake/Test/Case/Cache/Engine/FileEngineTest.php index a091fbd6e..6f506d845 100644 --- a/lib/Cake/Test/Case/Cache/Engine/FileEngineTest.php +++ b/lib/Cake/Test/Case/Cache/Engine/FileEngineTest.php @@ -102,7 +102,7 @@ class FileEngineTest extends CakeTestCase { /** * Test read/write on the same cache key. Ensures file handles are re-wound. - * + * * @return void */ public function testConsecutiveReadWrite() { diff --git a/lib/Cake/Test/Case/Console/Command/TestShellTest.php b/lib/Cake/Test/Case/Console/Command/TestShellTest.php index 5d08c584d..ddae489e2 100644 --- a/lib/Cake/Test/Case/Console/Command/TestShellTest.php +++ b/lib/Cake/Test/Case/Console/Command/TestShellTest.php @@ -64,7 +64,7 @@ class TestShellTest extends CakeTestCase { /** * testMapCoreFileToCategory - * + * * @return void */ public function testMapCoreFileToCategory() { @@ -84,7 +84,7 @@ class TestShellTest extends CakeTestCase { * testMapCoreFileToCase * * basics.php is a slightly special case - it's the only file in the core with a test that isn't Capitalized - * + * * @return void */ public function testMapCoreFileToCase() { @@ -102,7 +102,7 @@ class TestShellTest extends CakeTestCase { /** * testMapAppFileToCategory - * + * * @return void */ public function testMapAppFileToCategory() { @@ -132,7 +132,7 @@ class TestShellTest extends CakeTestCase { /** * testMapPluginFileToCategory - * + * * @return void */ public function testMapPluginFileToCategory() { @@ -162,7 +162,7 @@ class TestShellTest extends CakeTestCase { /** * testMapCoreTestToCategory - * + * * @return void */ public function testMapCoreTestToCategory() { @@ -182,7 +182,7 @@ class TestShellTest extends CakeTestCase { * testMapCoreTestToCase * * basics.php is a slightly special case - it's the only file in the core with a test that isn't Capitalized - * + * * @return void */ public function testMapCoreTestToCase() { @@ -200,7 +200,7 @@ class TestShellTest extends CakeTestCase { /** * testMapAppTestToCategory - * + * * @return void */ public function testMapAppTestToCategory() { @@ -230,7 +230,7 @@ class TestShellTest extends CakeTestCase { /** * testMapPluginTestToCategory - * + * * @return void */ public function testMapPluginTestToCategory() { diff --git a/lib/Cake/Test/Case/Event/CakeEventManagerTest.php b/lib/Cake/Test/Case/Event/CakeEventManagerTest.php index 04a358ab4..01f1ff7d4 100644 --- a/lib/Cake/Test/Case/Event/CakeEventManagerTest.php +++ b/lib/Cake/Test/Case/Event/CakeEventManagerTest.php @@ -53,7 +53,7 @@ class CakeEventTestListener { /** * Auxiliary function to help in stopPropagation testing * - * @param CakeEvent $event + * @param CakeEvent $event * @return void */ public function stopListener($event) { diff --git a/lib/Cake/Test/Case/Model/Datasource/DataSourceTest.php b/lib/Cake/Test/Case/Model/Datasource/DataSourceTest.php index 3bb9bd0d7..a0de0aba2 100644 --- a/lib/Cake/Test/Case/Model/Datasource/DataSourceTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/DataSourceTest.php @@ -29,7 +29,7 @@ class TestSource extends DataSource { /** * _schema - * @var type + * @var type */ protected $_schema = array( 'id' => array( diff --git a/lib/Cake/Test/Case/TestSuite/CakeTestFixtureTest.php b/lib/Cake/Test/Case/TestSuite/CakeTestFixtureTest.php index 556554872..6afdc0b35 100644 --- a/lib/Cake/Test/Case/TestSuite/CakeTestFixtureTest.php +++ b/lib/Cake/Test/Case/TestSuite/CakeTestFixtureTest.php @@ -227,7 +227,7 @@ class CakeTestFixtureTest extends CakeTestCase { } /** - * test that init() correctly sets the fixture table when the connection + * test that init() correctly sets the fixture table when the connection * or model have prefixes defined. * * @return void diff --git a/lib/Cake/Test/Case/TestSuite/CakeTestSuiteTest.php b/lib/Cake/Test/Case/TestSuite/CakeTestSuiteTest.php index a30fd5a86..9a25b4939 100644 --- a/lib/Cake/Test/Case/TestSuite/CakeTestSuiteTest.php +++ b/lib/Cake/Test/Case/TestSuite/CakeTestSuiteTest.php @@ -22,7 +22,7 @@ class CakeTestSuiteTest extends CakeTestCase { /** * testAddTestDirectory - * + * * @return void */ public function testAddTestDirectory() { @@ -39,7 +39,7 @@ class CakeTestSuiteTest extends CakeTestCase { /** * testAddTestDirectoryRecursive - * + * * @return void */ public function testAddTestDirectoryRecursive() { @@ -57,7 +57,7 @@ class CakeTestSuiteTest extends CakeTestCase { /** * testAddTestDirectoryRecursiveWithHidden - * + * * @return void */ public function testAddTestDirectoryRecursiveWithHidden() { @@ -81,7 +81,7 @@ class CakeTestSuiteTest extends CakeTestCase { /** * testAddTestDirectoryRecursiveWithNonPhp - * + * * @return void */ public function testAddTestDirectoryRecursiveWithNonPhp() { diff --git a/lib/Cake/TestSuite/Fixture/CakeTestFixture.php b/lib/Cake/TestSuite/Fixture/CakeTestFixture.php index 359d57f6f..f18f0f7e9 100644 --- a/lib/Cake/TestSuite/Fixture/CakeTestFixture.php +++ b/lib/Cake/TestSuite/Fixture/CakeTestFixture.php @@ -16,7 +16,7 @@ App::uses('CakeSchema', 'Model'); /** - * CakeTestFixture is responsible for building and destroying tables to be used + * CakeTestFixture is responsible for building and destroying tables to be used * during testing. * * @package Cake.TestSuite.Fixture diff --git a/lib/Cake/TestSuite/templates/header.php b/lib/Cake/TestSuite/templates/header.php index 4d41719f2..dfaa2d178 100644 --- a/lib/Cake/TestSuite/templates/header.php +++ b/lib/Cake/TestSuite/templates/header.php @@ -127,7 +127,7 @@ div.code-coverage-results span.result-bad { color: #a00; } div.code-coverage-results span.result-ok { color: #fa0; } div.code-coverage-results span.result-good { color: #0a0; } - + div#version { padding-top: 2px; float: right; diff --git a/lib/Cake/Utility/File.php b/lib/Cake/Utility/File.php index 6fe93995a..edf2dfbf3 100644 --- a/lib/Cake/Utility/File.php +++ b/lib/Cake/Utility/File.php @@ -546,7 +546,7 @@ class File { } /** - * Get the mime type of the file. Uses the finfo extension if + * Get the mime type of the file. Uses the finfo extension if * its available, otherwise falls back to mime_content_type * * @return false|string The mimetype of the file, or false if reading fails. diff --git a/lib/Cake/View/Elements/exception_stack_trace.ctp b/lib/Cake/View/Elements/exception_stack_trace.ctp index b744c164a..5177b2596 100644 --- a/lib/Cake/View/Elements/exception_stack_trace.ctp +++ b/lib/Cake/View/Elements/exception_stack_trace.ctp @@ -49,7 +49,7 @@ App::uses('Debugger', 'Utility'); endif; $called = isset($stack['class']) ? $stack['class'] . $stack['type'] . $stack['function'] : $stack['function']; - + printf( '%s(%s) ', $i, diff --git a/lib/Cake/View/Helper/SessionHelper.php b/lib/Cake/View/Helper/SessionHelper.php index 259c4df81..2bb983c47 100644 --- a/lib/Cake/View/Helper/SessionHelper.php +++ b/lib/Cake/View/Helper/SessionHelper.php @@ -100,7 +100,7 @@ class SessionHelper extends AppHelper { * echo $this->Session->flash('flash', array('element' => 'my_custom_element')); * }}} * - * If you want to use an element from a plugin for rendering your flash message you can do that using the + * If you want to use an element from a plugin for rendering your flash message you can do that using the * plugin param: * * {{{ diff --git a/lib/Cake/View/JsonView.php b/lib/Cake/View/JsonView.php index 3cf669c43..785f75437 100644 --- a/lib/Cake/View/JsonView.php +++ b/lib/Cake/View/JsonView.php @@ -25,7 +25,7 @@ App::uses('View', 'View'); * * `$this->set(array('posts' => $posts, '_serialize' => 'posts'));` * - * When the view is rendered, the `$posts` view variable will be serialized + * When the view is rendered, the `$posts` view variable will be serialized * into JSON. * * You can also define `'_serialize'` as an array. This will create a top level object containing @@ -35,7 +35,7 @@ App::uses('View', 'View'); * $this->set(compact('posts', 'users', 'stuff')); * $this->set('_serialize', array('posts', 'users')); * }}} - * + * * The above would generate a JSON object that looks like: * * `{"posts": [...], "users": [...]}` @@ -49,9 +49,9 @@ App::uses('View', 'View'); class JsonView extends View { /** - * JSON views are always located in the 'json' sub directory for a + * JSON views are always located in the 'json' sub directory for a * controllers views. - * + * * @var string */ public $subDir = 'json'; @@ -72,8 +72,8 @@ class JsonView extends View { * Render a JSON view. * * Uses the special '_serialize' parameter to convert a set of - * view variables into a JSON response. Makes generating simple - * JSON responses very easy. You can omit the '_serialize' parameter, + * view variables into a JSON response. Makes generating simple + * JSON responses very easy. You can omit the '_serialize' parameter, * and use a normal view + layout as well. * * @param string $view The view being rendered. diff --git a/lib/Cake/View/ViewBlock.php b/lib/Cake/View/ViewBlock.php index 5636d74d5..98b16d7fe 100644 --- a/lib/Cake/View/ViewBlock.php +++ b/lib/Cake/View/ViewBlock.php @@ -73,7 +73,7 @@ class ViewBlock { } /** - * Append to an existing or new block. Appending to a new + * Append to an existing or new block. Appending to a new * block will create the block. * * Calling append() without a value will create a new capturing From 7979ee5fa0aa5760aad6443d3a6a9529a2169408 Mon Sep 17 00:00:00 2001 From: mark_story Date: Tue, 17 Jul 2012 23:18:25 -0400 Subject: [PATCH 020/256] Remove test that is no longer needed for validation. --- .../Test/Case/Model/ModelValidationTest.php | 19 ------------------- 1 file changed, 19 deletions(-) diff --git a/lib/Cake/Test/Case/Model/ModelValidationTest.php b/lib/Cake/Test/Case/Model/ModelValidationTest.php index 713e578a7..b63e12a03 100644 --- a/lib/Cake/Test/Case/Model/ModelValidationTest.php +++ b/lib/Cake/Test/Case/Model/ModelValidationTest.php @@ -713,25 +713,6 @@ class ModelValidationTest extends BaseModelTest { $TestModel->invalidFields(array('fieldList' => array('title'))); } -/** - * Test that missing validation methods does not trigger errors in production mode. - * - * @return void - */ - public function testMissingValidationErrorNoTriggering() { - Configure::write('debug', 0); - $TestModel = new ValidationTest1(); - $TestModel->create(array('title' => 'foo')); - $TestModel->validate = array( - 'title' => array( - 'rule' => array('thisOneBringsThePain'), - 'required' => true - ) - ); - $TestModel->invalidFields(array('fieldList' => array('title'))); - $this->assertEquals(array(), $TestModel->validationErrors); - } - /** * Test placeholder replacement when validation message is an array * From bce82a2322d8d80c54d7ce89624f71a0d4c64998 Mon Sep 17 00:00:00 2001 From: Christian Winther Date: Thu, 19 Jul 2012 15:46:06 +0200 Subject: [PATCH 021/256] Better custom find for pagination Instead of shuffling the paginator settings you can now simply add a new "findType" key and it will automatically change the find() type accordingly --- .../Component/PaginatorComponent.php | 6 +++ .../Component/PaginatorComponentTest.php | 54 +++++++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/lib/Cake/Controller/Component/PaginatorComponent.php b/lib/Cake/Controller/Component/PaginatorComponent.php index bd3d31c18..163e487c6 100644 --- a/lib/Cake/Controller/Component/PaginatorComponent.php +++ b/lib/Cake/Controller/Component/PaginatorComponent.php @@ -152,6 +152,12 @@ class PaginatorComponent extends Component { $extra = array_diff_key($options, compact( 'conditions', 'fields', 'order', 'limit', 'page', 'recursive' )); + + if (!empty($extra['findType'])) { + $type = $extra['findType']; + unset($extra['findType']); + } + if ($type !== 'all') { $extra['type'] = $type; } diff --git a/lib/Cake/Test/Case/Controller/Component/PaginatorComponentTest.php b/lib/Cake/Test/Case/Controller/Component/PaginatorComponentTest.php index 1908e926e..34b3944ae 100644 --- a/lib/Cake/Test/Case/Controller/Component/PaginatorComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/PaginatorComponentTest.php @@ -710,6 +710,28 @@ class PaginatorComponentTest extends CakeTestCase { $this->assertEquals($expected, $result); } +/** + * test mergeOptions with customFind key + * + * @return void + */ + public function testMergeOptionsCustomFindKey() { + $this->request->params['named'] = array( + 'page' => 10, + 'limit' => 10 + ); + $this->Paginator->settings = array( + 'page' => 1, + 'limit' => 20, + 'maxLimit' => 100, + 'paramType' => 'named', + 'findType' => 'myCustomFind' + ); + $result = $this->Paginator->mergeOptions('Post'); + $expected = array('page' => 10, 'limit' => 10, 'maxLimit' => 100, 'paramType' => 'named', 'findType' => 'myCustomFind'); + $this->assertEquals($expected, $result); + } + /** * test merging options from the querystring. * @@ -1078,6 +1100,38 @@ class PaginatorComponentTest extends CakeTestCase { $this->assertTrue($result['nextPage']); $this->assertFalse($result['prevPage']); } +/** + * test paginate() and custom find with customFind key, to make sure the correct count is returned. + * + * @return void + */ + public function testPaginateCustomFindWithCustomFindKey() { + $Controller =& new Controller($this->request); + $Controller->uses = array('PaginatorCustomPost'); + $Controller->constructClasses(); + $data = array('author_id' => 3, 'title' => 'Fourth Article', 'body' => 'Article Body, unpublished', 'published' => 'N'); + $Controller->PaginatorCustomPost->create($data); + $result = $Controller->PaginatorCustomPost->save(); + $this->assertTrue(!empty($result)); + + $Controller->paginate = array( + 'conditions' => array('PaginatorCustomPost.published' => 'Y'), + 'findType' => 'list', + 'limit' => 2 + ); + $result = $Controller->paginate(); + $expected = array( + 1 => 'First Post', + 2 => 'Second Post', + ); + $this->assertEquals($expected, $result); + $result = $Controller->params['paging']['PaginatorCustomPost']; + $this->assertEquals(2, $result['current']); + $this->assertEquals(3, $result['count']); + $this->assertEquals(2, $result['pageCount']); + $this->assertTrue($result['nextPage']); + $this->assertFalse($result['prevPage']); + } /** * test paginate() and custom find with fields array, to make sure the correct count is returned. From c41ee9a5aafa692d68865b0c2b1141ec83e6b9ec Mon Sep 17 00:00:00 2001 From: AD7six Date: Thu, 19 Jul 2012 16:04:04 +0200 Subject: [PATCH 022/256] remove debug statement that slipped through Thanks to @jippi for pointing out this error, which originally came from a diff provided by.. @jippi --- app/Console/cake | 1 - 1 file changed, 1 deletion(-) diff --git a/app/Console/cake b/app/Console/cake index cd2430ead..c33a34539 100755 --- a/app/Console/cake +++ b/app/Console/cake @@ -29,7 +29,6 @@ done LIB=$(dirname -- "$LIB")/ APP=$(dirname $(cd $(dirname $ME) && pwd)) -echo $APP exec php -q "$LIB"cake.php -working "$APP" "$@" exit; From a7865b5d1d97cf9cc7611697b59a799bf5ab6e68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Lorenzo=20Rodr=C3=ADguez?= Date: Thu, 19 Jul 2012 14:24:12 -0530 Subject: [PATCH 023/256] Removing some new by reference calls --- .../Controller/Component/PaginatorComponentTest.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/Cake/Test/Case/Controller/Component/PaginatorComponentTest.php b/lib/Cake/Test/Case/Controller/Component/PaginatorComponentTest.php index 34b3944ae..12ede8bea 100644 --- a/lib/Cake/Test/Case/Controller/Component/PaginatorComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/PaginatorComponentTest.php @@ -1034,7 +1034,7 @@ class PaginatorComponentTest extends CakeTestCase { * @return void */ public function testPaginateCustomFind() { - $Controller =& new Controller($this->request); + $Controller = new Controller($this->request); $Controller->uses = array('PaginatorCustomPost'); $Controller->constructClasses(); $data = array('author_id' => 3, 'title' => 'Fourth Article', 'body' => 'Article Body, unpublished', 'published' => 'N'); @@ -1074,7 +1074,7 @@ class PaginatorComponentTest extends CakeTestCase { * @return void */ public function testPaginateCustomFindFieldsArray() { - $Controller =& new Controller($this->request); + $Controller = new Controller($this->request); $Controller->uses = array('PaginatorCustomPost'); $Controller->constructClasses(); $data = array('author_id' => 3, 'title' => 'Fourth Article', 'body' => 'Article Body, unpublished', 'published' => 'N'); @@ -1106,7 +1106,7 @@ class PaginatorComponentTest extends CakeTestCase { * @return void */ public function testPaginateCustomFindWithCustomFindKey() { - $Controller =& new Controller($this->request); + $Controller = new Controller($this->request); $Controller->uses = array('PaginatorCustomPost'); $Controller->constructClasses(); $data = array('author_id' => 3, 'title' => 'Fourth Article', 'body' => 'Article Body, unpublished', 'published' => 'N'); @@ -1139,7 +1139,7 @@ class PaginatorComponentTest extends CakeTestCase { * @return void */ public function testPaginateCustomFindGroupBy() { - $Controller =& new Controller($this->request); + $Controller = new Controller($this->request); $Controller->uses = array('PaginatorCustomPost'); $Controller->constructClasses(); $data = array('author_id' => 2, 'title' => 'Fourth Article', 'body' => 'Article Body, unpublished', 'published' => 'N'); @@ -1204,7 +1204,7 @@ class PaginatorComponentTest extends CakeTestCase { * @return void */ public function testPaginateCustomFindCount() { - $Controller =& new Controller($this->request); + $Controller = new Controller($this->request); $Controller->uses = array('PaginatorCustomPost'); $Controller->constructClasses(); $data = array('author_id' => 2, 'title' => 'Fourth Article', 'body' => 'Article Body, unpublished', 'published' => 'N'); From 4fe1ab1bf602555113e1aa9a0c875430383cabdd Mon Sep 17 00:00:00 2001 From: euromark Date: Sat, 21 Jul 2012 13:34:33 +0200 Subject: [PATCH 024/256] missing app uses statements --- lib/Cake/Console/Templates/skel/Controller/PagesController.php | 1 + lib/Cake/Controller/CakeErrorController.php | 1 + lib/Cake/Controller/Component/PaginatorComponent.php | 1 + lib/Cake/Controller/Component/RequestHandlerComponent.php | 1 + lib/Cake/Model/Behavior/AclBehavior.php | 1 + lib/Cake/Model/Behavior/ContainableBehavior.php | 1 + lib/Cake/Model/Behavior/TranslateBehavior.php | 1 + lib/Cake/Model/Behavior/TreeBehavior.php | 1 + lib/Cake/Model/I18nModel.php | 1 + 9 files changed, 9 insertions(+) diff --git a/lib/Cake/Console/Templates/skel/Controller/PagesController.php b/lib/Cake/Console/Templates/skel/Controller/PagesController.php index 28edfb6ec..174d32bd2 100644 --- a/lib/Cake/Console/Templates/skel/Controller/PagesController.php +++ b/lib/Cake/Console/Templates/skel/Controller/PagesController.php @@ -18,6 +18,7 @@ * @since CakePHP(tm) v 0.2.9 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('AppController', 'Controller'); /** * Static content controller diff --git a/lib/Cake/Controller/CakeErrorController.php b/lib/Cake/Controller/CakeErrorController.php index 577864881..14447710c 100644 --- a/lib/Cake/Controller/CakeErrorController.php +++ b/lib/Cake/Controller/CakeErrorController.php @@ -18,6 +18,7 @@ * @since CakePHP(tm) v 2.0 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('AppController', 'Controller'); /** * Error Handling Controller diff --git a/lib/Cake/Controller/Component/PaginatorComponent.php b/lib/Cake/Controller/Component/PaginatorComponent.php index 163e487c6..bc89ec0b2 100644 --- a/lib/Cake/Controller/Component/PaginatorComponent.php +++ b/lib/Cake/Controller/Component/PaginatorComponent.php @@ -16,6 +16,7 @@ * @since CakePHP(tm) v 2.0 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('Component', 'Controller/Component'); App::uses('Hash', 'Utility'); /** diff --git a/lib/Cake/Controller/Component/RequestHandlerComponent.php b/lib/Cake/Controller/Component/RequestHandlerComponent.php index 544e01cd1..dbeeb3b98 100644 --- a/lib/Cake/Controller/Component/RequestHandlerComponent.php +++ b/lib/Cake/Controller/Component/RequestHandlerComponent.php @@ -19,6 +19,7 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('Component', 'Controller/Component'); App::uses('Xml', 'Utility'); /** diff --git a/lib/Cake/Model/Behavior/AclBehavior.php b/lib/Cake/Model/Behavior/AclBehavior.php index d0f0a4ca3..848e82a4c 100644 --- a/lib/Cake/Model/Behavior/AclBehavior.php +++ b/lib/Cake/Model/Behavior/AclBehavior.php @@ -18,6 +18,7 @@ * @since CakePHP v 1.2.0.4487 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('ModelBehavior', 'Model/Behavior'); App::uses('AclNode', 'Model'); App::uses('Hash', 'Utility'); diff --git a/lib/Cake/Model/Behavior/ContainableBehavior.php b/lib/Cake/Model/Behavior/ContainableBehavior.php index 98c067468..321003448 100644 --- a/lib/Cake/Model/Behavior/ContainableBehavior.php +++ b/lib/Cake/Model/Behavior/ContainableBehavior.php @@ -18,6 +18,7 @@ * @since CakePHP(tm) v 1.2.0.5669 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('ModelBehavior', 'Model/Behavior'); /** * Behavior to allow for dynamic and atomic manipulation of a Model's associations diff --git a/lib/Cake/Model/Behavior/TranslateBehavior.php b/lib/Cake/Model/Behavior/TranslateBehavior.php index 387a37f0f..bde81d51c 100644 --- a/lib/Cake/Model/Behavior/TranslateBehavior.php +++ b/lib/Cake/Model/Behavior/TranslateBehavior.php @@ -13,6 +13,7 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('ModelBehavior', 'Model/Behavior'); App::uses('I18n', 'I18n'); App::uses('I18nModel', 'Model'); diff --git a/lib/Cake/Model/Behavior/TreeBehavior.php b/lib/Cake/Model/Behavior/TreeBehavior.php index 365d26002..77b4fe88b 100644 --- a/lib/Cake/Model/Behavior/TreeBehavior.php +++ b/lib/Cake/Model/Behavior/TreeBehavior.php @@ -18,6 +18,7 @@ * @since CakePHP v 1.2.0.4487 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('ModelBehavior', 'Model/Behavior'); /** * Tree Behavior. diff --git a/lib/Cake/Model/I18nModel.php b/lib/Cake/Model/I18nModel.php index 9b185064b..329f7cb50 100644 --- a/lib/Cake/Model/I18nModel.php +++ b/lib/Cake/Model/I18nModel.php @@ -12,6 +12,7 @@ * @since CakePHP(tm) v 1.2.0.4525 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +App::uses('AppModel', 'Model'); /** * A model used by TranslateBehavior to access the translation tables. From 27a895d7d8789334def82f32402c6bb282ed632a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Gonz=C3=A1lez?= Date: Sat, 21 Jul 2012 14:23:47 +0100 Subject: [PATCH 025/256] adding enableCrypto() method to CakeSocket class --- lib/Cake/Network/CakeSocket.php | 53 ++++++++- lib/Cake/Test/Case/Network/CakeSocketTest.php | 109 ++++++++++++++++++ 2 files changed, 161 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Network/CakeSocket.php b/lib/Cake/Network/CakeSocket.php index aa0eb4fbd..d1d597ff6 100644 --- a/lib/Cake/Network/CakeSocket.php +++ b/lib/Cake/Network/CakeSocket.php @@ -76,6 +76,27 @@ class CakeSocket { */ public $lastError = array(); +/** + * True if the socket stream is encrypted after a CakeSocket::enableCrypto() call + * @var type + */ + public $encrypted = false; + +/** + * Contains all the encryption methods available + * @var array + */ + protected $_encryptMethods = array( + 'sslv2_client' => STREAM_CRYPTO_METHOD_SSLv2_CLIENT, + 'sslv3_client' => STREAM_CRYPTO_METHOD_SSLv3_CLIENT, + 'sslv23_client' =>STREAM_CRYPTO_METHOD_SSLv23_CLIENT, + 'tls_client' => STREAM_CRYPTO_METHOD_TLS_CLIENT, + 'sslv2_server' => STREAM_CRYPTO_METHOD_SSLv2_SERVER, + 'sslv3_server' => STREAM_CRYPTO_METHOD_SSLv3_SERVER, + 'sslv23_server' => STREAM_CRYPTO_METHOD_SSLv23_SERVER, + 'tls_server' => STREAM_CRYPTO_METHOD_TLS_SERVER + ); + /** * Constructor. * @@ -277,4 +298,34 @@ class CakeSocket { return true; } -} +/** + * Encrypts current stream socket, using one of the defined encryption methods + * + * @param string $type can be one of 'ssl2', 'ssl3', 'ssl23' or 'tls' + * @param string $clientOrServer can be one of 'client', 'server'. Default is 'client' + * @param boolean $enable enable or disable encryption. Default is true (enable) + * @return boolean True on success + * @throws SocketException + * @see stream_socket_enable_crypto + */ + public function enableCrypto($type, $clientOrServer = 'client', $enable = true) { + if (!array_key_exists($type . '_' . $clientOrServer, $this->_encryptMethods)) { + throw new InvalidArgumentException(); + } + $enableCryptoResult = false; + try { + $enableCryptoResult = stream_socket_enable_crypto($this->connection, $enable, $this->_encryptMethods[$type . '_' . $clientOrServer]); + } catch (Exception $e) { + $this->setLastError(null, $e->getMessage()); + throw new SocketException($e->getMessage()); + } + if ($enableCryptoResult === true) { + $this->encrypted = $enable; + return true; + } else { + $errorMessage = __('Unable to perform enableCrypto operation on CakeSocket'); + $this->setLastError(null, $errorMessage); + throw new SocketException($errorMessage); + } + } +} \ No newline at end of file diff --git a/lib/Cake/Test/Case/Network/CakeSocketTest.php b/lib/Cake/Test/Case/Network/CakeSocketTest.php index abe6fcadf..9baf63df3 100644 --- a/lib/Cake/Test/Case/Network/CakeSocketTest.php +++ b/lib/Cake/Test/Case/Network/CakeSocketTest.php @@ -214,4 +214,113 @@ class CakeSocketTest extends CakeTestCase { $anotherSocket->reset(); $this->assertEquals(array(), $anotherSocket->config); } + +/** + * testEncrypt + * + * @return void + */ + public function testEnableCryptoSocketExceptionNoSsl() { + $configNoSslOrTls = array('host' => 'localhost', 'port' => 80, 'timeout' => 0.1); + + // testing exception on no ssl socket server for ssl and tls methods + $this->Socket = new CakeSocket($configNoSslOrTls); + $this->Socket->connect(); + $this->setExpectedException('SocketException'); + $this->Socket->enableCrypto('sslv3', 'client'); + } + +/** + * testEnableCryptoSocketExceptionNoTls + * + * @return void + */ + public function testEnableCryptoSocketExceptionNoTls() { + $configNoSslOrTls = array('host' => 'localhost', 'port' => 80, 'timeout' => 0.1); + + // testing exception on no ssl socket server for ssl and tls methods + $this->Socket = new CakeSocket($configNoSslOrTls); + $this->Socket->connect(); + $this->setExpectedException('SocketException'); + $this->Socket->enableCrypto('tls', 'client'); + } + +/** + * _connectSocketToSslTls + * + * @return void + */ + protected function _connectSocketToSslTls() { + $configSslTls = array('host' => 'smtp.gmail.com', 'port' => 465, 'timeout' => 5); + $this->Socket = new CakeSocket($configSslTls); + $this->Socket->connect(); + } + +/** + * testEnableCryptoBadMode + * + * @return void + */ + public function testEnableCryptoBadMode() { + // testing wrong encryption mode + $this->_connectSocketToSslTls(); + $this->setExpectedException('InvalidArgumentException'); + $this->Socket->enableCrypto('doesntExistMode', 'server'); + $this->Socket->disconnect(); + } + +/** + * testEnableCrypto + * + * @return void + */ + public function testEnableCrypto() { + // testing on ssl server + $this->_connectSocketToSslTls(); + $this->assertTrue($this->Socket->enableCrypto('sslv3', 'client')); + $this->Socket->disconnect(); + + // testing on tls server + $this->_connectSocketToSslTls(); + $this->assertTrue($this->Socket->enableCrypto('tls', 'client')); + $this->Socket->disconnect(); + } + +/** + * testEnableCryptoExceptionEnableTwice + * + * @return void + */ + public function testEnableCryptoExceptionEnableTwice() { + // testing on tls server + $this->_connectSocketToSslTls(); + $this->Socket->enableCrypto('tls', 'client'); + $this->setExpectedException('SocketException'); + $this->Socket->enableCrypto('tls', 'client'); + } + +/** + * testEnableCryptoExceptionDisableTwice + * + * @return void + */ + public function testEnableCryptoExceptionDisableTwice() { + // testing on tls server + $this->_connectSocketToSslTls(); + $this->setExpectedException('SocketException'); + $this->Socket->enableCrypto('tls', 'client', false); + } + +/** + * testEnableCryptoEnableStatus + * + * @return void + */ + public function testEnableCryptoEnableStatus() { + // testing on tls server + $this->_connectSocketToSslTls(); + $this->assertFalse($this->Socket->encrypted); + $this->Socket->enableCrypto('tls', 'client', true); + $this->assertTrue($this->Socket->encrypted); + } } From 6557e3bafe6fe0dfcaa8dd5d654309cac12120a1 Mon Sep 17 00:00:00 2001 From: euromark Date: Sat, 21 Jul 2012 15:23:54 +0200 Subject: [PATCH 026/256] only try to get comparison failure for the appropriate object --- lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php b/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php index 5bd2695ce..e05ee621a 100644 --- a/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php +++ b/lib/Cake/TestSuite/Reporter/CakeHtmlReporter.php @@ -249,10 +249,12 @@ class CakeHtmlReporter extends CakeBaseReporter { $testName = get_class($test) . '(' . $test->getName() . ')'; $actualMsg = $expectedMsg = null; - $failure = $message->getComparisonFailure(); - if (is_object($failure)) { - $actualMsg = $message->getComparisonFailure()->getActualAsString(); - $expectedMsg = $message->getComparisonFailure()->getExpectedAsString(); + if (method_exists($message, 'comparisonFailure')) { + $failure = $message->comparisonFailure(); + if (is_object($failure)) { + $actualMsg = $message->getComparisonFailure()->getActualAsString(); + $expectedMsg = $message->getComparisonFailure()->getExpectedAsString(); + } } echo "
  • \n"; From 2e71ef8f261f9e8226fe5cb80f23f277dbe65944 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 21 Jul 2012 14:08:10 -0400 Subject: [PATCH 027/256] Add CakeSession Fixture CakePHP should provide a fixture for the default session table name so developers don't need to add the same fixture to each application. Fixes #3054 --- lib/Cake/Test/Fixture/CakeSessionFixture.php | 47 ++++++++++++++++++++ 1 file changed, 47 insertions(+) create mode 100644 lib/Cake/Test/Fixture/CakeSessionFixture.php diff --git a/lib/Cake/Test/Fixture/CakeSessionFixture.php b/lib/Cake/Test/Fixture/CakeSessionFixture.php new file mode 100644 index 000000000..5b7f43025 --- /dev/null +++ b/lib/Cake/Test/Fixture/CakeSessionFixture.php @@ -0,0 +1,47 @@ + + * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * + * Licensed under The MIT License + * Redistributions of files must retain the above copyright notice + * + * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) + * @link http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests + * @package Cake.Test.Fixture + * @since CakePHP(tm) v 2.3.0 + * @license MIT License (http://www.opensource.org/licenses/mit-license.php) + */ + +/** + * Fixture class for the default session configuration + * + * @package Cake.Test.Fixture + */ +class CakeSessionFixture extends CakeTestFixture { + +/** + * name property + * + * @var string + */ + public $name = 'CakeSession'; + +/** + * fields property + * + * @var array + */ + public $fields = array( + 'id' => array('type' => 'string', 'length' => 128, 'key' => 'primary'), + 'data' => array('type' => 'text','null' => true), + 'expires' => array('type' => 'integer', 'length' => 11, 'null' => true) + ); + +/** + * records property + * + * @var array + */ + public $records = array(); +} From 01f1b0dadcb33172b993b579a510c8a8cd79d336 Mon Sep 17 00:00:00 2001 From: euromark Date: Sat, 21 Jul 2012 20:29:49 +0200 Subject: [PATCH 028/256] correcting previously added app uses statements --- lib/Cake/Model/Behavior/AclBehavior.php | 2 +- lib/Cake/Model/Behavior/ContainableBehavior.php | 2 +- lib/Cake/Model/Behavior/TranslateBehavior.php | 2 +- lib/Cake/Model/Behavior/TreeBehavior.php | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/Cake/Model/Behavior/AclBehavior.php b/lib/Cake/Model/Behavior/AclBehavior.php index 848e82a4c..e35f0a0d5 100644 --- a/lib/Cake/Model/Behavior/AclBehavior.php +++ b/lib/Cake/Model/Behavior/AclBehavior.php @@ -18,7 +18,7 @@ * @since CakePHP v 1.2.0.4487 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::uses('ModelBehavior', 'Model/Behavior'); +App::uses('ModelBehavior', 'Model'); App::uses('AclNode', 'Model'); App::uses('Hash', 'Utility'); diff --git a/lib/Cake/Model/Behavior/ContainableBehavior.php b/lib/Cake/Model/Behavior/ContainableBehavior.php index 321003448..e81df035c 100644 --- a/lib/Cake/Model/Behavior/ContainableBehavior.php +++ b/lib/Cake/Model/Behavior/ContainableBehavior.php @@ -18,7 +18,7 @@ * @since CakePHP(tm) v 1.2.0.5669 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::uses('ModelBehavior', 'Model/Behavior'); +App::uses('ModelBehavior', 'Model'); /** * Behavior to allow for dynamic and atomic manipulation of a Model's associations diff --git a/lib/Cake/Model/Behavior/TranslateBehavior.php b/lib/Cake/Model/Behavior/TranslateBehavior.php index bde81d51c..033fe55fc 100644 --- a/lib/Cake/Model/Behavior/TranslateBehavior.php +++ b/lib/Cake/Model/Behavior/TranslateBehavior.php @@ -13,7 +13,7 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::uses('ModelBehavior', 'Model/Behavior'); +App::uses('ModelBehavior', 'Model'); App::uses('I18n', 'I18n'); App::uses('I18nModel', 'Model'); diff --git a/lib/Cake/Model/Behavior/TreeBehavior.php b/lib/Cake/Model/Behavior/TreeBehavior.php index 77b4fe88b..6cc5deb4f 100644 --- a/lib/Cake/Model/Behavior/TreeBehavior.php +++ b/lib/Cake/Model/Behavior/TreeBehavior.php @@ -18,7 +18,7 @@ * @since CakePHP v 1.2.0.4487 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::uses('ModelBehavior', 'Model/Behavior'); +App::uses('ModelBehavior', 'Model'); /** * Tree Behavior. From 55c92065c674a9241b2ee36c32865a85b75d4443 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Gonz=C3=A1lez?= Date: Sat, 21 Jul 2012 20:28:38 +0100 Subject: [PATCH 029/256] adding a tls option to SmtpTransport to support TLS SMTP servers like MS Exchange 2010 --- lib/Cake/Network/Email/SmtpTransport.php | 13 +++- .../Case/Network/Email/SmtpTransportTest.php | 66 ++++++++++++++++++- 2 files changed, 77 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Network/Email/SmtpTransport.php b/lib/Cake/Network/Email/SmtpTransport.php index 363e477e8..eb3c13595 100644 --- a/lib/Cake/Network/Email/SmtpTransport.php +++ b/lib/Cake/Network/Email/SmtpTransport.php @@ -79,7 +79,8 @@ class SmtpTransport extends AbstractTransport { 'timeout' => 30, 'username' => null, 'password' => null, - 'client' => null + 'client' => null, + 'tls' => false ); $this->_config = $config + $default; } @@ -107,7 +108,15 @@ class SmtpTransport extends AbstractTransport { try { $this->_smtpSend("EHLO {$host}", '250'); + if ($this->_config['tls']) { + $this->_smtpSend("STARTTLS", '220'); + $this->_socket->enableCrypto('tls'); + $this->_smtpSend("EHLO {$host}", '250'); + } } catch (SocketException $e) { + if ($this->_config['tls']) { + throw new SocketException(__d('cake_dev', 'SMTP server did not accept the connection or trying to connect to non TLS SMTP server using TLS.')); + } try { $this->_smtpSend("HELO {$host}", '250'); } catch (SocketException $e2) { @@ -132,6 +141,8 @@ class SmtpTransport extends AbstractTransport { if (!$this->_smtpSend(base64_encode($this->_config['password']), '235')) { throw new SocketException(__d('cake_dev', 'SMTP server did not accept the password.')); } + } elseif ($authRequired == '504') { + throw new SocketException(__d('cake_dev', 'SMTP authentication method not allowed, check if SMTP server requires TLS')); } elseif ($authRequired != '503') { throw new SocketException(__d('cake_dev', 'SMTP does not require authentication.')); } diff --git a/lib/Cake/Test/Case/Network/Email/SmtpTransportTest.php b/lib/Cake/Test/Case/Network/Email/SmtpTransportTest.php index 0310e5320..f5fa2f95d 100644 --- a/lib/Cake/Test/Case/Network/Email/SmtpTransportTest.php +++ b/lib/Cake/Test/Case/Network/Email/SmtpTransportTest.php @@ -81,7 +81,7 @@ class SmtpTransportTest extends CakeTestCase { */ public function setUp() { if (!class_exists('MockSocket')) { - $this->getMock('CakeSocket', array('read', 'write', 'connect'), array(), 'MockSocket'); + $this->getMock('CakeSocket', array('read', 'write', 'connect', 'enableCrypto'), array(), 'MockSocket'); } $this->socket = new MockSocket(); @@ -105,6 +105,70 @@ class SmtpTransportTest extends CakeTestCase { $this->SmtpTransport->connect(); } +/** + * testConnectEhloTls method + * + * @return void + */ + public function testConnectEhloTls() { + $this->SmtpTransport->config(array('tls' => true)); + $this->socket->expects($this->any())->method('connect')->will($this->returnValue(true)); + $this->socket->expects($this->at(0))->method('read')->will($this->returnValue(false)); + $this->socket->expects($this->at(1))->method('read')->will($this->returnValue("220 Welcome message\r\n")); + $this->socket->expects($this->at(2))->method('write')->with("EHLO localhost\r\n"); + $this->socket->expects($this->at(3))->method('read')->will($this->returnValue(false)); + $this->socket->expects($this->at(4))->method('read')->will($this->returnValue("250 Accepted\r\n")); + $this->socket->expects($this->at(5))->method('write')->with("STARTTLS\r\n"); + $this->socket->expects($this->at(6))->method('read')->will($this->returnValue(false)); + $this->socket->expects($this->at(7))->method('read')->will($this->returnValue("220 Server ready\r\n")); + $this->socket->expects($this->at(8))->method('other')->with('tls')->will($this->returnValue(true)); + $this->socket->expects($this->at(9))->method('write')->with("EHLO localhost\r\n"); + $this->socket->expects($this->at(10))->method('read')->will($this->returnValue(false)); + $this->socket->expects($this->at(11))->method('read')->will($this->returnValue("250 Accepted\r\n")); + $this->SmtpTransport->connect(); + } + +/** + * testConnectEhloTlsOnNonTlsServer method + * + * @return void + */ + public function testConnectEhloTlsOnNonTlsServer() { + $this->SmtpTransport->config(array('tls' => true)); + $this->socket->expects($this->any())->method('connect')->will($this->returnValue(true)); + $this->socket->expects($this->at(0))->method('read')->will($this->returnValue(false)); + $this->socket->expects($this->at(1))->method('read')->will($this->returnValue("220 Welcome message\r\n")); + $this->socket->expects($this->at(2))->method('write')->with("EHLO localhost\r\n"); + $this->socket->expects($this->at(3))->method('read')->will($this->returnValue(false)); + $this->socket->expects($this->at(4))->method('read')->will($this->returnValue("250 Accepted\r\n")); + $this->socket->expects($this->at(5))->method('write')->with("STARTTLS\r\n"); + $this->socket->expects($this->at(6))->method('read')->will($this->returnValue(false)); + $this->socket->expects($this->at(7))->method('read')->will($this->returnValue("500 5.3.3 Unrecognized command\r\n")); + $this->setExpectedException('SocketException'); + $this->SmtpTransport->connect(); + } + +/** + * testConnectEhloNoTlsOnRequiredTlsServer method + * + * @return void + */ + public function testConnectEhloNoTlsOnRequiredTlsServer() { + $this->SmtpTransport->config(array('tls' => false, 'username' => 'user', 'password' => 'pass')); + $this->socket->expects($this->any())->method('connect')->will($this->returnValue(true)); + $this->socket->expects($this->at(0))->method('read')->will($this->returnValue(false)); + $this->socket->expects($this->at(1))->method('read')->will($this->returnValue("220 Welcome message\r\n")); + $this->socket->expects($this->at(2))->method('write')->with("EHLO localhost\r\n"); + $this->socket->expects($this->at(3))->method('read')->will($this->returnValue(false)); + $this->socket->expects($this->at(4))->method('read')->will($this->returnValue("250 Accepted\r\n")); + $this->socket->expects($this->at(5))->method('read')->with("AUTH LOGIN\r\n"); + $this->socket->expects($this->at(6))->method('read')->will($this->returnValue(false)); + $this->socket->expects($this->at(7))->method('read')->will($this->returnValue("504 5.7.4 Unrecognized authentication type\r\n")); + $this->setExpectedException('SocketException'); + $this->SmtpTransport->connect(); + $this->SmtpTransport->auth(); + } + /** * testConnectHelo method * From 9deb9666575d17b1d8c10232e7b7a6a8e5a258cc Mon Sep 17 00:00:00 2001 From: Joey Jan Date: Tue, 17 Jul 2012 12:18:35 -0500 Subject: [PATCH 030/256] Add ability to disable content-disposition for email attachments. This solves issues with outlook and text/calendar attachments. Refs #3042 --- lib/Cake/Network/Email/CakeEmail.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Network/Email/CakeEmail.php b/lib/Cake/Network/Email/CakeEmail.php index 8beac4c74..210f72f6e 100644 --- a/lib/Cake/Network/Email/CakeEmail.php +++ b/lib/Cake/Network/Email/CakeEmail.php @@ -1355,7 +1355,9 @@ class CakeEmail { $msg[] = '--' . $boundary; $msg[] = 'Content-Type: ' . $fileInfo['mimetype']; $msg[] = 'Content-Transfer-Encoding: base64'; - $msg[] = 'Content-Disposition: attachment; filename="' . $filename . '"'; + if (!isset($fileInfo['contentDisposition']) || $fileInfo['contentDisposition']) { + $msg[] = 'Content-Disposition: attachment; filename="' . $filename . '"'; + } $msg[] = ''; $msg[] = $data; $msg[] = ''; From 6ce4a3a1ec5994e2b60180875812f6953d0490bf Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 21 Jul 2012 21:22:04 -0400 Subject: [PATCH 031/256] Add tests for contentDisposition flag. Fixes #3042 --- lib/Cake/Network/Email/CakeEmail.php | 5 +- .../Test/Case/Network/Email/CakeEmailTest.php | 48 ++++++++++++++++++- 2 files changed, 50 insertions(+), 3 deletions(-) diff --git a/lib/Cake/Network/Email/CakeEmail.php b/lib/Cake/Network/Email/CakeEmail.php index 210f72f6e..07f02728b 100644 --- a/lib/Cake/Network/Email/CakeEmail.php +++ b/lib/Cake/Network/Email/CakeEmail.php @@ -1355,7 +1355,10 @@ class CakeEmail { $msg[] = '--' . $boundary; $msg[] = 'Content-Type: ' . $fileInfo['mimetype']; $msg[] = 'Content-Transfer-Encoding: base64'; - if (!isset($fileInfo['contentDisposition']) || $fileInfo['contentDisposition']) { + if ( + !isset($fileInfo['contentDisposition']) || + $fileInfo['contentDisposition'] + ) { $msg[] = 'Content-Disposition: attachment; filename="' . $filename . '"'; } $msg[] = ''; diff --git a/lib/Cake/Test/Case/Network/Email/CakeEmailTest.php b/lib/Cake/Test/Case/Network/Email/CakeEmailTest.php index cde649558..984c51865 100644 --- a/lib/Cake/Test/Case/Network/Email/CakeEmailTest.php +++ b/lib/Cake/Test/Case/Network/Email/CakeEmailTest.php @@ -640,13 +640,20 @@ class CakeEmailTest extends CakeTestCase { */ public function testAttachments() { $this->CakeEmail->attachments(CAKE . 'basics.php'); - $expected = array('basics.php' => array('file' => CAKE . 'basics.php', 'mimetype' => 'application/octet-stream')); + $expected = array( + 'basics.php' => array( + 'file' => CAKE . 'basics.php', + 'mimetype' => 'application/octet-stream' + ) + ); $this->assertSame($this->CakeEmail->attachments(), $expected); $this->CakeEmail->attachments(array()); $this->assertSame($this->CakeEmail->attachments(), array()); - $this->CakeEmail->attachments(array(array('file' => CAKE . 'basics.php', 'mimetype' => 'text/plain'))); + $this->CakeEmail->attachments(array( + array('file' => CAKE . 'basics.php', 'mimetype' => 'text/plain') + )); $this->CakeEmail->addAttachments(CAKE . 'bootstrap.php'); $this->CakeEmail->addAttachments(array(CAKE . 'bootstrap.php')); $this->CakeEmail->addAttachments(array('other.txt' => CAKE . 'bootstrap.php', 'license' => CAKE . 'LICENSE.txt')); @@ -937,6 +944,43 @@ class CakeEmailTest extends CakeTestCase { $this->assertContains('--' . $boundary . '--', $result['message']); } +/** + * Test disabling content-disposition. + * + * @return void + */ + public function testSendWithNoContentDispositionAttachments() { + $this->CakeEmail->transport('debug'); + $this->CakeEmail->from('cake@cakephp.org'); + $this->CakeEmail->to('cake@cakephp.org'); + $this->CakeEmail->subject('My title'); + $this->CakeEmail->emailFormat('text'); + $this->CakeEmail->attachments(array( + 'cake.png' => array( + 'file' => CAKE . 'VERSION.txt', + 'contentDisposition' => false + ) + )); + $result = $this->CakeEmail->send('Hello'); + + $boundary = $this->CakeEmail->getBoundary(); + $this->assertContains('Content-Type: multipart/mixed; boundary="' . $boundary . '"', $result['headers']); + $expected = "--$boundary\r\n" . + "Content-Type: text/plain; charset=UTF-8\r\n" . + "Content-Transfer-Encoding: 8bit\r\n" . + "\r\n" . + "Hello" . + "\r\n" . + "\r\n" . + "\r\n" . + "--{$boundary}\r\n" . + "Content-Type: application/octet-stream\r\n" . + "Content-Transfer-Encoding: base64\r\n" . + "\r\n"; + + $this->assertContains($expected, $result['message']); + $this->assertContains('--' . $boundary . '--', $result['message']); + } /** * testSendWithLog method * From 71507796c7cb6a00e31a9b7d3e60b25574237eb0 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 21 Jul 2012 21:35:45 -0400 Subject: [PATCH 032/256] Add docs. --- .../Controller/Component/PaginatorComponent.php | 14 ++++++++++++++ lib/Cake/Network/Email/CakeEmail.php | 7 ++++++- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Controller/Component/PaginatorComponent.php b/lib/Cake/Controller/Component/PaginatorComponent.php index bc89ec0b2..b09dbd5ea 100644 --- a/lib/Cake/Controller/Component/PaginatorComponent.php +++ b/lib/Cake/Controller/Component/PaginatorComponent.php @@ -51,6 +51,20 @@ App::uses('Hash', 'Utility'); * * This would allow you to have different pagination settings for `Comment` and `Post` models. * + * #### Paginating with custom finders + * + * You can paginate with any find type defined on your model using the `findType` option. + * + * {{{ + * $this->Paginator->settings = array( + * 'Post' => array( + * 'findType' => 'popular' + * ) + * ); + * }}} + * + * Would paginate using the `find('popular')` method. + * * @package Cake.Controller.Component * @link http://book.cakephp.org/2.0/en/core-libraries/components/pagination.html */ diff --git a/lib/Cake/Network/Email/CakeEmail.php b/lib/Cake/Network/Email/CakeEmail.php index 07f02728b..61371dc8c 100644 --- a/lib/Cake/Network/Email/CakeEmail.php +++ b/lib/Cake/Network/Email/CakeEmail.php @@ -946,13 +946,17 @@ class CakeEmail { * $email->attachments(array('custom_name.png' => array( * 'file' => 'path/to/file', * 'mimetype' => 'image/png', - * 'contentId' => 'abc123' + * 'contentId' => 'abc123', + * 'contentDisposition' => false * )); * }}} * * The `contentId` key allows you to specify an inline attachment. In your email text, you * can use `` to display the image inline. * + * The `contentDisposition` key allows you to disable the `Content-Disposition` header, this can improve + * attachment compatibility with outlook email clients. + * * @param string|array $attachments String with the filename or array with filenames * @return array|CakeEmail Either the array of attachments when getting or $this when setting. * @throws SocketException @@ -991,6 +995,7 @@ class CakeEmail { * @param string|array $attachments String with the filename or array with filenames * @return CakeEmail $this * @throws SocketException + * @see CakeEmail::attachments() */ public function addAttachments($attachments) { $current = $this->_attachments; From 93eb8c2c58564666d3c83cea8e79d09316857762 Mon Sep 17 00:00:00 2001 From: euromark Date: Sun, 22 Jul 2012 03:38:39 +0200 Subject: [PATCH 033/256] another correction for app uses --- lib/Cake/Controller/Component/PaginatorComponent.php | 2 +- lib/Cake/Controller/Component/RequestHandlerComponent.php | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Controller/Component/PaginatorComponent.php b/lib/Cake/Controller/Component/PaginatorComponent.php index bc89ec0b2..6d3b338b4 100644 --- a/lib/Cake/Controller/Component/PaginatorComponent.php +++ b/lib/Cake/Controller/Component/PaginatorComponent.php @@ -16,7 +16,7 @@ * @since CakePHP(tm) v 2.0 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::uses('Component', 'Controller/Component'); +App::uses('Component', 'Controller'); App::uses('Hash', 'Utility'); /** diff --git a/lib/Cake/Controller/Component/RequestHandlerComponent.php b/lib/Cake/Controller/Component/RequestHandlerComponent.php index dbeeb3b98..d6a182b7e 100644 --- a/lib/Cake/Controller/Component/RequestHandlerComponent.php +++ b/lib/Cake/Controller/Component/RequestHandlerComponent.php @@ -19,7 +19,7 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ -App::uses('Component', 'Controller/Component'); +App::uses('Component', 'Controller'); App::uses('Xml', 'Utility'); /** From 93957bc3e48c3e844f65fae3ecc1bac7c34faa42 Mon Sep 17 00:00:00 2001 From: euromark Date: Sun, 22 Jul 2012 03:55:13 +0200 Subject: [PATCH 034/256] fix for windows. the check seems to be the wrong way. at least compared to the one in the rss class itself --- lib/Cake/Test/Case/View/Helper/RssHelperTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Test/Case/View/Helper/RssHelperTest.php b/lib/Cake/Test/Case/View/Helper/RssHelperTest.php index bfffdf4fc..0c833606a 100644 --- a/lib/Cake/Test/Case/View/Helper/RssHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/RssHelperTest.php @@ -642,8 +642,7 @@ class RssHelperTest extends CakeTestCase { ) ); $result = $this->Rss->item(null, $item); - if (!function_exists('finfo_open') && - (function_exists('mime_content_type') && false === mime_content_type($tmpFile)) + if (!function_exists('finfo_open') || !function_exists('mime_content_type') || mime_content_type($tmpFile) === false ) { $type = false; } else { @@ -679,6 +678,9 @@ class RssHelperTest extends CakeTestCase { '/category', '/item' ); + if (!$type) { + unset($expected['enclosure']['type']); + } $this->assertTags($result, $expected); $File->delete(); From 15cf55d444871d30535f077f1fbc55257b123aa0 Mon Sep 17 00:00:00 2001 From: euromark Date: Sun, 22 Jul 2012 03:59:59 +0200 Subject: [PATCH 035/256] different approach on the failing test --- lib/Cake/Test/Case/View/Helper/RssHelperTest.php | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/Cake/Test/Case/View/Helper/RssHelperTest.php b/lib/Cake/Test/Case/View/Helper/RssHelperTest.php index 0c833606a..a7491f02a 100644 --- a/lib/Cake/Test/Case/View/Helper/RssHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/RssHelperTest.php @@ -642,12 +642,12 @@ class RssHelperTest extends CakeTestCase { ) ); $result = $this->Rss->item(null, $item); - if (!function_exists('finfo_open') || !function_exists('mime_content_type') || mime_content_type($tmpFile) === false - ) { - $type = false; + if (!function_exists('mime_content_type')) { + $type = null; } else { - $type = 'text/plain'; + $type = mime_content_type($tmpFile); } + $expected = array( 'assertTags($result, $expected); From 434d3a71377b52edf0af94d13e31594a785eac20 Mon Sep 17 00:00:00 2001 From: Heath Nail Date: Sat, 21 Jul 2012 12:48:14 -0400 Subject: [PATCH 036/256] Add bcrypt support to Security::hash() --- lib/Cake/Test/Case/Utility/SecurityTest.php | 56 ++++++++++ lib/Cake/Utility/Security.php | 111 ++++++++++++++++++-- 2 files changed, 159 insertions(+), 8 deletions(-) diff --git a/lib/Cake/Test/Case/Utility/SecurityTest.php b/lib/Cake/Test/Case/Utility/SecurityTest.php index cb323d9dd..e7ddced30 100644 --- a/lib/Cake/Test/Case/Utility/SecurityTest.php +++ b/lib/Cake/Test/Case/Utility/SecurityTest.php @@ -67,6 +67,46 @@ class SecurityTest extends CakeTestCase { $this->assertTrue(Security::validateAuthKey($authKey)); } +/** + * testHashInvalidSalt method + * + * @expectedException PHPUnit_Framework_Error + * @return void + */ + public function testHashInvalidSalt() { + $result = Security::hash('someKey', 'blowfish', true); + } + +/** + * testHashAnotherInvalidSalt + * + * @expectedException PHPUnit_Framework_Error + * @return void + */ + public function testHashAnotherInvalidSalt() { + $result = Security::hash('someKey', 'blowfish', '$1$lksdjoijfaoijs'); + } + +/** + * testHashYetAnotherInvalidSalt + * + * @expectedException PHPUnit_Framework_Error + * @return void + */ + public function testHashYetAnotherInvalidSalt() { + $result = Security::hash('someKey', 'blowfish', '$2a$10$123'); + } + +/** + * testHashInvalidCost method + * + * @expectedException PHPUnit_Framework_Error + * @return void + */ + public function testHashInvalidCost() { + Security::setCost(1000); + $result = Security::hash('somekey', 'blowfish', false); + } /** * testHash method * @@ -112,6 +152,22 @@ class SecurityTest extends CakeTestCase { $this->assertSame(strlen(Security::hash($key, 'sha256', true)), 64); } + $hashType = 'blowfish'; + Security::setHash($hashType); + Security::setCost(10); // ensure default cost + $this->assertSame(Security::$hashType, $hashType); + $this->assertSame(strlen(Security::hash($key, null, false)), 60); + + $password = $submittedPassword = $key; + $storedPassword = Security::hash($password); + + $hashedPassword = Security::hash($submittedPassword, null, $storedPassword); + $this->assertSame($storedPassword, $hashedPassword); + + $submittedPassword = 'someOtherKey'; + $hashedPassword = Security::hash($submittedPassword, null, $storedPassword); + $this->assertNotSame($storedPassword, $hashedPassword); + Security::setHash($_hashType); } diff --git a/lib/Cake/Utility/Security.php b/lib/Cake/Utility/Security.php index 6438338a2..c9f41008d 100644 --- a/lib/Cake/Utility/Security.php +++ b/lib/Cake/Utility/Security.php @@ -33,6 +33,13 @@ class Security { */ public static $hashType = null; +/** + * Default cost + * + * @var string + */ + public static $hashCost = '10'; + /** * Get allowed minutes of inactivity based on security level. * @@ -76,14 +83,26 @@ class Security { /** * Create a hash from string using given method. * Fallback on next available method. + * If you are using blowfish, for comparisons simply pass the originally hashed + * string as the salt (the salt is prepended to the hash and php handles the + * parsing automagically. Do NOT use a constant salt for blowfish. * * @param string $string String to hash * @param string $type Method to use (sha1/sha256/md5) - * @param boolean $salt If true, automatically appends the application's salt - * value to $string (Security.salt) + * @param mixed $salt If true, automatically appends the application's salt + * value to $string (Security.salt). If you are using blowfish the salt + * must be false or a previously generated salt. * @return string Hash */ public static function hash($string, $type = null, $salt = false) { + if (empty($type)) { + $type = self::$hashType; + } + $type = strtolower($type); + + if ($type === 'blowfish') { + return self::_crypt($string, $type, $salt); + } if ($salt) { if (is_string($salt)) { $string = $salt . $string; @@ -92,11 +111,6 @@ class Security { } } - if (empty($type)) { - $type = self::$hashType; - } - $type = strtolower($type); - if ($type == 'sha1' || $type == null) { if (function_exists('sha1')) { $return = sha1($string); @@ -119,7 +133,7 @@ class Security { * Sets the default hash method for the Security object. This affects all objects using * Security::hash(). * - * @param string $hash Method to use (sha1/sha256/md5) + * @param string $hash Method to use (sha1/sha256/md5/blowfish) * @return void * @see Security::hash() */ @@ -127,6 +141,16 @@ class Security { self::$hashType = $hash; } +/** + * Sets the cost for they blowfish hash method. + * + * @param integer $cost Valid values are 4-31 + * @return void + */ + public static function setCost($cost) { + self::$hashCost = $cost; + } + /** * Encrypts/Decrypts a text using the given key. * @@ -189,4 +213,75 @@ class Security { return $out; } +/** + * Generates a pseudo random salt suitable for use with php's crypt() function. + * The salt length should not exceed 27. The salt will be composed of + * [./0-9A-Za-z]{$length}. + * + * @param integer $length The length of the returned salt + * @return string The generated salt + */ + public static function salt($length = 22) { + return substr(str_replace('+', '.', base64_encode(sha1(uniqid(Configure::read('Security.salt'), true), true))), 0, $length); + } + +/** + * One way encryption using php's crypt() function. + * + * @param string $password The string to be encrypted. + * @param string $type The encryption method to use (blowfish) + * @param mixed $salt false to generate a new salt or an existing salt. + */ + protected static function _crypt($password, $type = null, $salt = false) { + $options = array( + 'saltFormat' => array( + 'blowfish' => '$2a$%s$%s', + ), + 'saltLength' => array( + 'blowfish' => 22, + ), + 'costLimits' => array( + 'blowfish' => array(4, 31), + ) + ); + extract($options); + if ($type === null) { + $hashType = self::$hashType; + } else { + $hashType = $type; + } + $cost = self::$hashCost; + if ($salt === false) { + if (isset($costLimits[$hashType]) && ($cost < $costLimits[$hashType][0] || $cost > $costLimits[$hashType][1])) { + trigger_error(__d( + 'cake_dev', + 'When using %s you must specify a cost between %s and %s', + array( + $hashType, + $costLimits[$hashType][0], + $costLimits[$hashType][1] + ) + ), E_USER_WARNING); + return ''; + } + $vspArgs = array(); + $salt = self::salt($saltLength[$hashType]); + if ($hashType === 'blowfish') { + $bfCost = chr(ord('0') + $cost / 10); + $bfCost .= chr(ord('0') + $cost % 10); + $vspArgs[] = $bfCost; + } + $vspArgs[] = $salt; + $salt = vsprintf($saltFormat[$hashType], $vspArgs); + } elseif ($salt === true || strpos($salt, '$2a$') !== 0 || strlen($salt) < 29) { + trigger_error(__d( + 'cake_dev', + 'Invalid salt: %s for %s Please visit http://www.php.net/crypt and read the appropriate section for building %s salts.', + array($salt, $hashType, $hashType) + ), E_USER_WARNING); + return ''; + } + return crypt($password, $salt); + } + } From 2359fb7e2efec50b113870298fd4847a4b1528ef Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 22 Jul 2012 21:28:49 -0400 Subject: [PATCH 037/256] Simplify number formatting. --- lib/Cake/Test/Case/Utility/SecurityTest.php | 5 ----- lib/Cake/Utility/Security.php | 13 +++++-------- 2 files changed, 5 insertions(+), 13 deletions(-) diff --git a/lib/Cake/Test/Case/Utility/SecurityTest.php b/lib/Cake/Test/Case/Utility/SecurityTest.php index e7ddced30..153d1ad57 100644 --- a/lib/Cake/Test/Case/Utility/SecurityTest.php +++ b/lib/Cake/Test/Case/Utility/SecurityTest.php @@ -1,9 +1,5 @@ * Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) * @@ -12,7 +8,6 @@ * * @copyright Copyright 2005-2012, Cake Software Foundation, Inc. (http://cakefoundation.org) * @link http://book.cakephp.org/2.0/en/development/testing.html CakePHP(tm) Tests - * @package Cake.Test.Case.Utility * @since CakePHP(tm) v 1.2.0.5432 * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ diff --git a/lib/Cake/Utility/Security.php b/lib/Cake/Utility/Security.php index c9f41008d..7f84c9687 100644 --- a/lib/Cake/Utility/Security.php +++ b/lib/Cake/Utility/Security.php @@ -235,7 +235,7 @@ class Security { protected static function _crypt($password, $type = null, $salt = false) { $options = array( 'saltFormat' => array( - 'blowfish' => '$2a$%s$%s', + 'blowfish' => '$2a$%02d$%s', ), 'saltLength' => array( 'blowfish' => 22, @@ -264,14 +264,11 @@ class Security { ), E_USER_WARNING); return ''; } - $vspArgs = array(); $salt = self::salt($saltLength[$hashType]); - if ($hashType === 'blowfish') { - $bfCost = chr(ord('0') + $cost / 10); - $bfCost .= chr(ord('0') + $cost % 10); - $vspArgs[] = $bfCost; - } - $vspArgs[] = $salt; + $vspArgs = array( + $cost, + $salt, + ); $salt = vsprintf($saltFormat[$hashType], $vspArgs); } elseif ($salt === true || strpos($salt, '$2a$') !== 0 || strlen($salt) < 29) { trigger_error(__d( From d7f93f5bcf0b8aeb0ad286fd2302ec2d123b0272 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Gonz=C3=A1lez?= Date: Tue, 24 Jul 2012 14:08:54 +0100 Subject: [PATCH 038/256] adding a related message to the enableCrypto InvalidArgumentException --- lib/Cake/Network/CakeSocket.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Network/CakeSocket.php b/lib/Cake/Network/CakeSocket.php index d1d597ff6..9ced3c7ce 100644 --- a/lib/Cake/Network/CakeSocket.php +++ b/lib/Cake/Network/CakeSocket.php @@ -89,7 +89,7 @@ class CakeSocket { protected $_encryptMethods = array( 'sslv2_client' => STREAM_CRYPTO_METHOD_SSLv2_CLIENT, 'sslv3_client' => STREAM_CRYPTO_METHOD_SSLv3_CLIENT, - 'sslv23_client' =>STREAM_CRYPTO_METHOD_SSLv23_CLIENT, + 'sslv23_client' => STREAM_CRYPTO_METHOD_SSLv23_CLIENT, 'tls_client' => STREAM_CRYPTO_METHOD_TLS_CLIENT, 'sslv2_server' => STREAM_CRYPTO_METHOD_SSLv2_SERVER, 'sslv3_server' => STREAM_CRYPTO_METHOD_SSLv3_SERVER, @@ -310,7 +310,7 @@ class CakeSocket { */ public function enableCrypto($type, $clientOrServer = 'client', $enable = true) { if (!array_key_exists($type . '_' . $clientOrServer, $this->_encryptMethods)) { - throw new InvalidArgumentException(); + throw new InvalidArgumentException(__('Invalid encryption scheme chosen')); } $enableCryptoResult = false; try { From f9f380d4013bf50eddeb501de026e38d1a3db1dd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Gonz=C3=A1lez?= Date: Tue, 24 Jul 2012 14:09:48 +0100 Subject: [PATCH 039/256] using annotations for catching exceptions in tests --- lib/Cake/Test/Case/Network/CakeSocketTest.php | 10 +++++----- lib/Cake/Test/Case/Network/Email/SmtpTransportTest.php | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/Cake/Test/Case/Network/CakeSocketTest.php b/lib/Cake/Test/Case/Network/CakeSocketTest.php index 9baf63df3..b214ca9b5 100644 --- a/lib/Cake/Test/Case/Network/CakeSocketTest.php +++ b/lib/Cake/Test/Case/Network/CakeSocketTest.php @@ -218,6 +218,7 @@ class CakeSocketTest extends CakeTestCase { /** * testEncrypt * + * @expectedException SocketException * @return void */ public function testEnableCryptoSocketExceptionNoSsl() { @@ -226,13 +227,13 @@ class CakeSocketTest extends CakeTestCase { // testing exception on no ssl socket server for ssl and tls methods $this->Socket = new CakeSocket($configNoSslOrTls); $this->Socket->connect(); - $this->setExpectedException('SocketException'); $this->Socket->enableCrypto('sslv3', 'client'); } /** * testEnableCryptoSocketExceptionNoTls * + * @expectedException SocketException * @return void */ public function testEnableCryptoSocketExceptionNoTls() { @@ -241,7 +242,6 @@ class CakeSocketTest extends CakeTestCase { // testing exception on no ssl socket server for ssl and tls methods $this->Socket = new CakeSocket($configNoSslOrTls); $this->Socket->connect(); - $this->setExpectedException('SocketException'); $this->Socket->enableCrypto('tls', 'client'); } @@ -259,12 +259,12 @@ class CakeSocketTest extends CakeTestCase { /** * testEnableCryptoBadMode * + * @expectedException InvalidArgumentException * @return void */ public function testEnableCryptoBadMode() { // testing wrong encryption mode $this->_connectSocketToSslTls(); - $this->setExpectedException('InvalidArgumentException'); $this->Socket->enableCrypto('doesntExistMode', 'server'); $this->Socket->disconnect(); } @@ -289,25 +289,25 @@ class CakeSocketTest extends CakeTestCase { /** * testEnableCryptoExceptionEnableTwice * + * @expectedException SocketException * @return void */ public function testEnableCryptoExceptionEnableTwice() { // testing on tls server $this->_connectSocketToSslTls(); $this->Socket->enableCrypto('tls', 'client'); - $this->setExpectedException('SocketException'); $this->Socket->enableCrypto('tls', 'client'); } /** * testEnableCryptoExceptionDisableTwice * + * @expectedException SocketException * @return void */ public function testEnableCryptoExceptionDisableTwice() { // testing on tls server $this->_connectSocketToSslTls(); - $this->setExpectedException('SocketException'); $this->Socket->enableCrypto('tls', 'client', false); } diff --git a/lib/Cake/Test/Case/Network/Email/SmtpTransportTest.php b/lib/Cake/Test/Case/Network/Email/SmtpTransportTest.php index f5fa2f95d..55dc7bb0a 100644 --- a/lib/Cake/Test/Case/Network/Email/SmtpTransportTest.php +++ b/lib/Cake/Test/Case/Network/Email/SmtpTransportTest.php @@ -131,6 +131,7 @@ class SmtpTransportTest extends CakeTestCase { /** * testConnectEhloTlsOnNonTlsServer method * + * @expectedException SocketException * @return void */ public function testConnectEhloTlsOnNonTlsServer() { @@ -144,13 +145,13 @@ class SmtpTransportTest extends CakeTestCase { $this->socket->expects($this->at(5))->method('write')->with("STARTTLS\r\n"); $this->socket->expects($this->at(6))->method('read')->will($this->returnValue(false)); $this->socket->expects($this->at(7))->method('read')->will($this->returnValue("500 5.3.3 Unrecognized command\r\n")); - $this->setExpectedException('SocketException'); $this->SmtpTransport->connect(); } /** * testConnectEhloNoTlsOnRequiredTlsServer method * + * @expectedException SocketException * @return void */ public function testConnectEhloNoTlsOnRequiredTlsServer() { @@ -164,7 +165,6 @@ class SmtpTransportTest extends CakeTestCase { $this->socket->expects($this->at(5))->method('read')->with("AUTH LOGIN\r\n"); $this->socket->expects($this->at(6))->method('read')->will($this->returnValue(false)); $this->socket->expects($this->at(7))->method('read')->will($this->returnValue("504 5.7.4 Unrecognized authentication type\r\n")); - $this->setExpectedException('SocketException'); $this->SmtpTransport->connect(); $this->SmtpTransport->auth(); } From 2a553dcfd1dc2ace3b12093eb46168cac01b9368 Mon Sep 17 00:00:00 2001 From: euromark Date: Tue, 24 Jul 2012 18:06:39 +0200 Subject: [PATCH 040/256] unified doctype for browser related layout templates --- lib/Cake/Console/Templates/skel/View/Layouts/default.ctp | 2 +- lib/Cake/Console/Templates/skel/View/Layouts/error.ctp | 2 +- lib/Cake/Console/Templates/skel/View/Layouts/flash.ctp | 2 +- lib/Cake/Test/test_app/View/Layouts/cache_empty_sections.ctp | 2 +- lib/Cake/Test/test_app/View/Layouts/default.ctp | 2 +- lib/Cake/Test/test_app/View/Layouts/flash.ctp | 2 +- lib/Cake/TestSuite/templates/header.php | 2 +- 7 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/Cake/Console/Templates/skel/View/Layouts/default.ctp b/lib/Cake/Console/Templates/skel/View/Layouts/default.ctp index 4aab010a9..0bcf45401 100644 --- a/lib/Cake/Console/Templates/skel/View/Layouts/default.ctp +++ b/lib/Cake/Console/Templates/skel/View/Layouts/default.ctp @@ -16,7 +16,7 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ ?> - + Html->charset(); ?> diff --git a/lib/Cake/Console/Templates/skel/View/Layouts/error.ctp b/lib/Cake/Console/Templates/skel/View/Layouts/error.ctp index c7d67871f..bfbefe4a3 100644 --- a/lib/Cake/Console/Templates/skel/View/Layouts/error.ctp +++ b/lib/Cake/Console/Templates/skel/View/Layouts/error.ctp @@ -16,7 +16,7 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ ?> - + Html->charset(); ?> diff --git a/lib/Cake/Console/Templates/skel/View/Layouts/flash.ctp b/lib/Cake/Console/Templates/skel/View/Layouts/flash.ctp index 35f5a942f..b96f52b26 100644 --- a/lib/Cake/Console/Templates/skel/View/Layouts/flash.ctp +++ b/lib/Cake/Console/Templates/skel/View/Layouts/flash.ctp @@ -16,7 +16,7 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ ?> - + Html->charset(); ?> diff --git a/lib/Cake/Test/test_app/View/Layouts/cache_empty_sections.ctp b/lib/Cake/Test/test_app/View/Layouts/cache_empty_sections.ctp index dae25af94..1cb60aedc 100644 --- a/lib/Cake/Test/test_app/View/Layouts/cache_empty_sections.ctp +++ b/lib/Cake/Test/test_app/View/Layouts/cache_empty_sections.ctp @@ -1,4 +1,4 @@ - + <?php echo $title_for_layout; ?> diff --git a/lib/Cake/Test/test_app/View/Layouts/default.ctp b/lib/Cake/Test/test_app/View/Layouts/default.ctp index 21b25e111..626128141 100644 --- a/lib/Cake/Test/test_app/View/Layouts/default.ctp +++ b/lib/Cake/Test/test_app/View/Layouts/default.ctp @@ -19,7 +19,7 @@ $this->loadHelper('Html'); $cakeDescription = __d('cake_dev', 'CakePHP: the rapid development php framework'); ?> - + Html->charset(); ?> diff --git a/lib/Cake/Test/test_app/View/Layouts/flash.ctp b/lib/Cake/Test/test_app/View/Layouts/flash.ctp index 2a0c34fc2..755c07863 100644 --- a/lib/Cake/Test/test_app/View/Layouts/flash.ctp +++ b/lib/Cake/Test/test_app/View/Layouts/flash.ctp @@ -16,7 +16,7 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ ?> - + <?php echo $page_title?> diff --git a/lib/Cake/TestSuite/templates/header.php b/lib/Cake/TestSuite/templates/header.php index dfaa2d178..4d0dc81e6 100644 --- a/lib/Cake/TestSuite/templates/header.php +++ b/lib/Cake/TestSuite/templates/header.php @@ -17,7 +17,7 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ ?> - + From 7418be04d3fd24bd7cef09527bd40e55783c28c6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jorge=20Gonz=C3=A1lez?= Date: Wed, 25 Jul 2012 19:20:30 +0100 Subject: [PATCH 041/256] fixing translation domain to cake_dev --- lib/Cake/Network/CakeSocket.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Network/CakeSocket.php b/lib/Cake/Network/CakeSocket.php index 9ced3c7ce..d2d72e76a 100644 --- a/lib/Cake/Network/CakeSocket.php +++ b/lib/Cake/Network/CakeSocket.php @@ -310,7 +310,7 @@ class CakeSocket { */ public function enableCrypto($type, $clientOrServer = 'client', $enable = true) { if (!array_key_exists($type . '_' . $clientOrServer, $this->_encryptMethods)) { - throw new InvalidArgumentException(__('Invalid encryption scheme chosen')); + throw new InvalidArgumentException(__d('cake_dev', 'Invalid encryption scheme chosen')); } $enableCryptoResult = false; try { @@ -323,7 +323,7 @@ class CakeSocket { $this->encrypted = $enable; return true; } else { - $errorMessage = __('Unable to perform enableCrypto operation on CakeSocket'); + $errorMessage = __d('cake_dev', 'Unable to perform enableCrypto operation on CakeSocket'); $this->setLastError(null, $errorMessage); throw new SocketException($errorMessage); } From 6e0cf0dab7a41c1dfcc29471f73b8eb376e1456c Mon Sep 17 00:00:00 2001 From: mark_story Date: Thu, 26 Jul 2012 21:19:20 -0400 Subject: [PATCH 042/256] Fix failing test. --- lib/Cake/Test/Case/Console/Command/CommandListShellTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Test/Case/Console/Command/CommandListShellTest.php b/lib/Cake/Test/Case/Console/Command/CommandListShellTest.php index 22eed1920..554917c68 100644 --- a/lib/Cake/Test/Case/Console/Command/CommandListShellTest.php +++ b/lib/Cake/Test/Case/Console/Command/CommandListShellTest.php @@ -88,7 +88,7 @@ class CommandListShellTest extends CakeTestCase { $expected = "/\[.*TestPluginTwo.*\] example, welcome/"; $this->assertRegExp($expected, $output); - $expected = "/\[.*CORE.*\] acl, api, bake, command_list, console, i18n, schema, test, testsuite, upgrade/"; + $expected = "/\[.*CORE.*\] acl, api, bake, command_list, console, i18n, schema, server, test, testsuite, upgrade/"; $this->assertRegExp($expected, $output); $expected = "/\[.*app.*\] sample/"; From f963e378b599ca0dc03aeee8811a4d0b011dbc50 Mon Sep 17 00:00:00 2001 From: mark_story Date: Thu, 26 Jul 2012 21:22:50 -0400 Subject: [PATCH 043/256] Fix coding standards errors. --- app/Config/Schema/i18n.php | 14 +++++--------- app/webroot/index.php | 2 +- lib/Cake/Console/Templates/skel/webroot/index.php | 2 +- lib/Cake/Test/Case/Utility/ValidationTest.php | 2 +- 4 files changed, 8 insertions(+), 12 deletions(-) diff --git a/app/Config/Schema/i18n.php b/app/Config/Schema/i18n.php index 8de0052dd..5f62427ce 100644 --- a/app/Config/Schema/i18n.php +++ b/app/Config/Schema/i18n.php @@ -1,11 +1,5 @@ assertTrue(Validation::url('http://underscore_subdomain.example.org')); $this->assertTrue(Validation::url('http://_jabber._tcp.gmail.com')); $this->assertFalse(Validation::url('http://www.underscore_domain.org')); - $this->assertFalse(Validation::url('http://_jabber._tcp.g_mail.com')); + $this->assertFalse(Validation::url('http://_jabber._tcp.g_mail.com')); $this->assertTrue(Validation::url('http://example.com/~userdir/subdir/index.html')); $this->assertTrue(Validation::url('http://www.zwischenraume.de')); From b73be3139f3394d73f7a2c459b3f6c061b30ef6b Mon Sep 17 00:00:00 2001 From: euromark Date: Wed, 1 Aug 2012 12:02:50 +0200 Subject: [PATCH 044/256] allowing tel protocol for mobile devices --- lib/Cake/Routing/Router.php | 3 ++- lib/Cake/Test/Case/Routing/RouterTest.php | 3 +++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Routing/Router.php b/lib/Cake/Routing/Router.php index cb28f6e9c..b33f14c6a 100644 --- a/lib/Cake/Routing/Router.php +++ b/lib/Cake/Routing/Router.php @@ -832,7 +832,8 @@ class Router { if ( (strpos($url, '://') !== false || (strpos($url, 'javascript:') === 0) || - (strpos($url, 'mailto:') === 0)) || + (strpos($url, 'mailto:') === 0) || + (strpos($url, 'tel:') === 0)) || (!strncmp($url, '#', 1)) ) { return $url; diff --git a/lib/Cake/Test/Case/Routing/RouterTest.php b/lib/Cake/Test/Case/Routing/RouterTest.php index 44bf6aacd..7e7fffca8 100644 --- a/lib/Cake/Test/Case/Routing/RouterTest.php +++ b/lib/Cake/Test/Case/Routing/RouterTest.php @@ -2484,6 +2484,9 @@ class RouterTest extends CakeTestCase { $url = '://example.com'; $this->assertEquals($url, Router::url($url)); + + $url = 'tel:012345-678'; + $this->assertEquals($url, Router::url($url)); } /** From f0ffe098d3b19da3a03a050cf95db619d398dfd0 Mon Sep 17 00:00:00 2001 From: euromark Date: Wed, 1 Aug 2012 12:11:05 +0200 Subject: [PATCH 045/256] adding html helper tests for special protocols --- lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php b/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php index 678a1df23..887b25b0c 100644 --- a/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php @@ -337,6 +337,14 @@ class HtmlHelperTest extends CakeTestCase { $result = $this->Html->link('http://www.example.org?param1=value1¶m2=value2'); $expected = array('a' => array('href' => 'http://www.example.org?param1=value1&param2=value2'), 'http://www.example.org?param1=value1&param2=value2', '/a'); $this->assertTags($result, $expected); + + $result = $this->Html->link('write me', 'mailto:example@cakephp.org'); + $expected = array('a' => array('href' => 'mailto:example@cakephp.org'), 'write me', '/a'); + $this->assertTags($result, $expected); + + $result = $this->Html->link('call me on 0123465-798', 'tel:0123465-798'); + $expected = array('a' => array('href' => 'tel:0123465-798'), 'call me on 0123465-798', '/a'); + $this->assertTags($result, $expected); } /** From 2a674fc461b0d2a80a9af6948129dcf41d2644e4 Mon Sep 17 00:00:00 2001 From: euromark Date: Wed, 1 Aug 2012 12:14:46 +0200 Subject: [PATCH 046/256] adding a test for the yet untested javascript protocol --- lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php b/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php index 887b25b0c..bbf5a65d5 100644 --- a/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php @@ -338,6 +338,10 @@ class HtmlHelperTest extends CakeTestCase { $expected = array('a' => array('href' => 'http://www.example.org?param1=value1&param2=value2'), 'http://www.example.org?param1=value1&param2=value2', '/a'); $this->assertTags($result, $expected); + $result = $this->Html->link('alert', 'javascript:alert(\'cakephp\');'); + $expected = array('a' => array('href' => 'javascript:alert('cakephp');'), 'alert', '/a'); + $this->assertTags($result, $expected); + $result = $this->Html->link('write me', 'mailto:example@cakephp.org'); $expected = array('a' => array('href' => 'mailto:example@cakephp.org'), 'write me', '/a'); $this->assertTags($result, $expected); From b6fe8af70194e93be61493f435b9d880e369d0c0 Mon Sep 17 00:00:00 2001 From: euromark Date: Wed, 1 Aug 2012 12:38:06 +0200 Subject: [PATCH 047/256] adding sms as protocol --- lib/Cake/Routing/Router.php | 3 ++- lib/Cake/Test/Case/Routing/RouterTest.php | 6 ++++++ lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php | 8 ++++++++ 3 files changed, 16 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Routing/Router.php b/lib/Cake/Routing/Router.php index b33f14c6a..19d0b95c6 100644 --- a/lib/Cake/Routing/Router.php +++ b/lib/Cake/Routing/Router.php @@ -833,7 +833,8 @@ class Router { (strpos($url, '://') !== false || (strpos($url, 'javascript:') === 0) || (strpos($url, 'mailto:') === 0) || - (strpos($url, 'tel:') === 0)) || + (strpos($url, 'tel:') === 0) || + (strpos($url, 'sms:') === 0)) || (!strncmp($url, '#', 1)) ) { return $url; diff --git a/lib/Cake/Test/Case/Routing/RouterTest.php b/lib/Cake/Test/Case/Routing/RouterTest.php index 7e7fffca8..512ab0565 100644 --- a/lib/Cake/Test/Case/Routing/RouterTest.php +++ b/lib/Cake/Test/Case/Routing/RouterTest.php @@ -2485,8 +2485,14 @@ class RouterTest extends CakeTestCase { $url = '://example.com'; $this->assertEquals($url, Router::url($url)); + $url = 'javascript:void(0)'; + $this->assertEquals($url, Router::url($url)); + $url = 'tel:012345-678'; $this->assertEquals($url, Router::url($url)); + + $url = 'sms:012345-678'; + $this->assertEquals($url, Router::url($url)); } /** diff --git a/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php b/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php index bbf5a65d5..0bb8e93bb 100644 --- a/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php @@ -349,6 +349,14 @@ class HtmlHelperTest extends CakeTestCase { $result = $this->Html->link('call me on 0123465-798', 'tel:0123465-798'); $expected = array('a' => array('href' => 'tel:0123465-798'), 'call me on 0123465-798', '/a'); $this->assertTags($result, $expected); + + $result = $this->Html->link('text me on 0123465-798', 'sms:0123465-798'); + $expected = array('a' => array('href' => 'sms:0123465-798'), 'text me on 0123465-798', '/a'); + $this->assertTags($result, $expected); + + $result = $this->Html->link('say hello to 0123465-798', 'sms:0123465-798?body=hello there'); + $expected = array('a' => array('href' => 'sms:0123465-798?body=hello there'), 'say hello to 0123465-798', '/a'); + $this->assertTags($result, $expected); } /** From 319658e9d37f8a5a2d891db058d9c5205f6474dc Mon Sep 17 00:00:00 2001 From: euromark Date: Wed, 1 Aug 2012 12:48:21 +0200 Subject: [PATCH 048/256] asserting escaped output for sms protocol --- lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php b/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php index 0bb8e93bb..4b54764a2 100644 --- a/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php @@ -357,6 +357,11 @@ class HtmlHelperTest extends CakeTestCase { $result = $this->Html->link('say hello to 0123465-798', 'sms:0123465-798?body=hello there'); $expected = array('a' => array('href' => 'sms:0123465-798?body=hello there'), 'say hello to 0123465-798', '/a'); $this->assertTags($result, $expected); + + $result = $this->Html->link('say hello to 0123465-798', 'sms:0123465-798?body=hello "cakephp"'); + debug($result); + $expected = array('a' => array('href' => 'sms:0123465-798?body=hello "cakephp"'), 'say hello to 0123465-798', '/a'); + $this->assertTags($result, $expected); } /** From 57bf15a415adc6d498bc0f9faac33b1ebf1a4672 Mon Sep 17 00:00:00 2001 From: euromark Date: Wed, 1 Aug 2012 20:42:27 +0200 Subject: [PATCH 049/256] multiple strpos to preg_match --- lib/Cake/Routing/Router.php | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/lib/Cake/Routing/Router.php b/lib/Cake/Routing/Router.php index 19d0b95c6..880057e05 100644 --- a/lib/Cake/Routing/Router.php +++ b/lib/Cake/Routing/Router.php @@ -829,14 +829,7 @@ class Router { $output = self::_handleNoRoute($url); } } else { - if ( - (strpos($url, '://') !== false || - (strpos($url, 'javascript:') === 0) || - (strpos($url, 'mailto:') === 0) || - (strpos($url, 'tel:') === 0) || - (strpos($url, 'sms:') === 0)) || - (!strncmp($url, '#', 1)) - ) { + if (preg_match('/:\/\/|^(javascript|mailto|tel|sms):|\#/i', $url)) { return $url; } if (substr($url, 0, 1) === '/') { From 64ba8c6b6e4241994ec36bb476a967a579238789 Mon Sep 17 00:00:00 2001 From: euromark Date: Thu, 2 Aug 2012 10:18:14 +0200 Subject: [PATCH 050/256] remove debug statement --- lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php b/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php index 4b54764a2..fd4cb0a77 100644 --- a/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php @@ -359,7 +359,6 @@ class HtmlHelperTest extends CakeTestCase { $this->assertTags($result, $expected); $result = $this->Html->link('say hello to 0123465-798', 'sms:0123465-798?body=hello "cakephp"'); - debug($result); $expected = array('a' => array('href' => 'sms:0123465-798?body=hello "cakephp"'), 'say hello to 0123465-798', '/a'); $this->assertTags($result, $expected); } From 917d912a43d1b7d22b6b86a60d8904cbc70490a7 Mon Sep 17 00:00:00 2001 From: euromark Date: Thu, 2 Aug 2012 13:21:31 +0200 Subject: [PATCH 051/256] String::tail() --- lib/Cake/Test/Case/Utility/StringTest.php | 40 +++++++++++++++++++++++ lib/Cake/Utility/String.php | 40 +++++++++++++++++++++++ 2 files changed, 80 insertions(+) diff --git a/lib/Cake/Test/Case/Utility/StringTest.php b/lib/Cake/Test/Case/Utility/StringTest.php index efa024b5b..9b6fe1e2b 100644 --- a/lib/Cake/Test/Case/Utility/StringTest.php +++ b/lib/Cake/Test/Case/Utility/StringTest.php @@ -443,6 +443,46 @@ podeís adquirirla.

    $this->assertEquals($expected, $result); } +/** + * testTail method + * + * @return void + */ + public function testTail() { + $text1 = 'The quick brown fox jumps over the lazy dog'; + $text2 = 'Heizölrückstoßabdämpfung'; + $text3 = 'El moño está en el lugar correcto. Eso fue lo que dijo la niña, ¿habrá dicho la verdad?'; + $text4 = 'Vive la R' . chr(195) . chr(169) . 'publique de France'; + $text5 = 'НОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдежзийклмнопрстуфхцчшщъыь'; + + $result = $this->Text->tail($text1, 13); + $this->assertEquals('...e lazy dog', $result); + + $result = $this->Text->tail($text1, 13, array('exact' => false)); + $this->assertEquals('...lazy dog', $result); + + $result = $this->Text->tail($text1, 100); + $this->assertEquals('The quick brown fox jumps over the lazy dog', $result); + + $result = $this->Text->tail($text2, 10); + $this->assertEquals('...;mpfung', $result); + + $result = $this->Text->tail($text2, 10, array('exact' => false)); + $this->assertEquals('...', $result); + + $result = $this->Text->tail($text3, 255); + $this->assertEquals($text3, $result); + + $result = $this->Text->tail($text3, 21); + $this->assertEquals('...á dicho la verdad?', $result); + + $result = $this->Text->tail($text4, 25); + $this->assertEquals('...a R' . chr(195) . chr(169) . 'publique de France', $result); + + $result = $this->Text->tail($text5, 10); + $this->assertEquals('...цчшщъыь', $result); + } + /** * testHighlight method * diff --git a/lib/Cake/Utility/String.php b/lib/Cake/Utility/String.php index 01f9acbbb..4330ea258 100644 --- a/lib/Cake/Utility/String.php +++ b/lib/Cake/Utility/String.php @@ -418,6 +418,46 @@ class String { return preg_replace('|]+>|im', '', preg_replace('|<\/a>|im', '', $text)); } +/** + * Truncates text starting from the end. + * + * Cuts a string to the length of $length and replaces the first characters + * with the beginning if the text is longer than length. + * + * ### Options: + * + * - `beginning` Will be used as Beginning and prepended to the trimmed string + * - `exact` If false, $text will not be cut mid-word + * + * @param string $text String to truncate. + * @param integer $length Length of returned string, including ellipsis. + * @param array $options An array of html attributes and options. + * @return string Trimmed string. + */ + public static function tail($text, $length = 100, $options = array()) { + $default = array( + 'beginning' => '...', 'exact' => true + ); + $options = array_merge($default, $options); + extract($options); + + if (!function_exists('mb_strlen')) { + class_exists('Multibyte'); + } + + if (mb_strlen($text) <= $length) { + return $text; + } else { + $truncate = mb_substr($text, mb_strlen($text) - $length + mb_strlen($beginning)); + } + if (!$exact) { + $spacepos = mb_strpos($truncate, ' '); + $truncate = $spacepos === false ? '' : trim(mb_substr($truncate, $spacepos)); + } + + return $beginning . $truncate; + } + /** * Truncates text. * From df8ec176267ce06ff6ac04e646f3f6be052c8df9 Mon Sep 17 00:00:00 2001 From: Tigran Gabrielyan Date: Wed, 1 Aug 2012 21:28:24 -0700 Subject: [PATCH 052/256] Added `disabledActions` feature to SecurityComponent --- .../Controller/Component/SecurityComponent.php | 15 ++++++++++----- .../Component/SecurityComponentTest.php | 14 ++++++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/lib/Cake/Controller/Component/SecurityComponent.php b/lib/Cake/Controller/Component/SecurityComponent.php index 907b43a8f..bc5212900 100644 --- a/lib/Cake/Controller/Component/SecurityComponent.php +++ b/lib/Cake/Controller/Component/SecurityComponent.php @@ -178,6 +178,13 @@ class SecurityComponent extends Component { */ public $csrfLimit = 100; +/** + * List of actions to disable security checks + * + * @var array +*/ + public $disabledActions = array(); + /** * Other components used by the Security component * @@ -218,13 +225,11 @@ class SecurityComponent extends Component { $controller->request->params['requested'] != 1 ); - if ($isPost && $isNotRequestAction && $this->validatePost) { - if ($this->_validatePost($controller) === false) { + if (!in_array($this->_action, (array)$this->disabledActions) && $isPost && $isNotRequestAction) { + if ($this->validatePost && $this->_validatePost($controller) === false) { return $this->blackHole($controller, 'auth'); } - } - if ($isPost && $isNotRequestAction && $this->csrfCheck) { - if ($this->_validateCsrf($controller) === false) { + if ($this->csrfCheck && $this->_validateCsrf($controller) === false) { return $this->blackHole($controller, 'csrf'); } } diff --git a/lib/Cake/Test/Case/Controller/Component/SecurityComponentTest.php b/lib/Cake/Test/Case/Controller/Component/SecurityComponentTest.php index 84f78036b..c7c01e525 100644 --- a/lib/Cake/Test/Case/Controller/Component/SecurityComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/SecurityComponentTest.php @@ -1372,4 +1372,18 @@ class SecurityComponentTest extends CakeTestCase { $this->assertTrue(isset($result['4'])); $this->assertTrue(isset($result['5'])); } + +/** + * Test disabled actions + * + * @return void + */ + public function testDisabledActions() { + $_SERVER['REQUEST_METHOD'] = 'POST'; + $this->Controller->request->data = array('data'); + $this->Controller->Security->disabledActions = 'index'; + $this->Controller->Security->blackHoleCallback = null; + $result = $this->Controller->Security->startup($this->Controller); + $this->assertNull($result); + } } From a208eb6cb1e5489c722639fac0460e09d335191b Mon Sep 17 00:00:00 2001 From: euromark Date: Mon, 23 Jul 2012 16:39:46 +0200 Subject: [PATCH 053/256] fixes disabled attribute for multiple checkboxes --- .../Test/Case/View/Helper/FormHelperTest.php | 72 +++++++++++++++++++ lib/Cake/View/Helper/FormHelper.php | 16 ++++- 2 files changed, 86 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php index 69f709910..80253c28d 100644 --- a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php @@ -2339,6 +2339,78 @@ class FormHelperTest extends CakeTestCase { } } +/** + * Test generating checkboxes with disabled elements. + * + * @return void + */ + public function testInputCheckboxWithDisabledElements() { + $options = array(1 => 'One', 2 => 'Two', '3' => 'Three'); + $result = $this->Form->input('Contact.multiple', array('multiple' => 'checkbox', 'disabled' => 'disabled', 'options' => $options)); + + $expected = array( + array('div' => array('class' => 'input select')), + array('label' => array('for' => "ContactMultiple")), + 'Multiple', + '/label', + array('input' => array('type' => 'hidden', 'name' => "data[Contact][multiple]", 'value' => '', 'id' => "ContactMultiple")), + array('div' => array('class' => 'checkbox')), + array('input' => array('type' => 'checkbox', 'name' => "data[Contact][multiple][]", 'value' => 1, 'disabled' => 'disabled', 'id' => "ContactMultiple1")), + array('label' => array('for' => "ContactMultiple1")), + 'One', + '/label', + '/div', + array('div' => array('class' => 'checkbox')), + array('input' => array('type' => 'checkbox', 'name' => "data[Contact][multiple][]", 'value' => 2, 'disabled' => 'disabled', 'id' => "ContactMultiple2")), + array('label' => array('for' => "ContactMultiple2")), + 'Two', + '/label', + '/div', + array('div' => array('class' => 'checkbox')), + array('input' => array('type' => 'checkbox', 'name' => "data[Contact][multiple][]", 'value' => 3, 'disabled' => 'disabled', 'id' => "ContactMultiple3")), + array('label' => array('for' => "ContactMultiple3")), + 'Three', + '/label', + '/div', + '/div' + ); + $this->assertTags($result, $expected); + + $result = $this->Form->input('Contact.multiple', array('multiple' => 'checkbox', 'disabled' => true, 'options' => $options)); + $this->assertTags($result, $expected); + + $disabled = array('2', 3); + + $expected = array( + array('div' => array('class' => 'input select')), + array('label' => array('for' => "ContactMultiple")), + 'Multiple', + '/label', + array('input' => array('type' => 'hidden', 'name' => "data[Contact][multiple]", 'value' => '', 'id' => "ContactMultiple")), + array('div' => array('class' => 'checkbox')), + array('input' => array('type' => 'checkbox', 'name' => "data[Contact][multiple][]", 'value' => 1, 'id' => "ContactMultiple1")), + array('label' => array('for' => "ContactMultiple1")), + 'One', + '/label', + '/div', + array('div' => array('class' => 'checkbox')), + array('input' => array('type' => 'checkbox', 'name' => "data[Contact][multiple][]", 'value' => 2, 'disabled' => 'disabled', 'id' => "ContactMultiple2")), + array('label' => array('for' => "ContactMultiple2")), + 'Two', + '/label', + '/div', + array('div' => array('class' => 'checkbox')), + array('input' => array('type' => 'checkbox', 'name' => "data[Contact][multiple][]", 'value' => 3, 'disabled' => 'disabled', 'id' => "ContactMultiple3")), + array('label' => array('for' => "ContactMultiple3")), + 'Three', + '/label', + '/div', + '/div' + ); + $result = $this->Form->input('Contact.multiple', array('multiple' => 'checkbox', 'disabled' => $disabled, 'options' => $options)); + $this->assertTags($result, $expected); + } + /** * test input name with leading integer, ensure attributes are generated correctly. * diff --git a/lib/Cake/View/Helper/FormHelper.php b/lib/Cake/View/Helper/FormHelper.php index c9e193017..f23fa63b7 100644 --- a/lib/Cake/View/Helper/FormHelper.php +++ b/lib/Cake/View/Helper/FormHelper.php @@ -1801,7 +1801,8 @@ class FormHelper extends AppHelper { 'secure' => true, 'empty' => '', 'showParents' => false, - 'hiddenField' => true + 'hiddenField' => true, + 'disabled' => false ); $escapeOptions = $this->_extractOption('escape', $attributes); @@ -1874,7 +1875,8 @@ class FormHelper extends AppHelper { 'name' => $attributes['name'], 'value' => $attributes['value'], 'class' => $attributes['class'], - 'id' => $attributes['id'] + 'id' => $attributes['id'], + 'disabled' => $attributes['disabled'], ) )); @@ -2427,6 +2429,16 @@ class FormHelper extends AppHelper { if ($attributes['style'] === 'checkbox') { $htmlOptions['value'] = $name; + + if (!empty($attributes['disabled'])) { + if (is_array($attributes['disabled'])) { + if (in_array($htmlOptions['value'], $attributes['disabled'])) { + $htmlOptions['disabled'] = 'disabled'; + } + } else { + $htmlOptions['disabled'] = $attributes['disabled'] === true ? 'disabled' : $attributes['disabled']; + } + } $tagName = $attributes['id'] . Inflector::camelize(Inflector::slug($name)); $htmlOptions['id'] = $tagName; From e38c149880ea7887e6b862a73827a1d8d43c425e Mon Sep 17 00:00:00 2001 From: mark_story Date: Thu, 2 Aug 2012 21:25:27 -0400 Subject: [PATCH 054/256] Decompose complex nested conditionals. Refs #808 --- lib/Cake/View/Helper/FormHelper.php | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) diff --git a/lib/Cake/View/Helper/FormHelper.php b/lib/Cake/View/Helper/FormHelper.php index f23fa63b7..62458ebda 100644 --- a/lib/Cake/View/Helper/FormHelper.php +++ b/lib/Cake/View/Helper/FormHelper.php @@ -2429,15 +2429,21 @@ class FormHelper extends AppHelper { if ($attributes['style'] === 'checkbox') { $htmlOptions['value'] = $name; - - if (!empty($attributes['disabled'])) { - if (is_array($attributes['disabled'])) { - if (in_array($htmlOptions['value'], $attributes['disabled'])) { - $htmlOptions['disabled'] = 'disabled'; - } - } else { - $htmlOptions['disabled'] = $attributes['disabled'] === true ? 'disabled' : $attributes['disabled']; - } + + $disabledType = null; + $hasDisabled = !empty($attributes['disabled']); + if ($hasDisabled) { + $disabledType = gettype($attributes['disabled']); + } + if ( + $hasDisabled && + $disabledType === 'array' && + in_array($htmlOptions['value'], $attributes['disabled']) + ) { + $htmlOptions['disabled'] = 'disabled'; + } + if ($hasDisabled && $disabledType !== 'array') { + $htmlOptions['disabled'] = $attributes['disabled'] === true ? 'disabled' : $attributes['disabled']; } $tagName = $attributes['id'] . Inflector::camelize(Inflector::slug($name)); From e620433680a5133b4f78fe0df0c37f1728da6ade Mon Sep 17 00:00:00 2001 From: mark_story Date: Thu, 2 Aug 2012 21:34:45 -0400 Subject: [PATCH 055/256] Update doc block. --- lib/Cake/View/Helper/FormHelper.php | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/lib/Cake/View/Helper/FormHelper.php b/lib/Cake/View/Helper/FormHelper.php index 62458ebda..ffeedf8c6 100644 --- a/lib/Cake/View/Helper/FormHelper.php +++ b/lib/Cake/View/Helper/FormHelper.php @@ -1749,6 +1749,9 @@ class FormHelper extends AppHelper { * - `escape` - If true contents of options will be HTML entity encoded. Defaults to true. * - `value` The selected value of the input. * - `class` - When using multiple = checkbox the classname to apply to the divs. Defaults to 'checkbox'. + * - `disabled` - Control the disabled attribute. When creating a select box, set to true to disable the + * select box. When creating checkboxes, `true` will disable all checkboxes. You can also set disabled + * to a list of values you want to disable when creating checkboxes. * * ### Using options * @@ -1762,11 +1765,11 @@ class FormHelper extends AppHelper { * While a nested options array will create optgroups with options inside them. * {{{ * $options = array( - * 1 => 'bill', - * 'fred' => array( - * 2 => 'fred', - * 3 => 'fred jr.' - * ) + * 1 => 'bill', + * 'fred' => array( + * 2 => 'fred', + * 3 => 'fred jr.' + * ) * ); * $this->Form->select('Model.field', $options); * }}} @@ -1779,8 +1782,8 @@ class FormHelper extends AppHelper { * * {{{ * $options = array( - * array('name' => 'United states', 'value' => 'USA'), - * array('name' => 'USA', 'value' => 'USA'), + * array('name' => 'United states', 'value' => 'USA'), + * array('name' => 'USA', 'value' => 'USA'), * ); * }}} * From 853fa7d95bd86a82e05151359a022b0084f66195 Mon Sep 17 00:00:00 2001 From: euromark Date: Fri, 3 Aug 2012 10:54:16 +0200 Subject: [PATCH 056/256] doc block correction --- lib/Cake/Utility/String.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Utility/String.php b/lib/Cake/Utility/String.php index 4330ea258..f339cd8a3 100644 --- a/lib/Cake/Utility/String.php +++ b/lib/Cake/Utility/String.php @@ -431,7 +431,7 @@ class String { * * @param string $text String to truncate. * @param integer $length Length of returned string, including ellipsis. - * @param array $options An array of html attributes and options. + * @param array $options An array of options. * @return string Trimmed string. */ public static function tail($text, $length = 100, $options = array()) { From 617d47042729d0c9b096ef66316ad6c11fe5a116 Mon Sep 17 00:00:00 2001 From: Tigran Gabrielyan Date: Fri, 3 Aug 2012 11:01:19 -0700 Subject: [PATCH 057/256] Renamed disabledActions to unlockedActions --- .../Controller/Component/SecurityComponent.php | 16 ++++++++-------- .../Component/SecurityComponentTest.php | 6 +++--- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/lib/Cake/Controller/Component/SecurityComponent.php b/lib/Cake/Controller/Component/SecurityComponent.php index bc5212900..f6d30bc26 100644 --- a/lib/Cake/Controller/Component/SecurityComponent.php +++ b/lib/Cake/Controller/Component/SecurityComponent.php @@ -129,6 +129,13 @@ class SecurityComponent extends Component { */ public $unlockedFields = array(); +/** + * Actions to exclude from any security checks + * + * @var array + */ + public $unlockedActions = array(); + /** * Whether to validate POST data. Set to false to disable for data coming from 3rd party * services, etc. @@ -178,13 +185,6 @@ class SecurityComponent extends Component { */ public $csrfLimit = 100; -/** - * List of actions to disable security checks - * - * @var array -*/ - public $disabledActions = array(); - /** * Other components used by the Security component * @@ -225,7 +225,7 @@ class SecurityComponent extends Component { $controller->request->params['requested'] != 1 ); - if (!in_array($this->_action, (array)$this->disabledActions) && $isPost && $isNotRequestAction) { + if (!in_array($this->_action, (array)$this->unlockedActions) && $isPost && $isNotRequestAction) { if ($this->validatePost && $this->_validatePost($controller) === false) { return $this->blackHole($controller, 'auth'); } diff --git a/lib/Cake/Test/Case/Controller/Component/SecurityComponentTest.php b/lib/Cake/Test/Case/Controller/Component/SecurityComponentTest.php index c7c01e525..fb92b8614 100644 --- a/lib/Cake/Test/Case/Controller/Component/SecurityComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/SecurityComponentTest.php @@ -1374,14 +1374,14 @@ class SecurityComponentTest extends CakeTestCase { } /** - * Test disabled actions + * Test unlocked actions * * @return void */ - public function testDisabledActions() { + public function testUnlockedActions() { $_SERVER['REQUEST_METHOD'] = 'POST'; $this->Controller->request->data = array('data'); - $this->Controller->Security->disabledActions = 'index'; + $this->Controller->Security->unlockedActions = 'index'; $this->Controller->Security->blackHoleCallback = null; $result = $this->Controller->Security->startup($this->Controller); $this->assertNull($result); From de1450763b9a9c270650ab235a4d2d82528f3409 Mon Sep 17 00:00:00 2001 From: Christopher Vrooman Date: Wed, 25 Jul 2012 01:24:28 -0300 Subject: [PATCH 058/256] Added a failing test to testSavePartialFields Added a failing test to the testSavePartialFields method where the title data for two locales creates only one empty content entry instead of two. --- .../Model/Behavior/TranslateBehaviorTest.php | 63 +++++++++++++++++++ 1 file changed, 63 insertions(+) diff --git a/lib/Cake/Test/Case/Model/Behavior/TranslateBehaviorTest.php b/lib/Cake/Test/Case/Model/Behavior/TranslateBehaviorTest.php index e5d31fd32..f2f9af169 100644 --- a/lib/Cake/Test/Case/Model/Behavior/TranslateBehaviorTest.php +++ b/lib/Cake/Test/Case/Model/Behavior/TranslateBehaviorTest.php @@ -552,6 +552,69 @@ class TranslateBehaviorTest extends CakeTestCase { ) + $data ); $this->assertEquals($expected, $result); + + $TestModel->locale = 'eng'; + $data = array( + 'slug' => 'fifth_translated', + 'title' => array('eng' => 'Title #5', 'spa' => 'Leyenda #5'), + ); + $TestModel->create($data); + $TestModel->save(); + $TestModel->unbindTranslation(); + $translations = array('title' => 'Title', 'content' => 'Content'); + $TestModel->bindTranslation($translations, false); + $result = $TestModel->read(null, $TestModel->id); + $expected = array( + 'TranslatedItem' => array( + 'id' => '5', + 'translated_article_id' => null, + 'slug' => 'fifth_translated', + 'locale' => 'eng', + 'title' => '', + 'content' => '' + ), + 0 => array( + 'TranslatedItem__i18n_Title' => 'Title #5', + 'TranslatedItem__i18n_Content' => '' + ), + 'Title' => array( + 0 => array( + 'id' => '21', + 'locale' => 'eng', + 'model' => 'TranslatedItem', + 'foreign_key' => '5', + 'field' => 'title', + 'content' => 'Title #5' + ), + 1 => array( + 'id' => '22', + 'locale' => 'spa', + 'model' => 'TranslatedItem', + 'foreign_key' => '5', + 'field' => 'title', + 'content' => 'Leyenda #5' + ) + ), + 'Content' => array( + 0 => array( + 'id' => '23', + 'locale' => 'eng', + 'model' => 'TranslatedItem', + 'foreign_key' => '5', + 'field' => 'content', + 'content' => '' + ), + 1 => array( + 'id' => '24', + 'locale' => 'spa', + 'model' => 'TranslatedItem', + 'foreign_key' => '5', + 'field' => 'content', + 'content' => '' + ) + ) + ); + $this->assertEquals($expected, $result); } /** From bbd0b9dd8b85c9ed97a32c416abef82a5844abbb Mon Sep 17 00:00:00 2001 From: Christopher Vrooman Date: Thu, 26 Jul 2012 23:30:17 -0300 Subject: [PATCH 059/256] Tweaked DocBlocks Set property and return to boolean for DocBlocks of the CallbackPostTestModel class. --- lib/Cake/Event/CakeEvent.php | 4 ++-- lib/Cake/Event/CakeEventListener.php | 6 +++--- lib/Cake/Event/CakeEventManager.php | 22 +++++++++++----------- lib/Cake/Test/Case/Model/models.php | 12 ++++++------ 4 files changed, 22 insertions(+), 22 deletions(-) diff --git a/lib/Cake/Event/CakeEvent.php b/lib/Cake/Event/CakeEvent.php index c70d4f816..a51b0e61d 100644 --- a/lib/Cake/Event/CakeEvent.php +++ b/lib/Cake/Event/CakeEvent.php @@ -17,9 +17,9 @@ */ /** - * Represent the transport class of events across the system, it receives a name, and subject and an optional + * Represents the transport class of events across the system, it receives a name, and subject and an optional * payload. The name can be any string that uniquely identifies the event across the application, while the subject - * represents the object that the event is applying to. + * represents the object that the event applies to. * * @package Cake.Event */ diff --git a/lib/Cake/Event/CakeEventListener.php b/lib/Cake/Event/CakeEventListener.php index c4915949d..d1dd7de81 100644 --- a/lib/Cake/Event/CakeEventListener.php +++ b/lib/Cake/Event/CakeEventListener.php @@ -18,15 +18,15 @@ /** * Objects implementing this interface should declare the `implementedEvents` function - * to hint the event manager what methods should be called when an event is triggered. + * to notify the event manager what methods should be called when an event is triggered. * * @package Cake.Event */ interface CakeEventListener { /** - * Returns a list of events this object is implementing, when the class is registered - * in an event manager, each individual method will be associated to the respective event. + * Returns a list of events this object is implementing. When the class is registered + * in an event manager, each individual method will be associated with the respective event. * * ## Example: * diff --git a/lib/Cake/Event/CakeEventManager.php b/lib/Cake/Event/CakeEventManager.php index aacd537c9..fde456a8c 100644 --- a/lib/Cake/Event/CakeEventManager.php +++ b/lib/Cake/Event/CakeEventManager.php @@ -19,9 +19,9 @@ App::uses('CakeEventListener', 'Event'); /** - * The event manager is responsible for keeping track of event listeners and pass the correct - * data to them, and fire them in the correct order, when associated events are triggered. You - * can create multiple instances of this objects to manage local events or keep a single instance + * The event manager is responsible for keeping track of event listeners, passing the correct + * data to them, and firing them in the correct order, when associated events are triggered. You + * can create multiple instances of this object to manage local events or keep a single instance * and pass it around to manage all events in your app. * * @package Cake.Event @@ -29,7 +29,7 @@ App::uses('CakeEventListener', 'Event'); class CakeEventManager { /** - * The default priority queue value for new attached listeners + * The default priority queue value for new, attached listeners * * @var int */ @@ -50,7 +50,7 @@ class CakeEventManager { protected $_listeners = array(); /** - * Internal flag to distinguish a common manager from the sigleton + * Internal flag to distinguish a common manager from the singleton * * @var boolean */ @@ -62,7 +62,7 @@ class CakeEventManager { * other managers were created. Usually for creating hook systems or inter-class * communication * - * If called with a first params, it will be set as the globally available instance + * If called with the first parameter, it will be set as the globally available instance * * @param CakeEventManager $manager * @return CakeEventManager the global event manager @@ -83,15 +83,15 @@ class CakeEventManager { * Adds a new listener to an event. Listeners * * @param callback|CakeEventListener $callable PHP valid callback type or instance of CakeEventListener to be called - * when the event named with $eventKey is triggered. If a CakeEventListener instances is passed, then the `implementedEvents` + * when the event named with $eventKey is triggered. If a CakeEventListener instance is passed, then the `implementedEvents` * method will be called on the object to register the declared events individually as methods to be managed by this class. * It is possible to define multiple event handlers per event name. * - * @param string $eventKey The event unique identifier name to with the callback will be associated. If $callable + * @param string $eventKey The event unique identifier name with which the callback will be associated. If $callable * is an instance of CakeEventListener this argument will be ignored * * @param array $options used to set the `priority` and `passParams` flags to the listener. - * Priorities are handled like queues, and multiple attachments into the same priority queue will be treated in + * Priorities are handled like queues, and multiple attachments added to the same priority queue will be treated in * the order of insertion. `passParams` means that the event data property will be converted to function arguments * when the listener is called. If $called is an instance of CakeEventListener, this parameter will be ignored * @@ -145,7 +145,7 @@ class CakeEventManager { * Auxiliary function to extract and return a PHP callback type out of the callable definition * from the return value of the `implementedEvents` method on a CakeEventListener * - * @param array $function the array taken from a handler definition for a event + * @param array $function the array taken from a handler definition for an event * @param CakeEventListener $object The handler object * @return callback */ @@ -256,7 +256,7 @@ class CakeEventManager { } /** - * Returns a list of all listeners for a eventKey in the order they should be called + * Returns a list of all listeners for an eventKey in the order they should be called * * @param string $eventKey * @return array diff --git a/lib/Cake/Test/Case/Model/models.php b/lib/Cake/Test/Case/Model/models.php index b550a0ac6..f07303eee 100644 --- a/lib/Cake/Test/Case/Model/models.php +++ b/lib/Cake/Test/Case/Model/models.php @@ -2003,28 +2003,28 @@ class CallbackPostTestModel extends CakeTestModel { /** * variable to control return of beforeValidate * - * @var string + * @var boolean */ public $beforeValidateReturn = true; /** * variable to control return of beforeSave * - * @var string + * @var boolean */ public $beforeSaveReturn = true; /** * variable to control return of beforeDelete * - * @var string + * @var boolean */ public $beforeDeleteReturn = true; /** * beforeSave callback * - * @return void + * @return boolean */ public function beforeSave($options = array()) { return $this->beforeSaveReturn; @@ -2033,7 +2033,7 @@ class CallbackPostTestModel extends CakeTestModel { /** * beforeValidate callback * - * @return void + * @return boolean */ public function beforeValidate($options = array()) { return $this->beforeValidateReturn; @@ -2042,7 +2042,7 @@ class CallbackPostTestModel extends CakeTestModel { /** * beforeDelete callback * - * @return void + * @return boolean */ public function beforeDelete($cascade = true) { return $this->beforeDeleteReturn; From 788cf5257211495bf77329a07ed915142e103c33 Mon Sep 17 00:00:00 2001 From: mark_story Date: Fri, 3 Aug 2012 22:39:51 -0400 Subject: [PATCH 060/256] Fix saving empty values for translated fields with multiple locales --- lib/Cake/Model/Behavior/TranslateBehavior.php | 52 ++++++++++++++----- .../Model/Behavior/TranslateBehaviorTest.php | 39 ++++++++------ 2 files changed, 63 insertions(+), 28 deletions(-) diff --git a/lib/Cake/Model/Behavior/TranslateBehavior.php b/lib/Cake/Model/Behavior/TranslateBehavior.php index e0a1824ee..3eccf6269 100644 --- a/lib/Cake/Model/Behavior/TranslateBehavior.php +++ b/lib/Cake/Model/Behavior/TranslateBehavior.php @@ -385,7 +385,6 @@ class TranslateBehavior extends ModelBehavior { if (!isset($this->runtime[$Model->alias]['beforeValidate']) && !isset($this->runtime[$Model->alias]['beforeSave'])) { return true; } - $locale = $this->_getLocale($Model); if (isset($this->runtime[$Model->alias]['beforeValidate'])) { $tempData = $this->runtime[$Model->alias]['beforeValidate']; } else { @@ -396,18 +395,10 @@ class TranslateBehavior extends ModelBehavior { $conditions = array('model' => $Model->alias, 'foreign_key' => $Model->id); $RuntimeModel = $this->translateModel($Model); - $fields = array_merge($this->settings[$Model->alias], $this->runtime[$Model->alias]['fields']); if ($created) { - // set each field value to an empty string - foreach ($fields as $key => $field) { - if (!is_numeric($key)) { - $field = $key; - } - if (!isset($tempData[$field])) { - $tempData[$field] = ''; - } - } + $tempData = $this->_prepareTranslations($Model, $tempData); } + $locale = $this->_getLocale($Model); foreach ($tempData as $field => $value) { unset($conditions['content']); @@ -422,7 +413,13 @@ class TranslateBehavior extends ModelBehavior { $value = array($locale => $value); } } - $translations = $RuntimeModel->find('list', array('conditions' => $conditions, 'fields' => array($RuntimeModel->alias . '.locale', $RuntimeModel->alias . '.id'))); + $translations = $RuntimeModel->find('list', array( + 'conditions' => $conditions, + 'fields' => array( + $RuntimeModel->alias . '.locale', + $RuntimeModel->alias . '.id' + ) + )); foreach ($value as $_locale => $_value) { $RuntimeModel->create(); $conditions['locale'] = $_locale; @@ -436,6 +433,37 @@ class TranslateBehavior extends ModelBehavior { } } +/** + * Prepares the data to be saved for translated records. + * Add blank fields, and populates data for multi-locale saves. + * + * @param array $data The sparse data that was provided. + * @return array The fully populated data to save. + */ + protected function _prepareTranslations(Model $Model, $data) { + $fields = array_merge($this->settings[$Model->alias], $this->runtime[$Model->alias]['fields']); + $locales = array(); + foreach ($data as $key => $value) { + if (is_array($value)) { + $locales = array_merge($locales, array_keys($value)); + } + } + $locales = array_unique($locales); + $hasLocales = count($locales) > 0; + + foreach ($fields as $key => $field) { + if (!is_numeric($key)) { + $field = $key; + } + if ($hasLocales && !isset($data[$field])) { + $data[$field] = array_fill_keys($locales, ''); + } elseif (!isset($data[$field])) { + $data[$field] = ''; + } + } + return $data; + } + /** * afterDelete Callback * diff --git a/lib/Cake/Test/Case/Model/Behavior/TranslateBehaviorTest.php b/lib/Cake/Test/Case/Model/Behavior/TranslateBehaviorTest.php index f2f9af169..8d6a8a1b4 100644 --- a/lib/Cake/Test/Case/Model/Behavior/TranslateBehaviorTest.php +++ b/lib/Cake/Test/Case/Model/Behavior/TranslateBehaviorTest.php @@ -552,7 +552,17 @@ class TranslateBehaviorTest extends CakeTestCase { ) + $data ); $this->assertEquals($expected, $result); - + } + +/** + * Test that all fields are create with partial data + multiple locales. + * + * @return void + */ + public function testSavePartialFieldMultipleLocales() { + $this->loadFixtures('Translate', 'TranslatedItem'); + + $TestModel = new TranslatedItem(); $TestModel->locale = 'eng'; $data = array( 'slug' => 'fifth_translated', @@ -561,60 +571,57 @@ class TranslateBehaviorTest extends CakeTestCase { $TestModel->create($data); $TestModel->save(); $TestModel->unbindTranslation(); + $translations = array('title' => 'Title', 'content' => 'Content'); $TestModel->bindTranslation($translations, false); $result = $TestModel->read(null, $TestModel->id); $expected = array( 'TranslatedItem' => array( - 'id' => '5', + 'id' => '4', 'translated_article_id' => null, 'slug' => 'fifth_translated', 'locale' => 'eng', - 'title' => '', + 'title' => 'Title #5', 'content' => '' ), - 0 => array( - 'TranslatedItem__i18n_Title' => 'Title #5', - 'TranslatedItem__i18n_Content' => '' - ), 'Title' => array( 0 => array( - 'id' => '21', + 'id' => '19', 'locale' => 'eng', 'model' => 'TranslatedItem', - 'foreign_key' => '5', + 'foreign_key' => '4', 'field' => 'title', 'content' => 'Title #5' ), 1 => array( - 'id' => '22', + 'id' => '20', 'locale' => 'spa', 'model' => 'TranslatedItem', - 'foreign_key' => '5', + 'foreign_key' => '4', 'field' => 'title', 'content' => 'Leyenda #5' ) ), 'Content' => array( 0 => array( - 'id' => '23', + 'id' => '21', 'locale' => 'eng', 'model' => 'TranslatedItem', - 'foreign_key' => '5', + 'foreign_key' => '4', 'field' => 'content', 'content' => '' ), 1 => array( - 'id' => '24', + 'id' => '22', 'locale' => 'spa', 'model' => 'TranslatedItem', - 'foreign_key' => '5', + 'foreign_key' => '4', 'field' => 'content', 'content' => '' ) ) ); - $this->assertEquals($expected, $result); + $this->assertEquals($expected, $result); } /** From 2a570e639ca6ecf359ff13c9358577e4079b827a Mon Sep 17 00:00:00 2001 From: euromark Date: Sat, 4 Aug 2012 19:58:23 +0200 Subject: [PATCH 061/256] ellipsis instead of ending/beginning for core wide consistency --- lib/Cake/Test/Case/Utility/StringTest.php | 29 +++++++++++++++---- lib/Cake/Utility/String.php | 35 ++++++++++++----------- 2 files changed, 43 insertions(+), 21 deletions(-) diff --git a/lib/Cake/Test/Case/Utility/StringTest.php b/lib/Cake/Test/Case/Utility/StringTest.php index 9b6fe1e2b..8f4abdd9b 100644 --- a/lib/Cake/Test/Case/Utility/StringTest.php +++ b/lib/Cake/Test/Case/Utility/StringTest.php @@ -379,7 +379,7 @@ TEXT; $this->assertSame($this->Text->truncate($text2, 10, array('exact' => false)), '...'); $this->assertSame($this->Text->truncate($text3, 20), '© 2005-20...'); $this->assertSame($this->Text->truncate($text4, 15), ' This image ...'); $this->assertSame($this->Text->truncate($text4, 45, array('html' => true)), ' This image tag is not XHTML conform!

    But t...'); $this->assertSame($this->Text->truncate($text4, 90, array('html' => true)), ' This image tag is not XHTML conform!

    But the following image tag should be conform Me, myself and I
    Grea...'); - $this->assertSame($this->Text->truncate($text5, 6, array('ending' => '', 'html' => true)), '012345'); - $this->assertSame($this->Text->truncate($text5, 20, array('ending' => '', 'html' => true)), $text5); + $this->assertSame($this->Text->truncate($text5, 6, array('ellipsis' => '', 'html' => true)), '012345'); + $this->assertSame($this->Text->truncate($text5, 20, array('ellipsis' => '', 'html' => true)), $text5); $this->assertSame($this->Text->truncate($text6, 57, array('exact' => false, 'html' => true)), "

    Extra dates have been announced for this year's...

    "); $this->assertSame($this->Text->truncate($text7, 255), $text7); $this->assertSame($this->Text->truncate($text7, 15), 'El moño está...'); @@ -399,7 +399,7 @@ TEXT; $text = '

    Iamatestwithnospacesandhtml

    '; $result = $this->Text->truncate($text, 10, array( - 'ending' => '...', + 'ellipsis' => '...', 'exact' => false, 'html' => true )); @@ -422,7 +422,7 @@ podeís adquirirla.

    http://www.amazon.com/Steve- Jobs-Walter-Isaacson/dp/1451648537

    '; $result = $this->Text->truncate($text, 500, array( - 'ending' => '... ', + 'ellipsis' => '... ', 'exact' => false, 'html' => true )); @@ -441,6 +441,22 @@ Isaacson", aquí os dejamos la dirección de amazon donde podeís adquirirla.

    ...

    '; $this->assertEquals($expected, $result); + + // test deprecated `ending` (`ellipsis` taking precedence if both are defined) + $result = $this->Text->truncate($text1, 31, array( + 'ending' => '.', + 'exact' => false, + )); + $expected = 'The quick brown fox jumps.'; + $this->assertEquals($expected, $result); + + $result = $this->Text->truncate($text1, 31, array( + 'ellipsis' => '..', + 'ending' => '.', + 'exact' => false, + )); + $expected = 'The quick brown fox jumps..'; + $this->assertEquals($expected, $result); } /** @@ -481,6 +497,9 @@ podeís adquirirla.

    $result = $this->Text->tail($text5, 10); $this->assertEquals('...цчшщъыь', $result); + + $result = $this->Text->tail($text5, 6, array('ellipsis' => '')); + $this->assertEquals('чшщъыь', $result); } /** diff --git a/lib/Cake/Utility/String.php b/lib/Cake/Utility/String.php index f339cd8a3..03bb761b4 100644 --- a/lib/Cake/Utility/String.php +++ b/lib/Cake/Utility/String.php @@ -422,11 +422,11 @@ class String { * Truncates text starting from the end. * * Cuts a string to the length of $length and replaces the first characters - * with the beginning if the text is longer than length. + * with the ellipsis if the text is longer than length. * * ### Options: * - * - `beginning` Will be used as Beginning and prepended to the trimmed string + * - `ellipsis` Will be used as Beginning and prepended to the trimmed string * - `exact` If false, $text will not be cut mid-word * * @param string $text String to truncate. @@ -436,7 +436,7 @@ class String { */ public static function tail($text, $length = 100, $options = array()) { $default = array( - 'beginning' => '...', 'exact' => true + 'ellipsis' => '...', 'exact' => true ); $options = array_merge($default, $options); extract($options); @@ -448,25 +448,25 @@ class String { if (mb_strlen($text) <= $length) { return $text; } else { - $truncate = mb_substr($text, mb_strlen($text) - $length + mb_strlen($beginning)); + $truncate = mb_substr($text, mb_strlen($text) - $length + mb_strlen($ellipsis)); } if (!$exact) { $spacepos = mb_strpos($truncate, ' '); $truncate = $spacepos === false ? '' : trim(mb_substr($truncate, $spacepos)); } - return $beginning . $truncate; + return $ellipsis . $truncate; } /** * Truncates text. * * Cuts a string to the length of $length and replaces the last characters - * with the ending if the text is longer than length. + * with the ellipsis if the text is longer than length. * * ### Options: * - * - `ending` Will be used as Ending and appended to the trimmed string + * - `ellipsis` Will be used as Ending and appended to the trimmed string (`ending` is deprecated) * - `exact` If false, $text will not be cut mid-word * - `html` If true, HTML tags would be handled correctly * @@ -478,8 +478,11 @@ class String { */ public static function truncate($text, $length = 100, $options = array()) { $default = array( - 'ending' => '...', 'exact' => true, 'html' => false + 'ellipsis' => '...', 'exact' => true, 'html' => false ); + if (isset($options['ending'])) { + $default['ellipsis'] = $options['ending']; + } $options = array_merge($default, $options); extract($options); @@ -491,7 +494,7 @@ class String { if (mb_strlen(preg_replace('/<.*?>/', '', $text)) <= $length) { return $text; } - $totalLength = mb_strlen(strip_tags($ending)); + $totalLength = mb_strlen(strip_tags($ellipsis)); $openTags = array(); $truncate = ''; @@ -538,7 +541,7 @@ class String { if (mb_strlen($text) <= $length) { return $text; } else { - $truncate = mb_substr($text, 0, $length - mb_strlen($ending)); + $truncate = mb_substr($text, 0, $length - mb_strlen($ellipsis)); } } if (!$exact) { @@ -570,7 +573,7 @@ class String { } $truncate = mb_substr($truncate, 0, $spacepos); } - $truncate .= $ending; + $truncate .= $ellipsis; if ($html) { foreach ($openTags as $tag) { @@ -588,23 +591,23 @@ class String { * @param string $text String to search the phrase in * @param string $phrase Phrase that will be searched for * @param integer $radius The amount of characters that will be returned on each side of the founded phrase - * @param string $ending Ending that will be appended + * @param string $ellipsis Ending that will be appended * @return string Modified string * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/text.html#TextHelper::excerpt */ - public static function excerpt($text, $phrase, $radius = 100, $ending = '...') { + public static function excerpt($text, $phrase, $radius = 100, $ellipsis = '...') { if (empty($text) || empty($phrase)) { - return self::truncate($text, $radius * 2, array('ending' => $ending)); + return self::truncate($text, $radius * 2, array('ellipsis' => $ellipsis)); } - $append = $prepend = $ending; + $append = $prepend = $ellipsis; $phraseLen = mb_strlen($phrase); $textLen = mb_strlen($text); $pos = mb_strpos(mb_strtolower($text), mb_strtolower($phrase)); if ($pos === false) { - return mb_substr($text, 0, $radius) . $ending; + return mb_substr($text, 0, $radius) . $ellipsis; } $startPos = $pos - $radius; From b32273e713904c84fe18d98f189b49b83b69f1e8 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 4 Aug 2012 15:57:04 -0400 Subject: [PATCH 062/256] Fix whitespace errors. --- lib/Cake/Test/Case/BasicsTest.php | 2 +- lib/Cake/Test/Case/View/Helper/FormHelperTest.php | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/Cake/Test/Case/BasicsTest.php b/lib/Cake/Test/Case/BasicsTest.php index 407986919..0c12fed6f 100644 --- a/lib/Cake/Test/Case/BasicsTest.php +++ b/lib/Cake/Test/Case/BasicsTest.php @@ -225,7 +225,7 @@ class BasicsTest extends CakeTestCase { 'n' => ' ' ); $this->assertEquals($expected, $result); - + // Test that boolean values are not converted to strings $result = h(false); $this->assertFalse($result); diff --git a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php index 80253c28d..ef2686ca2 100644 --- a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php @@ -2347,7 +2347,7 @@ class FormHelperTest extends CakeTestCase { public function testInputCheckboxWithDisabledElements() { $options = array(1 => 'One', 2 => 'Two', '3' => 'Three'); $result = $this->Form->input('Contact.multiple', array('multiple' => 'checkbox', 'disabled' => 'disabled', 'options' => $options)); - + $expected = array( array('div' => array('class' => 'input select')), array('label' => array('for' => "ContactMultiple")), @@ -2375,12 +2375,12 @@ class FormHelperTest extends CakeTestCase { '/div' ); $this->assertTags($result, $expected); - + $result = $this->Form->input('Contact.multiple', array('multiple' => 'checkbox', 'disabled' => true, 'options' => $options)); $this->assertTags($result, $expected); - + $disabled = array('2', 3); - + $expected = array( array('div' => array('class' => 'input select')), array('label' => array('for' => "ContactMultiple")), From 8931b74ba2c3085c28ffdb8767b1400aeef278d0 Mon Sep 17 00:00:00 2001 From: ADmad Date: Sun, 5 Aug 2012 02:16:09 +0530 Subject: [PATCH 063/256] Removed variable escaping in CakeErrorController::beforeRender(). Closes #3074 --- lib/Cake/Controller/CakeErrorController.php | 14 -------------- lib/Cake/Error/ExceptionRenderer.php | 8 ++++---- lib/Cake/Test/Case/Error/ExceptionRendererTest.php | 2 +- lib/Cake/View/Errors/pdo_error.ctp | 6 +++--- 4 files changed, 8 insertions(+), 22 deletions(-) diff --git a/lib/Cake/Controller/CakeErrorController.php b/lib/Cake/Controller/CakeErrorController.php index 14447710c..cf3ccd1f3 100644 --- a/lib/Cake/Controller/CakeErrorController.php +++ b/lib/Cake/Controller/CakeErrorController.php @@ -66,18 +66,4 @@ class CakeErrorController extends AppController { $this->_set(array('cacheAction' => false, 'viewPath' => 'Errors')); } -/** - * Escapes the viewVars. - * - * @return void - */ - public function beforeRender() { - parent::beforeRender(); - foreach ($this->viewVars as $key => $value) { - if (!is_object($value)) { - $this->viewVars[$key] = h($value); - } - } - } - } diff --git a/lib/Cake/Error/ExceptionRenderer.php b/lib/Cake/Error/ExceptionRenderer.php index 8c69e4d0e..372a643e2 100644 --- a/lib/Cake/Error/ExceptionRenderer.php +++ b/lib/Cake/Error/ExceptionRenderer.php @@ -184,7 +184,7 @@ class ExceptionRenderer { $this->controller->set(array( 'code' => $code, 'url' => h($url), - 'name' => $error->getMessage(), + 'name' => h($error->getMessage()), 'error' => $error, '_serialize' => array('code', 'url', 'name') )); @@ -206,7 +206,7 @@ class ExceptionRenderer { $url = $this->controller->request->here(); $this->controller->response->statusCode($error->getCode()); $this->controller->set(array( - 'name' => $message, + 'name' => h($message), 'url' => h($url), 'error' => $error, '_serialize' => array('name', 'url') @@ -229,7 +229,7 @@ class ExceptionRenderer { $code = ($error->getCode() > 500 && $error->getCode() < 506) ? $error->getCode() : 500; $this->controller->response->statusCode($code); $this->controller->set(array( - 'name' => $message, + 'name' => h($message), 'message' => h($url), 'error' => $error, '_serialize' => array('name', 'message') @@ -250,7 +250,7 @@ class ExceptionRenderer { $this->controller->set(array( 'code' => $code, 'url' => h($url), - 'name' => $error->getMessage(), + 'name' => h($error->getMessage()), 'error' => $error, '_serialize' => array('code', 'url', 'name', 'error') )); diff --git a/lib/Cake/Test/Case/Error/ExceptionRendererTest.php b/lib/Cake/Test/Case/Error/ExceptionRendererTest.php index 956acecc2..22d44316d 100644 --- a/lib/Cake/Test/Case/Error/ExceptionRendererTest.php +++ b/lib/Cake/Test/Case/Error/ExceptionRendererTest.php @@ -770,7 +770,7 @@ class ExceptionRendererTest extends CakeTestCase { $this->assertContains('

    Database Error

    ', $result); $this->assertContains('There was an error in the SQL query', $result); - $this->assertContains('SELECT * from poo_query < 5 and :seven', $result); + $this->assertContains(h('SELECT * from poo_query < 5 and :seven'), $result); $this->assertContains("'seven' => (int) 7", $result); } } diff --git a/lib/Cake/View/Errors/pdo_error.ctp b/lib/Cake/View/Errors/pdo_error.ctp index 9aecee6cf..a6af55939 100644 --- a/lib/Cake/View/Errors/pdo_error.ctp +++ b/lib/Cake/View/Errors/pdo_error.ctp @@ -19,17 +19,17 @@

    : - getMessage()); ?> +

    queryString)) : ?>

    : - queryString; ?> + queryString); ?>

    params)) : ?> : - params); ?> + params); ?>

    : From 57c495f53a63b92fe2766f03d6f20754f79be31d Mon Sep 17 00:00:00 2001 From: mark_story Date: Mon, 6 Aug 2012 13:31:35 -0400 Subject: [PATCH 064/256] Enabled Debugger::exportVar() to display private & protected properties. This will only work in PHP >= 5.3. Patch originally created by 'dereuromark'. --- lib/Cake/Test/Case/Utility/DebuggerTest.php | 35 +++++++++++++++++++++ lib/Cake/Utility/Debugger.php | 25 +++++++++++++++ 2 files changed, 60 insertions(+) diff --git a/lib/Cake/Test/Case/Utility/DebuggerTest.php b/lib/Cake/Test/Case/Utility/DebuggerTest.php index b57dcf932..40a7ef3d4 100644 --- a/lib/Cake/Test/Case/Utility/DebuggerTest.php +++ b/lib/Cake/Test/Case/Utility/DebuggerTest.php @@ -325,8 +325,43 @@ object(View) { elementCacheSettings => array() int => (int) 2 float => (float) 1.333 + +TEXT; + if (version_compare(PHP_VERSION, '5.3.0') >= 0) { + $expected .= << array( + (int) 0 => 'viewVars', + (int) 1 => 'autoLayout', + (int) 2 => 'ext', + (int) 3 => 'helpers', + (int) 4 => 'view', + (int) 5 => 'layout', + (int) 6 => 'name', + (int) 7 => 'theme', + (int) 8 => 'layoutPath', + (int) 9 => 'viewPath', + (int) 10 => 'request', + (int) 11 => 'plugin', + (int) 12 => 'passedArgs', + (int) 13 => 'cacheAction' + ) + [protected] _scripts => array() + [protected] _paths => array() + [protected] _helpersLoaded => false + [protected] _parents => array() + [protected] _current => null + [protected] _currentType => '' + [protected] _stack => array() + [protected] _eventManager => object(CakeEventManager) {} + [protected] _eventManagerConfigured => false + [private] __viewFileName => null + +TEXT; + } + $expected .= <<assertTextEquals($expected, $result); $data = array( diff --git a/lib/Cake/Utility/Debugger.php b/lib/Cake/Utility/Debugger.php index 319701fe2..87ba9ca1c 100644 --- a/lib/Cake/Utility/Debugger.php +++ b/lib/Cake/Utility/Debugger.php @@ -576,6 +576,31 @@ class Debugger { $value = self::_export($value, $depth - 1, $indent); $props[] = "$key => " . $value; } + + if (version_compare(PHP_VERSION, '5.3.0') >= 0) { + $ref = new ReflectionObject($var); + + $reflectionProperties = $ref->getProperties(ReflectionProperty::IS_PROTECTED); + foreach ($reflectionProperties as $reflectionProperty) { + $reflectionProperty->setAccessible(true); + $property = $reflectionProperty->getValue($var); + + $value = self::_export($property, $depth - 1, $indent); + $key = $reflectionProperty->name; + $props[] = "[protected] $key => " . $value; + } + + $reflectionProperties = $ref->getProperties(ReflectionProperty::IS_PRIVATE); + foreach ($reflectionProperties as $reflectionProperty) { + $reflectionProperty->setAccessible(true); + $property = $reflectionProperty->getValue($var); + + $value = self::_export($property, $depth - 1, $indent); + $key = $reflectionProperty->name; + $props[] = "[private] $key => " . $value; + } + } + $out .= $break . implode($break, $props) . $end; } $out .= '}'; From 5e0e85073337620fbd5e9c3ca7d9aefda491e709 Mon Sep 17 00:00:00 2001 From: euromark Date: Wed, 8 Aug 2012 13:42:40 +0200 Subject: [PATCH 065/256] reduce 5-level if cases to 2 levels --- lib/Cake/Model/CakeSchema.php | 74 ++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 35 deletions(-) diff --git a/lib/Cake/Model/CakeSchema.php b/lib/Cake/Model/CakeSchema.php index 60c3b7643..f72316a03 100644 --- a/lib/Cake/Model/CakeSchema.php +++ b/lib/Cake/Model/CakeSchema.php @@ -254,44 +254,48 @@ class CakeSchema extends Object { continue; } - $db = $Object->getDataSource(); - if (is_object($Object) && $Object->useTable !== false) { - $fulltable = $table = $db->fullTableName($Object, false, false); - if ($prefix && strpos($table, $prefix) !== 0) { + $fulltable = $table = $db->fullTableName($Object, false, false); + if ($prefix && strpos($table, $prefix) !== 0) { + continue; + } + if (!is_object($Object) || $Object->useTable === false) { + continue; + } + if (!in_array($fulltable, $currentTables)) { + continue; + } + + $table = $this->_noPrefixTable($prefix, $table); + + $key = array_search($fulltable, $currentTables); + if (empty($tables[$table])) { + $tables[$table] = $this->_columns($Object); + $tables[$table]['indexes'] = $db->index($Object); + $tables[$table]['tableParameters'] = $db->readTableParameters($fulltable); + unset($currentTables[$key]); + } + if (empty($Object->hasAndBelongsToMany)) { + continue; + } + foreach ($Object->hasAndBelongsToMany as $Assoc => $assocData) { + if (isset($assocData['with'])) { + $class = $assocData['with']; + } + if (!is_object($Object->$class)) { continue; } - $table = $this->_noPrefixTable($prefix, $table); + $withTable = $db->fullTableName($Object->$class, false, false); + if ($prefix && strpos($withTable, $prefix) !== 0) { + continue; + } + if (in_array($withTable, $currentTables)) { + $key = array_search($withTable, $currentTables); + $noPrefixWith = $this->_noPrefixTable($prefix, $withTable); - if (in_array($fulltable, $currentTables)) { - $key = array_search($fulltable, $currentTables); - if (empty($tables[$table])) { - $tables[$table] = $this->_columns($Object); - $tables[$table]['indexes'] = $db->index($Object); - $tables[$table]['tableParameters'] = $db->readTableParameters($fulltable); - unset($currentTables[$key]); - } - if (!empty($Object->hasAndBelongsToMany)) { - foreach ($Object->hasAndBelongsToMany as $Assoc => $assocData) { - if (isset($assocData['with'])) { - $class = $assocData['with']; - } - if (is_object($Object->$class)) { - $withTable = $db->fullTableName($Object->$class, false, false); - if ($prefix && strpos($withTable, $prefix) !== 0) { - continue; - } - if (in_array($withTable, $currentTables)) { - $key = array_search($withTable, $currentTables); - $noPrefixWith = $this->_noPrefixTable($prefix, $withTable); - - $tables[$noPrefixWith] = $this->_columns($Object->$class); - $tables[$noPrefixWith]['indexes'] = $db->index($Object->$class); - $tables[$noPrefixWith]['tableParameters'] = $db->readTableParameters($withTable); - unset($currentTables[$key]); - } - } - } - } + $tables[$noPrefixWith] = $this->_columns($Object->$class); + $tables[$noPrefixWith]['indexes'] = $db->index($Object->$class); + $tables[$noPrefixWith]['tableParameters'] = $db->readTableParameters($withTable); + unset($currentTables[$key]); } } } From 62dee78ca5ab69356a026d89e025c0b2d762886b Mon Sep 17 00:00:00 2001 From: euromark Date: Wed, 8 Aug 2012 14:15:28 +0200 Subject: [PATCH 066/256] adding models for schema generate --- lib/Cake/Console/Command/SchemaShell.php | 10 ++++-- .../Case/Console/Command/SchemaShellTest.php | 35 +++++++++++++++++++ 2 files changed, 43 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Console/Command/SchemaShell.php b/lib/Cake/Console/Command/SchemaShell.php index eb3321500..4fed54b7f 100644 --- a/lib/Cake/Console/Command/SchemaShell.php +++ b/lib/Cake/Console/Command/SchemaShell.php @@ -127,7 +127,9 @@ class SchemaShell extends AppShell { $this->out(__d('cake_console', 'Generating Schema...')); $options = array(); if ($this->params['force']) { - $options = array('models' => false); + $options['models'] = false; + } elseif (!empty($this->params['models'])) { + $options['models'] = String::tokenize($this->params['models']); } $snapshot = false; @@ -464,6 +466,10 @@ class SchemaShell extends AppShell { 'short' => 's', 'help' => __d('cake_console', 'Snapshot number to use/make.') ); + $models = array( + 'short' => 'm', + 'help' => __d('cake_console', 'Specify models as comma separated list.'), + ); $dry = array( 'help' => __d('cake_console', 'Perform a dry run on create and update commands. Queries will be output instead of run.'), 'boolean' => true @@ -489,7 +495,7 @@ class SchemaShell extends AppShell { ))->addSubcommand('generate', array( 'help' => __d('cake_console', 'Reads from --connection and writes to --path. Generate snapshots with -s'), 'parser' => array( - 'options' => compact('plugin', 'path', 'file', 'name', 'connection', 'snapshot', 'force'), + 'options' => compact('plugin', 'path', 'file', 'name', 'connection', 'snapshot', 'force', 'models'), 'arguments' => array( 'snapshot' => array('help' => __d('cake_console', 'Generate a snapshot.')) ) diff --git a/lib/Cake/Test/Case/Console/Command/SchemaShellTest.php b/lib/Cake/Test/Case/Console/Command/SchemaShellTest.php index 7d2175389..3c3be73aa 100644 --- a/lib/Cake/Test/Case/Console/Command/SchemaShellTest.php +++ b/lib/Cake/Test/Case/Console/Command/SchemaShellTest.php @@ -362,6 +362,41 @@ class SchemaShellTest extends CakeTestCase { CakePlugin::unload(); } +/** + * test generate with specific models + * + * @return void + */ + public function testGenerateModels() { + App::build(array( + 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS) + ), App::RESET); + CakePlugin::load('TestPlugin'); + + $this->db->cacheSources = false; + $this->Shell->params = array( + 'plugin' => 'TestPlugin', + 'connection' => 'test', + 'models' => 'TestPluginComment', + 'force' => false, + 'overwrite' => true + ); + $this->Shell->startup(); + $this->Shell->Schema->path = TMP . 'tests' . DS; + + $this->Shell->generate(); + $this->file = new File(TMP . 'tests' . DS . 'schema.php'); + $contents = $this->file->read(); + + $this->assertRegExp('/class TestPluginSchema/', $contents); + $this->assertRegExp('/public \$test_plugin_comments/', $contents); + $this->assertNotRegExp('/public \$authors/', $contents); + $this->assertNotRegExp('/public \$auth_users/', $contents); + $this->assertNotRegExp('/public \$posts/', $contents); + CakePlugin::unload(); + } + + /** * Test schema run create with no table args. * From bed5453be0271f0b0fe925ccd3cd6721c185e088 Mon Sep 17 00:00:00 2001 From: euromark Date: Wed, 8 Aug 2012 14:44:38 +0200 Subject: [PATCH 067/256] correcting order --- lib/Cake/Model/CakeSchema.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/Cake/Model/CakeSchema.php b/lib/Cake/Model/CakeSchema.php index f72316a03..0d15d9ae7 100644 --- a/lib/Cake/Model/CakeSchema.php +++ b/lib/Cake/Model/CakeSchema.php @@ -254,11 +254,12 @@ class CakeSchema extends Object { continue; } - $fulltable = $table = $db->fullTableName($Object, false, false); - if ($prefix && strpos($table, $prefix) !== 0) { + if (!is_object($Object) || $Object->useTable === false) { continue; } - if (!is_object($Object) || $Object->useTable === false) { + + $fulltable = $table = $db->fullTableName($Object, false, false); + if ($prefix && strpos($table, $prefix) !== 0) { continue; } if (!in_array($fulltable, $currentTables)) { From 5190b9f2c91f5ac2adf36ce529c1be53ff89e8f2 Mon Sep 17 00:00:00 2001 From: euromark Date: Wed, 8 Aug 2012 16:35:59 +0200 Subject: [PATCH 068/256] asserting that under_scored names result in valid ClassNames --- lib/Cake/Console/Command/SchemaShell.php | 1 + .../Case/Console/Command/SchemaShellTest.php | 29 +++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/lib/Cake/Console/Command/SchemaShell.php b/lib/Cake/Console/Command/SchemaShell.php index 4fed54b7f..5b1d94057 100644 --- a/lib/Cake/Console/Command/SchemaShell.php +++ b/lib/Cake/Console/Command/SchemaShell.php @@ -96,6 +96,7 @@ class SchemaShell extends AppShell { $name = $plugin; } } + $name = Inflector::classify($name); $this->Schema = new CakeSchema(compact('name', 'path', 'file', 'connection', 'plugin')); } diff --git a/lib/Cake/Test/Case/Console/Command/SchemaShellTest.php b/lib/Cake/Test/Case/Console/Command/SchemaShellTest.php index 3c3be73aa..d47f55691 100644 --- a/lib/Cake/Test/Case/Console/Command/SchemaShellTest.php +++ b/lib/Cake/Test/Case/Console/Command/SchemaShellTest.php @@ -498,6 +498,35 @@ class SchemaShellTest extends CakeTestCase { CakePlugin::unload(); } +/** + * test that underscored names also result in CamelCased class names + * + * @return void + */ + public function testName() { + App::build(array( + 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS) + )); + CakePlugin::load('TestPlugin'); + $this->Shell->params = array( + 'plugin' => 'TestPlugin', + 'connection' => 'test', + 'name' => 'custom_name', + 'force' => false, + 'overwrite' => true, + ); + $this->Shell->startup(); + if (file_exists($this->Shell->Schema->path . DS . 'custom_name.php')) { + unlink($this->Shell->Schema->path . DS . 'custom_name.php'); + } + $this->Shell->generate(); + + $contents = file_get_contents($this->Shell->Schema->path . DS . 'custom_name.php'); + $this->assertRegExp('/class CustomNameSchema/', $contents); + unlink($this->Shell->Schema->path . DS . 'custom_name.php'); + CakePlugin::unload(); + } + /** * test that using Plugin.name with write. * From 36243b45f87600939f271acd72cfd02c8f70fc86 Mon Sep 17 00:00:00 2001 From: Saleh Souzanchi Date: Thu, 9 Aug 2012 06:42:24 +0430 Subject: [PATCH 069/256] Full url prefix is better defined before auto loading --- lib/Cake/bootstrap.php | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/lib/Cake/bootstrap.php b/lib/Cake/bootstrap.php index 40ac76b4d..9fdd3d589 100644 --- a/lib/Cake/bootstrap.php +++ b/lib/Cake/bootstrap.php @@ -126,21 +126,12 @@ if (!defined('JS_URL')) { } + + require CAKE . 'basics.php'; require CAKE . 'Core' . DS . 'App.php'; require CAKE . 'Error' . DS . 'exceptions.php'; -spl_autoload_register(array('App', 'load')); - -App::uses('ErrorHandler', 'Error'); -App::uses('Configure', 'Core'); -App::uses('CakePlugin', 'Core'); -App::uses('Cache', 'Cache'); -App::uses('Object', 'Core'); -App::$bootstrapping = true; - -Configure::bootstrap(isset($boot) ? $boot : true); - /** * Full url prefix @@ -158,3 +149,15 @@ if (!defined('FULL_BASE_URL')) { } unset($httpHost, $s); } + +spl_autoload_register(array('App', 'load')); + +App::uses('ErrorHandler', 'Error'); +App::uses('Configure', 'Core'); +App::uses('CakePlugin', 'Core'); +App::uses('Cache', 'Cache'); +App::uses('Object', 'Core'); +App::$bootstrapping = true; + +Configure::bootstrap(isset($boot) ? $boot : true); + From d4986b5f2469c7f8fcbbc26a581849ccf228cdbf Mon Sep 17 00:00:00 2001 From: Ceeram Date: Wed, 8 Aug 2012 13:13:28 +0200 Subject: [PATCH 070/256] add responseHeader() method to new base exception class, ExceptionRenderer will pass the headers to the response. Tests added. --- lib/Cake/Error/ExceptionRenderer.php | 5 +++ lib/Cake/Error/exceptions.php | 41 ++++++++++++++++++- .../Test/Case/Error/ExceptionRendererTest.php | 21 ++++++++++ 3 files changed, 65 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Error/ExceptionRenderer.php b/lib/Cake/Error/ExceptionRenderer.php index 372a643e2..fb55b3ad6 100644 --- a/lib/Cake/Error/ExceptionRenderer.php +++ b/lib/Cake/Error/ExceptionRenderer.php @@ -147,6 +147,11 @@ class ExceptionRenderer { $request = new CakeRequest(); } $response = new CakeResponse(array('charset' => Configure::read('App.encoding'))); + + if (method_exists($exception, 'responseHeader')) { + $response->header($exception->responseHeader()); + } + try { if (class_exists('AppController')) { $controller = new CakeErrorController($request, $response); diff --git a/lib/Cake/Error/exceptions.php b/lib/Cake/Error/exceptions.php index 94952f12e..3d0757106 100644 --- a/lib/Cake/Error/exceptions.php +++ b/lib/Cake/Error/exceptions.php @@ -18,6 +18,43 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +/** + * Base class that all Exceptions extend. + * + * @package Cake.Error + */ +class CakeBaseException extends RuntimeException { + +/** + * Array of headers to be passed to CakeResponse::header() + * + * @var array + */ + protected $_responseHeaders = null; + +/** + * Get/set the response header to be used + * + * See also CakeResponse::header() + * + * @param string|array $header. An array of header strings or a single header string + * - an associative array of "header name" => "header value" + * - an array of string headers is also accepted + * @param string $value. The header value. + * @return array + */ + public function responseHeader($header = null, $value = null) { + if ($header) { + if (is_array($header)) { + return $this->_responseHeaders = $header; + } + $this->_responseHeaders = array($header => $value); + } + return $this->_responseHeaders; + } + +} + /** * Parent class for all of the HTTP related exceptions in CakePHP. * All HTTP status/error related exceptions should extend this class so @@ -26,7 +63,7 @@ * @package Cake.Error */ if (!class_exists('HttpException')) { - class HttpException extends RuntimeException { + class HttpException extends CakeBaseException { } } @@ -168,7 +205,7 @@ class InternalErrorException extends HttpException { * * @package Cake.Error */ -class CakeException extends RuntimeException { +class CakeException extends CakeBaseException { /** * Array of attributes that are passed in from the constructor, and diff --git a/lib/Cake/Test/Case/Error/ExceptionRendererTest.php b/lib/Cake/Test/Case/Error/ExceptionRendererTest.php index 22d44316d..04cb2df8c 100644 --- a/lib/Cake/Test/Case/Error/ExceptionRendererTest.php +++ b/lib/Cake/Test/Case/Error/ExceptionRendererTest.php @@ -480,6 +480,27 @@ class ExceptionRendererTest extends CakeTestCase { $this->assertRegExp('/

    An Internal Error Has Occurred<\/h2>/', $result); } +/** + * testExceptionResponseHeader method + * + * @return void + */ + public function testExceptionResponseHeader() { + $exception = new MethodNotAllowedException('Only allowing POST and DELETE'); + $exception->responseHeader(array('Allow: POST, DELETE')); + $ExceptionRenderer = new ExceptionRenderer($exception); + + //Replace response object with mocked object add back the original headers which had been set in ExceptionRenderer constructor + $headers = $ExceptionRenderer->controller->response->header(); + $ExceptionRenderer->controller->response = $this->getMock('CakeResponse', array('_sendHeader')); + $ExceptionRenderer->controller->response->header($headers); + + $ExceptionRenderer->controller->response->expects($this->at(1))->method('_sendHeader')->with('Allow', 'POST, DELETE'); + ob_start(); + $ExceptionRenderer->render(); + $result = ob_get_clean(); + } + /** * testMissingController method * From 6f7557898d2e5bb22b2d030b860d111f76279fb3 Mon Sep 17 00:00:00 2001 From: mark_story Date: Thu, 9 Aug 2012 20:51:29 -0400 Subject: [PATCH 071/256] Fix whitespace and comment errors. --- lib/Cake/Network/CakeSocket.php | 32 ++++++++------- lib/Cake/Test/Case/Network/CakeSocketTest.php | 41 ++++++++++--------- .../Case/Network/Email/SmtpTransportTest.php | 4 +- 3 files changed, 41 insertions(+), 36 deletions(-) diff --git a/lib/Cake/Network/CakeSocket.php b/lib/Cake/Network/CakeSocket.php index d2d72e76a..c5b98a33d 100644 --- a/lib/Cake/Network/CakeSocket.php +++ b/lib/Cake/Network/CakeSocket.php @@ -41,11 +41,11 @@ class CakeSocket { * @var array */ protected $_baseConfig = array( - 'persistent' => false, - 'host' => 'localhost', - 'protocol' => 'tcp', - 'port' => 80, - 'timeout' => 30 + 'persistent' => false, + 'host' => 'localhost', + 'protocol' => 'tcp', + 'port' => 80, + 'timeout' => 30 ); /** @@ -78,13 +78,15 @@ class CakeSocket { /** * True if the socket stream is encrypted after a CakeSocket::enableCrypto() call - * @var type - */ + * + * @var boolean + */ public $encrypted = false; - + /** * Contains all the encryption methods available - * @var array + * + * @var array */ protected $_encryptMethods = array( 'sslv2_client' => STREAM_CRYPTO_METHOD_SSLv2_CLIENT, @@ -300,13 +302,14 @@ class CakeSocket { /** * Encrypts current stream socket, using one of the defined encryption methods - * + * * @param string $type can be one of 'ssl2', 'ssl3', 'ssl23' or 'tls' * @param string $clientOrServer can be one of 'client', 'server'. Default is 'client' * @param boolean $enable enable or disable encryption. Default is true (enable) * @return boolean True on success - * @throws SocketException - * @see stream_socket_enable_crypto + * @throws InvalidArgumentException When an invalid encryption scheme is chosen. + * @throws SocketException When attempting to enable SSL/TLS fails + * @see stream_socket_enable_crypto */ public function enableCrypto($type, $clientOrServer = 'client', $enable = true) { if (!array_key_exists($type . '_' . $clientOrServer, $this->_encryptMethods)) { @@ -327,5 +330,6 @@ class CakeSocket { $this->setLastError(null, $errorMessage); throw new SocketException($errorMessage); } - } -} \ No newline at end of file + } + +} diff --git a/lib/Cake/Test/Case/Network/CakeSocketTest.php b/lib/Cake/Test/Case/Network/CakeSocketTest.php index b214ca9b5..0cee94c38 100644 --- a/lib/Cake/Test/Case/Network/CakeSocketTest.php +++ b/lib/Cake/Test/Case/Network/CakeSocketTest.php @@ -217,10 +217,10 @@ class CakeSocketTest extends CakeTestCase { /** * testEncrypt - * + * * @expectedException SocketException * @return void - */ + */ public function testEnableCryptoSocketExceptionNoSsl() { $configNoSslOrTls = array('host' => 'localhost', 'port' => 80, 'timeout' => 0.1); @@ -232,10 +232,10 @@ class CakeSocketTest extends CakeTestCase { /** * testEnableCryptoSocketExceptionNoTls - * + * * @expectedException SocketException * @return void - */ + */ public function testEnableCryptoSocketExceptionNoTls() { $configNoSslOrTls = array('host' => 'localhost', 'port' => 80, 'timeout' => 0.1); @@ -247,9 +247,9 @@ class CakeSocketTest extends CakeTestCase { /** * _connectSocketToSslTls - * + * * @return void - */ + */ protected function _connectSocketToSslTls() { $configSslTls = array('host' => 'smtp.gmail.com', 'port' => 465, 'timeout' => 5); $this->Socket = new CakeSocket($configSslTls); @@ -258,22 +258,22 @@ class CakeSocketTest extends CakeTestCase { /** * testEnableCryptoBadMode - * + * * @expectedException InvalidArgumentException * @return void - */ + */ public function testEnableCryptoBadMode() { // testing wrong encryption mode $this->_connectSocketToSslTls(); $this->Socket->enableCrypto('doesntExistMode', 'server'); $this->Socket->disconnect(); } - + /** * testEnableCrypto - * + * * @return void - */ + */ public function testEnableCrypto() { // testing on ssl server $this->_connectSocketToSslTls(); @@ -285,13 +285,13 @@ class CakeSocketTest extends CakeTestCase { $this->assertTrue($this->Socket->enableCrypto('tls', 'client')); $this->Socket->disconnect(); } - + /** * testEnableCryptoExceptionEnableTwice - * + * * @expectedException SocketException * @return void - */ + */ public function testEnableCryptoExceptionEnableTwice() { // testing on tls server $this->_connectSocketToSslTls(); @@ -301,26 +301,27 @@ class CakeSocketTest extends CakeTestCase { /** * testEnableCryptoExceptionDisableTwice - * + * * @expectedException SocketException * @return void - */ + */ public function testEnableCryptoExceptionDisableTwice() { // testing on tls server $this->_connectSocketToSslTls(); $this->Socket->enableCrypto('tls', 'client', false); - } + } /** * testEnableCryptoEnableStatus - * + * * @return void - */ + */ public function testEnableCryptoEnableStatus() { // testing on tls server $this->_connectSocketToSslTls(); $this->assertFalse($this->Socket->encrypted); $this->Socket->enableCrypto('tls', 'client', true); $this->assertTrue($this->Socket->encrypted); - } + } + } diff --git a/lib/Cake/Test/Case/Network/Email/SmtpTransportTest.php b/lib/Cake/Test/Case/Network/Email/SmtpTransportTest.php index 55dc7bb0a..53b213a38 100644 --- a/lib/Cake/Test/Case/Network/Email/SmtpTransportTest.php +++ b/lib/Cake/Test/Case/Network/Email/SmtpTransportTest.php @@ -147,7 +147,7 @@ class SmtpTransportTest extends CakeTestCase { $this->socket->expects($this->at(7))->method('read')->will($this->returnValue("500 5.3.3 Unrecognized command\r\n")); $this->SmtpTransport->connect(); } - + /** * testConnectEhloNoTlsOnRequiredTlsServer method * @@ -168,7 +168,7 @@ class SmtpTransportTest extends CakeTestCase { $this->SmtpTransport->connect(); $this->SmtpTransport->auth(); } - + /** * testConnectHelo method * From e5ad204265055ca8170315201969ea19f9d8eea8 Mon Sep 17 00:00:00 2001 From: mark_story Date: Thu, 9 Aug 2012 20:54:04 -0400 Subject: [PATCH 072/256] Ignore standards for PHP defined constants. --- lib/Cake/Network/CakeSocket.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/Cake/Network/CakeSocket.php b/lib/Cake/Network/CakeSocket.php index c5b98a33d..04f0302c4 100644 --- a/lib/Cake/Network/CakeSocket.php +++ b/lib/Cake/Network/CakeSocket.php @@ -89,6 +89,7 @@ class CakeSocket { * @var array */ protected $_encryptMethods = array( + // @codingStandardsIgnoreStart 'sslv2_client' => STREAM_CRYPTO_METHOD_SSLv2_CLIENT, 'sslv3_client' => STREAM_CRYPTO_METHOD_SSLv3_CLIENT, 'sslv23_client' => STREAM_CRYPTO_METHOD_SSLv23_CLIENT, @@ -97,6 +98,7 @@ class CakeSocket { 'sslv3_server' => STREAM_CRYPTO_METHOD_SSLv3_SERVER, 'sslv23_server' => STREAM_CRYPTO_METHOD_SSLv23_SERVER, 'tls_server' => STREAM_CRYPTO_METHOD_TLS_SERVER + // @codingStandardsIgnoreEnd ); /** From e2e42ee185f48d88350d7c060636ef009b8c0b3c Mon Sep 17 00:00:00 2001 From: Ceeram Date: Fri, 10 Aug 2012 09:54:05 +0200 Subject: [PATCH 073/256] move serialization to separate method, for easier overriding in subclasses --- lib/Cake/View/JsonView.php | 31 +++++++++++++++++++------------ lib/Cake/View/XmlView.php | 36 ++++++++++++++++++++++-------------- 2 files changed, 41 insertions(+), 26 deletions(-) diff --git a/lib/Cake/View/JsonView.php b/lib/Cake/View/JsonView.php index 785f75437..188c29d1e 100644 --- a/lib/Cake/View/JsonView.php +++ b/lib/Cake/View/JsonView.php @@ -82,18 +82,7 @@ class JsonView extends View { */ public function render($view = null, $layout = null) { if (isset($this->viewVars['_serialize'])) { - $serialize = $this->viewVars['_serialize']; - if (is_array($serialize)) { - $data = array(); - foreach ($serialize as $key) { - $data[$key] = $this->viewVars[$key]; - } - } else { - $data = isset($this->viewVars[$serialize]) ? $this->viewVars[$serialize] : null; - } - $content = json_encode($data); - $this->Blocks->set('content', $content); - return $content; + return $this->_serialize($this->viewVars['_serialize']); } if ($view !== false && $viewFileName = $this->_getViewFileName($view)) { if (!$this->_helpersLoaded) { @@ -105,4 +94,22 @@ class JsonView extends View { } } +/** + * Serialize view vars + * + * @param array $serialize The viewVars that need to be serialized + * @return string The serialized data + */ + protected function _serialize($serialize) { + if (is_array($serialize)) { + $data = array(); + foreach ($serialize as $key) { + $data[$key] = $this->viewVars[$key]; + } + } else { + $data = isset($this->viewVars[$serialize]) ? $this->viewVars[$serialize] : null; + } + return json_encode($data); + } + } diff --git a/lib/Cake/View/XmlView.php b/lib/Cake/View/XmlView.php index f89efa6ee..9b81066ba 100644 --- a/lib/Cake/View/XmlView.php +++ b/lib/Cake/View/XmlView.php @@ -85,20 +85,7 @@ class XmlView extends View { */ public function render($view = null, $layout = null) { if (isset($this->viewVars['_serialize'])) { - $serialize = $this->viewVars['_serialize']; - if (is_array($serialize)) { - $data = array('response' => array()); - foreach ($serialize as $key) { - $data['response'][$key] = $this->viewVars[$key]; - } - } else { - $data = isset($this->viewVars[$serialize]) ? $this->viewVars[$serialize] : null; - if (is_array($data) && Set::numeric(array_keys($data))) { - $data = array('response' => array($serialize => $data)); - } - } - $content = Xml::fromArray($data)->asXML(); - return $content; + return $this->_serialize($this->viewVars['_serialize']); } if ($view !== false && $viewFileName = $this->_getViewFileName($view)) { if (!$this->_helpersLoaded) { @@ -110,4 +97,25 @@ class XmlView extends View { } } +/** + * Serialize view vars + * + * @param array $serialize The viewVars that need to be serialized + * @return string The serialized data + */ + protected function _serialize($serialize) { + if (is_array($serialize)) { + $data = array('response' => array()); + foreach ($serialize as $key) { + $data['response'][$key] = $this->viewVars[$key]; + } + } else { + $data = isset($this->viewVars[$serialize]) ? $this->viewVars[$serialize] : null; + if (is_array($data) && Set::numeric(array_keys($data))) { + $data = array('response' => array($serialize => $data)); + } + } + return Xml::fromArray($data)->asXML(); + } + } From 21431cba64a05e2098b9e9be42f177c6491dc498 Mon Sep 17 00:00:00 2001 From: Ceeram Date: Fri, 10 Aug 2012 09:54:22 +0200 Subject: [PATCH 074/256] Add viewClass map method to RequestHandler component, to map content types to viewclass. --- .../Component/RequestHandlerComponent.php | 44 ++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Controller/Component/RequestHandlerComponent.php b/lib/Cake/Controller/Component/RequestHandlerComponent.php index d6a182b7e..ee90814b3 100644 --- a/lib/Cake/Controller/Component/RequestHandlerComponent.php +++ b/lib/Cake/Controller/Component/RequestHandlerComponent.php @@ -89,6 +89,17 @@ class RequestHandlerComponent extends Component { 'json' => array('json_decode', true) ); +/** + * A mapping between type and viewClass + * By default only JSON and XML are mapped, use RequestHandlerComponent::viewClassMap() + * + * @var array + */ + protected $_viewClassMap = array( + 'json' => 'Json', + 'xml' => 'Xml' + ); + /** * Constructor. Parses the accepted content types accepted by the client using HTTP_ACCEPT * @@ -125,6 +136,9 @@ class RequestHandlerComponent extends Component { } $this->params = $controller->params; $this->_set($settings); + if (!empty($settings['viewClassMap'])) { + $this->viewClassMap($settings['viewClassMap']); + } } /** @@ -581,10 +595,16 @@ class RequestHandlerComponent extends Component { } $controller->ext = '.ctp'; - $viewClass = Inflector::classify($type); + $pluginDot = null; + $viewClassMap = $this->viewClassMap(); + if (array_key_exists($type, $viewClassMap)) { + list($pluginDot, $viewClass) = pluginSplit($viewClassMap[$type], true); + } else { + $viewClass = Inflector::classify($type); + } $viewName = $viewClass . 'View'; if (!class_exists($viewName)) { - App::uses($viewName, 'View'); + App::uses($viewName, $pluginDot . 'View'); } if (class_exists($viewName)) { $controller->viewClass = $viewClass; @@ -728,4 +748,24 @@ class RequestHandlerComponent extends Component { $this->_inputTypeMap[$type] = $handler; } +/** + * Getter/setter for viewClassMap + * + * @param array|string $type The type string or array with format `array('type' => 'viewClass')` to map one or more + * @param array $viewClass The viewClass to be used for the type without `View` appended + * @return array]string Returns viewClass when only string $type is set, else array with viewClassMap + */ + public function viewClassMap($type = null, $viewClass = null) { + if (!$viewClass && is_string($type) && isset($this->_viewClassMap[$type])) { + return $this->_viewClassMap[$type]; + } elseif (is_string($type)) { + $this->_viewClassMap[$type] = $viewClass; + } elseif (is_array($type)) { + foreach ($type as $key => $value) { + $this->viewClassMap($key, $value); + } + } + return $this->_viewClassMap; + } + } From 7ea1a590354617d13f31d644e09fbddf7e667271 Mon Sep 17 00:00:00 2001 From: Ceeram Date: Fri, 10 Aug 2012 10:29:55 +0200 Subject: [PATCH 075/256] adding test for viewClass mapping --- .../Component/RequestHandlerComponentTest.php | 41 ++++++++++++++++++- 1 file changed, 40 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php b/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php index 0840c64d3..197298448 100644 --- a/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php @@ -21,6 +21,7 @@ App::uses('RequestHandlerComponent', 'Controller/Component'); App::uses('CakeRequest', 'Network'); App::uses('CakeResponse', 'Network'); App::uses('Router', 'Routing'); +App::uses('JsonView', 'View'); /** * RequestHandlerTestController class @@ -70,6 +71,15 @@ class RequestHandlerTestController extends Controller { } +class CustomJsonView extends JsonView { + +/** + * Test method for viewClassMap and overriding _serialize() + */ + protected function _serialize($serialize) { + return json_encode(array('return' => 'ok')); + } +} /** * RequestHandlerComponentTest class @@ -137,12 +147,14 @@ class RequestHandlerComponentTest extends CakeTestCase { */ public function testConstructorSettings() { $settings = array( - 'ajaxLayout' => 'test_ajax' + 'ajaxLayout' => 'test_ajax', + 'viewClassMap' => array('json' => 'MyPlugin.MyJson') ); $Collection = new ComponentCollection(); $Collection->init($this->Controller); $RequestHandler = new RequestHandlerComponent($Collection, $settings); $this->assertEquals('test_ajax', $RequestHandler->ajaxLayout); + $this->assertEquals(array('json' => 'MyPlugin.MyJson'), $RequestHandler->settings['viewClassMap']); } /** @@ -264,6 +276,33 @@ class RequestHandlerComponentTest extends CakeTestCase { call_user_func_array(array('Router', 'parseExtensions'), $extensions); } +/** + * testViewClassMap method + * + * @return void + */ + public function testViewClassMap() { + $settings = array('viewClassMap' => array('json' => 'CustomJson')); + $this->RequestHandler->initialize($this->Controller, $settings); + $result = $this->RequestHandler->viewClassMap(); + $expected = array( + 'json' => 'CustomJson', + 'xml' => 'Xml' + ); + $this->assertEquals($expected, $result); + + $result = $this->RequestHandler->viewClassMap('xls', 'Excel.Excel'); + $expected = array( + 'json' => 'CustomJson', + 'xml' => 'Xml', + 'xls' => 'Excel.Excel' + ); + $this->assertEquals($expected, $result); + + $this->RequestHandler->renderAs($this->Controller, 'json'); + $this->assertEquals('CustomJson', $this->Controller->viewClass); + } + /** * testDisabling method * From ab7dd99e436d5ce78b5857f7149dc5f030d5b341 Mon Sep 17 00:00:00 2001 From: Ceeram Date: Fri, 10 Aug 2012 11:05:19 +0200 Subject: [PATCH 076/256] add missing docblock, remove unneeded code --- .../Component/RequestHandlerComponentTest.php | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php b/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php index 197298448..baa0c946b 100644 --- a/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php @@ -71,15 +71,12 @@ class RequestHandlerTestController extends Controller { } -class CustomJsonView extends JsonView { - /** - * Test method for viewClassMap and overriding _serialize() + * CustomJsonView class + * + * @package Cake.Test.Case.Controller.Component */ - protected function _serialize($serialize) { - return json_encode(array('return' => 'ok')); - } -} +class CustomJsonView extends JsonView {} /** * RequestHandlerComponentTest class From 0bbf61ce3db3d7f0657083f6530426c269aa4c10 Mon Sep 17 00:00:00 2001 From: mark_story Date: Fri, 10 Aug 2012 21:48:22 -0400 Subject: [PATCH 077/256] Add removed getDataSource() call. This fixes an issue where the wrong datasource could potentially be used for getting the full table name. --- lib/Cake/Model/CakeSchema.php | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/Cake/Model/CakeSchema.php b/lib/Cake/Model/CakeSchema.php index 0d15d9ae7..75339e608 100644 --- a/lib/Cake/Model/CakeSchema.php +++ b/lib/Cake/Model/CakeSchema.php @@ -257,6 +257,7 @@ class CakeSchema extends Object { if (!is_object($Object) || $Object->useTable === false) { continue; } + $db = $Object->getDataSource(); $fulltable = $table = $db->fullTableName($Object, false, false); if ($prefix && strpos($table, $prefix) !== 0) { From 11227f54903c52a43faabd16fe951e8db127d927 Mon Sep 17 00:00:00 2001 From: mark_story Date: Fri, 10 Aug 2012 21:50:37 -0400 Subject: [PATCH 078/256] Fix coding standards. --- lib/Cake/Test/Case/Console/Command/SchemaShellTest.php | 1 - .../Case/Controller/Component/RequestHandlerComponentTest.php | 4 +++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Test/Case/Console/Command/SchemaShellTest.php b/lib/Cake/Test/Case/Console/Command/SchemaShellTest.php index d47f55691..34441aa7a 100644 --- a/lib/Cake/Test/Case/Console/Command/SchemaShellTest.php +++ b/lib/Cake/Test/Case/Console/Command/SchemaShellTest.php @@ -396,7 +396,6 @@ class SchemaShellTest extends CakeTestCase { CakePlugin::unload(); } - /** * Test schema run create with no table args. * diff --git a/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php b/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php index baa0c946b..ff3f98965 100644 --- a/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php @@ -76,7 +76,9 @@ class RequestHandlerTestController extends Controller { * * @package Cake.Test.Case.Controller.Component */ -class CustomJsonView extends JsonView {} +class CustomJsonView extends JsonView { + +} /** * RequestHandlerComponentTest class From e1fbfcef005a1b876fe527dbf9c03703bfece269 Mon Sep 17 00:00:00 2001 From: euromark Date: Mon, 13 Aug 2012 08:10:51 +0200 Subject: [PATCH 079/256] fix contain for find method --- .../Model/Behavior/ContainableBehavior.php | 2 +- .../Behavior/ContainableBehaviorTest.php | 24 +++++++++++++++++++ 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Model/Behavior/ContainableBehavior.php b/lib/Cake/Model/Behavior/ContainableBehavior.php index e81df035c..98989b64a 100644 --- a/lib/Cake/Model/Behavior/ContainableBehavior.php +++ b/lib/Cake/Model/Behavior/ContainableBehavior.php @@ -171,7 +171,7 @@ class ContainableBehavior extends ModelBehavior { } if ($this->settings[$Model->alias]['recursive']) { - $query['recursive'] = (isset($query['recursive'])) ? $query['recursive'] : $containments['depth']; + $query['recursive'] = (isset($query['recursive'])) ? max($query['recursive'], $containments['depth']) : $containments['depth']; } $autoFields = ($this->settings[$Model->alias]['autoFields'] diff --git a/lib/Cake/Test/Case/Model/Behavior/ContainableBehaviorTest.php b/lib/Cake/Test/Case/Model/Behavior/ContainableBehaviorTest.php index 8345c87d6..aa8eee1f6 100644 --- a/lib/Cake/Test/Case/Model/Behavior/ContainableBehaviorTest.php +++ b/lib/Cake/Test/Case/Model/Behavior/ContainableBehaviorTest.php @@ -261,6 +261,30 @@ class ContainableBehaviorTest extends CakeTestCase { $this->assertFalse(Set::matches('/Comment/User', $r)); } +/** + * testContainFindList method + * + * @return void + */ + public function testContainFindList() { + $this->Article->contain('Comment.User'); + $result = $this->Article->find('list'); + $expected = array( + 1 => 'First Article', + 2 => 'Second Article', + 3 => 'Third Article' + ); + $this->assertEquals($expected, $result); + + $result = $this->Article->find('list', array('fields'=>array('Article.id', 'User.id'), 'contain'=>array('User'))); + $expected = array( + 1 => '1', + 2 => '3', + 3 => '1' + ); + $this->assertEquals($expected, $result); + } + /** * testFindEmbeddedNoBindings method * From b0f2cfd1d1f1ed042b15019a83bc63c608784db1 Mon Sep 17 00:00:00 2001 From: mark_story Date: Wed, 15 Aug 2012 20:19:08 -0400 Subject: [PATCH 080/256] Fix coding standards. --- lib/Cake/Test/Case/Model/Behavior/ContainableBehaviorTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Test/Case/Model/Behavior/ContainableBehaviorTest.php b/lib/Cake/Test/Case/Model/Behavior/ContainableBehaviorTest.php index aa8eee1f6..0051e93a6 100644 --- a/lib/Cake/Test/Case/Model/Behavior/ContainableBehaviorTest.php +++ b/lib/Cake/Test/Case/Model/Behavior/ContainableBehaviorTest.php @@ -276,7 +276,7 @@ class ContainableBehaviorTest extends CakeTestCase { ); $this->assertEquals($expected, $result); - $result = $this->Article->find('list', array('fields'=>array('Article.id', 'User.id'), 'contain'=>array('User'))); + $result = $this->Article->find('list', array('fields' => array('Article.id', 'User.id'), 'contain' => array('User'))); $expected = array( 1 => '1', 2 => '3', From f201684873a6d9efec11c4b313669219d07f01a2 Mon Sep 17 00:00:00 2001 From: euromark Date: Fri, 17 Aug 2012 13:31:01 +0200 Subject: [PATCH 081/256] use html ellipsis if possible (only a single char and therefore does not line break or mess up the strlen count for length) --- lib/Cake/Test/Case/Utility/StringTest.php | 18 +++++++++--------- lib/Cake/Utility/String.php | 3 +++ 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/lib/Cake/Test/Case/Utility/StringTest.php b/lib/Cake/Test/Case/Utility/StringTest.php index 8f4abdd9b..ef2f15e35 100644 --- a/lib/Cake/Test/Case/Utility/StringTest.php +++ b/lib/Cake/Test/Case/Utility/StringTest.php @@ -380,17 +380,17 @@ TEXT; $this->assertSame($this->Text->truncate($text3, 20), '© 2005-20...'); $this->assertSame($this->Text->truncate($text4, 15), ' This image ...'); - $this->assertSame($this->Text->truncate($text4, 45, array('html' => true)), ' This image tag is not XHTML conform!

    But t...'); - $this->assertSame($this->Text->truncate($text4, 90, array('html' => true)), ' This image tag is not XHTML conform!

    But the following image tag should be conform Me, myself and I
    Grea...'); + $this->assertSame($this->Text->truncate($text1, 15, array('html' => true)), 'The quick brow' . chr(226)); + $this->assertSame($this->Text->truncate($text1, 15, array('exact' => false, 'html' => true)), 'The quick' . chr(226)); + $this->assertSame($this->Text->truncate($text2, 10, array('html' => true)), 'Heizölrüc' . chr(226)); + $this->assertSame($this->Text->truncate($text2, 10, array('exact' => false, 'html' => true)), chr(226)); + $this->assertSame($this->Text->truncate($text3, 20, array('html' => true)), '© 2005-2007, Cake S' . chr(226) . ''); + $this->assertSame($this->Text->truncate($text4, 15, array('html' => true)), ' This image ta' . chr(226)); + $this->assertSame($this->Text->truncate($text4, 45, array('html' => true)), ' This image tag is not XHTML conform!

    But the'. chr(226) .''); + $this->assertSame($this->Text->truncate($text4, 90, array('html' => true)), ' This image tag is not XHTML conform!

    But the following image tag should be conform Me, myself and I
    Great,' . chr(226)); $this->assertSame($this->Text->truncate($text5, 6, array('ellipsis' => '', 'html' => true)), '012345'); $this->assertSame($this->Text->truncate($text5, 20, array('ellipsis' => '', 'html' => true)), $text5); - $this->assertSame($this->Text->truncate($text6, 57, array('exact' => false, 'html' => true)), "

    Extra dates have been announced for this year's...

    "); + $this->assertSame($this->Text->truncate($text6, 57, array('exact' => false, 'html' => true)), "

    Extra dates have been announced for this year's". chr(226)."

    "); $this->assertSame($this->Text->truncate($text7, 255), $text7); $this->assertSame($this->Text->truncate($text7, 15), 'El moño está...'); $this->assertSame($this->Text->truncate($text8, 15), 'Vive la R' . chr(195) . chr(169) . 'pu...'); diff --git a/lib/Cake/Utility/String.php b/lib/Cake/Utility/String.php index 03bb761b4..4aa9f7966 100644 --- a/lib/Cake/Utility/String.php +++ b/lib/Cake/Utility/String.php @@ -480,6 +480,9 @@ class String { $default = array( 'ellipsis' => '...', 'exact' => true, 'html' => false ); + if (!empty($options['html'])) { + $default['ellipsis'] = chr(226); + } if (isset($options['ending'])) { $default['ellipsis'] = $options['ending']; } From 40398429ff2fd7e3e643e262f1a4006a8daf8a9a Mon Sep 17 00:00:00 2001 From: euromark Date: Fri, 17 Aug 2012 13:37:04 +0200 Subject: [PATCH 082/256] coding standards --- lib/Cake/Test/Case/Utility/StringTest.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Test/Case/Utility/StringTest.php b/lib/Cake/Test/Case/Utility/StringTest.php index ef2f15e35..bde04f849 100644 --- a/lib/Cake/Test/Case/Utility/StringTest.php +++ b/lib/Cake/Test/Case/Utility/StringTest.php @@ -386,11 +386,11 @@ TEXT; $this->assertSame($this->Text->truncate($text2, 10, array('exact' => false, 'html' => true)), chr(226)); $this->assertSame($this->Text->truncate($text3, 20, array('html' => true)), '© 2005-2007, Cake S' . chr(226) . ''); $this->assertSame($this->Text->truncate($text4, 15, array('html' => true)), ' This image ta' . chr(226)); - $this->assertSame($this->Text->truncate($text4, 45, array('html' => true)), ' This image tag is not XHTML conform!

    But the'. chr(226) .''); + $this->assertSame($this->Text->truncate($text4, 45, array('html' => true)), ' This image tag is not XHTML conform!

    But the' . chr(226) . ''); $this->assertSame($this->Text->truncate($text4, 90, array('html' => true)), ' This image tag is not XHTML conform!

    But the following image tag should be conform Me, myself and I
    Great,' . chr(226)); $this->assertSame($this->Text->truncate($text5, 6, array('ellipsis' => '', 'html' => true)), '012345'); $this->assertSame($this->Text->truncate($text5, 20, array('ellipsis' => '', 'html' => true)), $text5); - $this->assertSame($this->Text->truncate($text6, 57, array('exact' => false, 'html' => true)), "

    Extra dates have been announced for this year's". chr(226)."

    "); + $this->assertSame($this->Text->truncate($text6, 57, array('exact' => false, 'html' => true)), "

    Extra dates have been announced for this year's" . chr(226) . "

    "); $this->assertSame($this->Text->truncate($text7, 255), $text7); $this->assertSame($this->Text->truncate($text7, 15), 'El moño está...'); $this->assertSame($this->Text->truncate($text8, 15), 'Vive la R' . chr(195) . chr(169) . 'pu...'); From 79690626141b9ccb7fd05f4440b76f133e4869a8 Mon Sep 17 00:00:00 2001 From: euromark Date: Fri, 17 Aug 2012 13:57:47 +0200 Subject: [PATCH 083/256] legacy support with test cases --- lib/Cake/Test/Case/Utility/StringTest.php | 21 +++++++++++++++++++++ lib/Cake/Utility/String.php | 5 ++--- 2 files changed, 23 insertions(+), 3 deletions(-) diff --git a/lib/Cake/Test/Case/Utility/StringTest.php b/lib/Cake/Test/Case/Utility/StringTest.php index bde04f849..f13fe25eb 100644 --- a/lib/Cake/Test/Case/Utility/StringTest.php +++ b/lib/Cake/Test/Case/Utility/StringTest.php @@ -459,6 +459,27 @@ podeís adquirirla.

    $this->assertEquals($expected, $result); } +/** + * testTruncate method with non utf8 sites + * + * @return void + */ + public function testTruncateLegacy() { + Configure::write('App.encoding', 'ISO-8859-1'); + $text = '© 2005-2007, Cake Software Foundation, Inc.
    written by Alexander Wegener'; + $result = $this->Text->truncate($text, 31, array( + 'exact' => false, + )); + $expected = '© 2005-2007, Cake...'; + $this->assertEquals($expected, $result); + + $result = $this->Text->truncate($text, 31, array( + 'exact' => true, + )); + $expected = '© 2005-2007, Cake So...'; + $this->assertEquals($expected, $result); + } + /** * testTail method * diff --git a/lib/Cake/Utility/String.php b/lib/Cake/Utility/String.php index 4aa9f7966..d3c6b0868 100644 --- a/lib/Cake/Utility/String.php +++ b/lib/Cake/Utility/String.php @@ -480,11 +480,10 @@ class String { $default = array( 'ellipsis' => '...', 'exact' => true, 'html' => false ); - if (!empty($options['html'])) { - $default['ellipsis'] = chr(226); - } if (isset($options['ending'])) { $default['ellipsis'] = $options['ending']; + } elseif (!empty($options['html']) && Configure::read('App.encoding') == 'UTF-8') { + $default['ellipsis'] = chr(226); } $options = array_merge($default, $options); extract($options); From 07d92ef678f3aad210ba31a8784f1e2050047808 Mon Sep 17 00:00:00 2001 From: euromark Date: Fri, 17 Aug 2012 14:02:20 +0200 Subject: [PATCH 084/256] correcting test --- lib/Cake/Test/Case/Utility/StringTest.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Test/Case/Utility/StringTest.php b/lib/Cake/Test/Case/Utility/StringTest.php index f13fe25eb..062005ec1 100644 --- a/lib/Cake/Test/Case/Utility/StringTest.php +++ b/lib/Cake/Test/Case/Utility/StringTest.php @@ -468,15 +468,17 @@ podeís adquirirla.

    Configure::write('App.encoding', 'ISO-8859-1'); $text = '© 2005-2007, Cake Software Foundation, Inc.
    written by Alexander Wegener'; $result = $this->Text->truncate($text, 31, array( + 'html' => true, 'exact' => false, )); - $expected = '© 2005-2007, Cake...'; + $expected = '© 2005-2007, Cake Software...'; $this->assertEquals($expected, $result); $result = $this->Text->truncate($text, 31, array( + 'html' => true, 'exact' => true, )); - $expected = '© 2005-2007, Cake So...'; + $expected = '© 2005-2007, Cake Software F...'; $this->assertEquals($expected, $result); } From 62dd39133b5c2fab30977f2e509e7bbfb7287984 Mon Sep 17 00:00:00 2001 From: mark_story Date: Mon, 20 Aug 2012 16:21:59 -0400 Subject: [PATCH 085/256] Fix lint errors + comment content. --- lib/Cake/Console/Command/Task/TestTask.php | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/lib/Cake/Console/Command/Task/TestTask.php b/lib/Cake/Console/Command/Task/TestTask.php index edee2d21b..73b29f6aa 100644 --- a/lib/Cake/Console/Command/Task/TestTask.php +++ b/lib/Cake/Console/Command/Task/TestTask.php @@ -331,13 +331,14 @@ class TestTask extends BakeTask { /** * Get the base class and package name for a given type. * - * @param string $package The package the class having a test - * generated for is in. + * @param string $type The type of class having a test + * generated is in. * @return array Array of class, type) + * @throws CakeException on invalid types. */ public function getBaseType($type) { if (empty($this->baseTypes[$type])) { - throw new CakeException(__d('cake_dev', 'Invalid package name')); + throw new CakeException(__d('cake_dev', 'Invalid type name')); } return $this->baseTypes[$type]; } From e7dc23b920ac1b1b4825d57538a12c395939ba20 Mon Sep 17 00:00:00 2001 From: Ceeram Date: Wed, 22 Aug 2012 13:13:49 +0200 Subject: [PATCH 086/256] Ensure callbacks are triggered when using Xml/Json view with view templates. PaginatorHelper for instance needs this to correctly set options --- lib/Cake/Test/Case/View/JsonViewTest.php | 4 +++- lib/Cake/Test/test_app/View/Posts/json/index.ctp | 5 ++++- lib/Cake/View/JsonView.php | 7 +------ lib/Cake/View/XmlView.php | 7 +------ 4 files changed, 9 insertions(+), 14 deletions(-) diff --git a/lib/Cake/Test/Case/View/JsonViewTest.php b/lib/Cake/Test/Case/View/JsonViewTest.php index 39a3e7a1d..ed2b04e4e 100644 --- a/lib/Cake/Test/Case/View/JsonViewTest.php +++ b/lib/Cake/Test/Case/View/JsonViewTest.php @@ -76,6 +76,7 @@ class JsonViewTest extends CakeTestCase { 'View' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'View' . DS) )); $Request = new CakeRequest(); + $Request->params['named'] = array('page' => 2); $Response = new CakeResponse(); $Controller = new Controller($Request, $Response); $Controller->name = $Controller->viewPath = 'Posts'; @@ -91,9 +92,10 @@ class JsonViewTest extends CakeTestCase { ); $Controller->set('user', $data); $View = new JsonView($Controller); + $View->helpers = array('Paginator'); $output = $View->render('index'); - $expected = json_encode(array('user' => 'fake', 'list' => array('item1', 'item2'))); + $expected = json_encode(array('user' => 'fake', 'list' => array('item1', 'item2'), 'paging' => array('page' => 2))); $this->assertSame($expected, $output); $this->assertSame('application/json', $Response->type()); } diff --git a/lib/Cake/Test/test_app/View/Posts/json/index.ctp b/lib/Cake/Test/test_app/View/Posts/json/index.ctp index 433162d58..f2d423459 100644 --- a/lib/Cake/Test/test_app/View/Posts/json/index.ctp +++ b/lib/Cake/Test/test_app/View/Posts/json/index.ctp @@ -16,9 +16,12 @@ * @license MIT License (http://www.opensource.org/licenses/mit-license.php) */ +$paging = isset($this->Paginator->options['url']) ? $this->Paginator->options['url'] : null; + $formatted = array( 'user' => $user['User']['username'], - 'list' => array() + 'list' => array(), + 'paging' => $paging, ); foreach ($user['Item'] as $item) { $formatted['list'][] = $item['name']; diff --git a/lib/Cake/View/JsonView.php b/lib/Cake/View/JsonView.php index 188c29d1e..f88cc678a 100644 --- a/lib/Cake/View/JsonView.php +++ b/lib/Cake/View/JsonView.php @@ -85,12 +85,7 @@ class JsonView extends View { return $this->_serialize($this->viewVars['_serialize']); } if ($view !== false && $viewFileName = $this->_getViewFileName($view)) { - if (!$this->_helpersLoaded) { - $this->loadHelpers(); - } - $content = $this->_render($viewFileName); - $this->Blocks->set('content', $content); - return $content; + return parent::render($view, false); } } diff --git a/lib/Cake/View/XmlView.php b/lib/Cake/View/XmlView.php index 9b81066ba..7e757b54c 100644 --- a/lib/Cake/View/XmlView.php +++ b/lib/Cake/View/XmlView.php @@ -88,12 +88,7 @@ class XmlView extends View { return $this->_serialize($this->viewVars['_serialize']); } if ($view !== false && $viewFileName = $this->_getViewFileName($view)) { - if (!$this->_helpersLoaded) { - $this->loadHelpers(); - } - $content = $this->_render($viewFileName); - $this->Blocks->set('content', (string)$content); - return $content; + return parent::render($view, false); } } From d730acba59156884f7a04428dbe3ce956ea7d337 Mon Sep 17 00:00:00 2001 From: Ceeram Date: Thu, 9 Aug 2012 16:11:32 +0200 Subject: [PATCH 087/256] Add onlyAllow() to CakeRequest, to check if the request method matches the allowed ones. Throws exception if not matched, using the required Allow response header. --- lib/Cake/Network/CakeRequest.php | 32 +++++++++++++++++ .../Test/Case/Network/CakeRequestTest.php | 34 +++++++++++++++++++ 2 files changed, 66 insertions(+) diff --git a/lib/Cake/Network/CakeRequest.php b/lib/Cake/Network/CakeRequest.php index cadbbbd0c..32d7c9744 100644 --- a/lib/Cake/Network/CakeRequest.php +++ b/lib/Cake/Network/CakeRequest.php @@ -803,6 +803,38 @@ class CakeRequest implements ArrayAccess { return $input; } +/** + * Only allow certain HTTP request methods, if the request method does not match + * a 405 error will be shown and the required "Allow" response header will be set. + * + * Example: + * + * $this->request->onlyAllow('post', 'delete'); + * or + * $this->request->onlyAllow(array('post', 'delete')); + * + * If the request would be GET, response header "Allow: POST, DELETE" will be set + * and a 405 error will be returned + * + * @param string|array $methods Allowed HTTP request methods + * @return boolean true + * @throws MethodNotAllowedException + */ + public function onlyAllow($methods) { + if (!is_array($methods)) { + $methods = func_get_args(); + } + foreach ($methods as $method) { + if ($this->is($method)) { + return true; + } + } + $allowed = strtoupper(implode(', ', $methods)); + $e = new MethodNotAllowedException(); + $e->responseHeader('Allow', $allowed); + throw $e; + } + /** * Read data from php://input, mocked in tests. * diff --git a/lib/Cake/Test/Case/Network/CakeRequestTest.php b/lib/Cake/Test/Case/Network/CakeRequestTest.php index 8ef0e1868..7853a048d 100644 --- a/lib/Cake/Test/Case/Network/CakeRequestTest.php +++ b/lib/Cake/Test/Case/Network/CakeRequestTest.php @@ -1857,6 +1857,40 @@ XML; $this->assertFalse($request->isRequested()); } +/** + * TestOnlyAllow + * + * @return void + */ + public function testOnlyAllow() { + $_SERVER['REQUEST_METHOD'] = 'PUT'; + $request = new CakeRequest('/posts/edit/1'); + + $this->assertTrue($request->onlyAllow(array('put'))); + + $_SERVER['REQUEST_METHOD'] = 'DELETE'; + $this->assertTrue($request->onlyAllow('post', 'delete')); + } + +/** + * TestOnlyAllow throwing exception + * + */ + public function testOnlyAllowException() { + $_SERVER['REQUEST_METHOD'] = 'PUT'; + $request = new CakeRequest('/posts/edit/1'); + + try { + $request->onlyAllow('POST', 'DELETE'); + $this->fail('An expected exception has not been raised.'); + } catch (MethodNotAllowedException $e) { + $this->assertEquals(array('Allow' => 'POST, DELETE'), $e->responseHeader()); + } + + $this->setExpectedException('MethodNotAllowedException'); + $request->onlyAllow('POST'); + } + /** * loadEnvironment method * From d24bbcb2550aadadb6e7b2d333d559dc0bc84da5 Mon Sep 17 00:00:00 2001 From: Heath Nail Date: Wed, 15 Aug 2012 13:49:31 -0400 Subject: [PATCH 088/256] Add BlowfishAuthenticate adapter. --- .../Component/Auth/BaseAuthenticate.php | 30 ++- .../Component/Auth/BlowfishAuthenticate.php | 75 +++++++ .../Component/Auth/FormAuthenticate.php | 29 ++- .../Auth/BlowfishAuthenticateTest.php | 206 ++++++++++++++++++ .../Component/Auth/FormAuthenticateTest.php | 15 ++ 5 files changed, 340 insertions(+), 15 deletions(-) create mode 100644 lib/Cake/Controller/Component/Auth/BlowfishAuthenticate.php create mode 100644 lib/Cake/Test/Case/Controller/Component/Auth/BlowfishAuthenticateTest.php diff --git a/lib/Cake/Controller/Component/Auth/BaseAuthenticate.php b/lib/Cake/Controller/Component/Auth/BaseAuthenticate.php index d9dc7248f..827774db2 100644 --- a/lib/Cake/Controller/Component/Auth/BaseAuthenticate.php +++ b/lib/Cake/Controller/Component/Auth/BaseAuthenticate.php @@ -66,19 +66,28 @@ abstract class BaseAuthenticate { /** * Find a user record using the standard options. * - * @param string $username The username/identifier. - * @param string $password The unhashed password. + * The $conditions parameter can be a (string)username or an array containing conditions for Model::find('first'). If + * the password field is not included in the conditions the password will be returned. + * + * @param Mixed $conditions The username/identifier, or an array of find conditions. + * @param Mixed $password The password, only use if passing as $conditions = 'username'. * @return Mixed Either false on failure, or an array of user data. */ - protected function _findUser($username, $password) { + protected function _findUser($conditions, $password = null) { $userModel = $this->settings['userModel']; list($plugin, $model) = pluginSplit($userModel); $fields = $this->settings['fields']; - $conditions = array( - $model . '.' . $fields['username'] => $username, - $model . '.' . $fields['password'] => $this->_password($password), - ); + if (!is_array($conditions)) { + if (!$password) { + return false; + } + $username = $conditions; + $conditions = array( + $model . '.' . $fields['username'] => $username, + $model . '.' . $fields['password'] => $this->_password($password), + ); + } if (!empty($this->settings['scope'])) { $conditions = array_merge($conditions, $this->settings['scope']); } @@ -91,7 +100,12 @@ abstract class BaseAuthenticate { return false; } $user = $result[$model]; - unset($user[$fields['password']]); + if ( + isset($conditions[$model . '.' . $fields['password']]) || + isset($conditions[$fields['password']]) + ) { + unset($user[$fields['password']]); + } unset($result[$model]); return array_merge($user, $result); } diff --git a/lib/Cake/Controller/Component/Auth/BlowfishAuthenticate.php b/lib/Cake/Controller/Component/Auth/BlowfishAuthenticate.php new file mode 100644 index 000000000..d806c6ff6 --- /dev/null +++ b/lib/Cake/Controller/Component/Auth/BlowfishAuthenticate.php @@ -0,0 +1,75 @@ +Auth->authenticate = array( + * 'Blowfish' => array( + * 'scope' => array('User.active' => 1) + * ) + * ) + * }}} + * + * When configuring BlowfishAuthenticate you can pass in settings to which fields, model and additional conditions + * are used. See BlowfishAuthenticate::$settings for more information. + * + * @package Cake.Controller.Component.Auth + * @since CakePHP(tm) v 2.3 + * @see AuthComponent::$authenticate + */ +class BlowfishAuthenticate extends FormAuthenticate { + +/** + * Authenticates the identity contained in a request. Will use the `settings.userModel`, and `settings.fields` + * to find POST data that is used to find a matching record in the`settings.userModel`. Will return false if + * there is no post data, either username or password is missing, or if the scope conditions have not been met. + * + * @param CakeRequest $request The request that contains login information. + * @param CakeResponse $response Unused response object. + * @return mixed False on login failure. An array of User data on success. + */ + public function authenticate(CakeRequest $request, CakeResponse $response) { + $userModel = $this->settings['userModel']; + list($plugin, $model) = pluginSplit($userModel); + + $fields = $this->settings['fields']; + if (!$this->_checkFields($request, $model, $fields)) { + return false; + } + $user = $this->_findUser( + array( + $model . '.' . $fields['username'] => $request->data[$model][$fields['username']], + ) + ); + if (!$user) { + return false; + } + $password = Security::hash( + $request->data[$model][$fields['password']], + 'blowfish', + $user[$fields['password']] + ); + if ($password === $user[$fields['password']]) { + unset($user[$fields['password']]); + return $user; + } + return false; + } +} diff --git a/lib/Cake/Controller/Component/Auth/FormAuthenticate.php b/lib/Cake/Controller/Component/Auth/FormAuthenticate.php index 0a51f527e..c6bc5a8bf 100644 --- a/lib/Cake/Controller/Component/Auth/FormAuthenticate.php +++ b/lib/Cake/Controller/Component/Auth/FormAuthenticate.php @@ -36,6 +36,27 @@ App::uses('BaseAuthenticate', 'Controller/Component/Auth'); */ class FormAuthenticate extends BaseAuthenticate { +/** + * Checks the fields to ensure they are supplied. + * + * @param CakeRequest $request The request that contains login information. + * @param string $model The model used for login verification. + * @param array $fields The fields to be checked. + * @return boolean False if the fields have not been supplied. True if they exist. + */ + protected function _checkFields(CakeRequest $request, $model, $fields) { + if (empty($request->data[$model])) { + return false; + } + if ( + empty($request->data[$model][$fields['username']]) || + empty($request->data[$model][$fields['password']]) + ) { + return false; + } + return true; + } + /** * Authenticates the identity contained in a request. Will use the `settings.userModel`, and `settings.fields` * to find POST data that is used to find a matching record in the `settings.userModel`. Will return false if @@ -50,13 +71,7 @@ class FormAuthenticate extends BaseAuthenticate { list($plugin, $model) = pluginSplit($userModel); $fields = $this->settings['fields']; - if (empty($request->data[$model])) { - return false; - } - if ( - empty($request->data[$model][$fields['username']]) || - empty($request->data[$model][$fields['password']]) - ) { + if (!$this->_checkFields($request, $model, $fields)) { return false; } return $this->_findUser( diff --git a/lib/Cake/Test/Case/Controller/Component/Auth/BlowfishAuthenticateTest.php b/lib/Cake/Test/Case/Controller/Component/Auth/BlowfishAuthenticateTest.php new file mode 100644 index 000000000..59238199e --- /dev/null +++ b/lib/Cake/Test/Case/Controller/Component/Auth/BlowfishAuthenticateTest.php @@ -0,0 +1,206 @@ +Collection = $this->getMock('ComponentCollection'); + $this->auth = new BlowfishAuthenticate($this->Collection, array( + 'fields' => array('username' => 'user', 'password' => 'password'), + 'userModel' => 'User' + )); + $password = Security::hash('password', 'blowfish'); + $User = ClassRegistry::init('User'); + $User->updateAll(array('password' => $User->getDataSource()->value($password))); + $this->response = $this->getMock('CakeResponse'); + } + +/** + * test applying settings in the constructor + * + * @return void + */ + public function testConstructor() { + $Object = new BlowfishAuthenticate($this->Collection, array( + 'userModel' => 'AuthUser', + 'fields' => array('username' => 'user', 'password' => 'password') + )); + $this->assertEquals('AuthUser', $Object->settings['userModel']); + $this->assertEquals(array('username' => 'user', 'password' => 'password'), $Object->settings['fields']); + } + +/** + * testAuthenticateNoData method + * + * @return void + */ + public function testAuthenticateNoData() { + $request = new CakeRequest('posts/index', false); + $request->data = array(); + $this->assertFalse($this->auth->authenticate($request, $this->response)); + } + +/** + * testAuthenticateNoUsername method + * + * @return void + */ + public function testAuthenticateNoUsername() { + $request = new CakeRequest('posts/index', false); + $request->data = array('User' => array('password' => 'foobar')); + $this->assertFalse($this->auth->authenticate($request, $this->response)); + } + +/** + * testAuthenticateNoPassword method + * + * @return void + */ + public function testAuthenticateNoPassword() { + $request = new CakeRequest('posts/index', false); + $request->data = array('User' => array('user' => 'mariano')); + $this->assertFalse($this->auth->authenticate($request, $this->response)); + } + +/** + * testAuthenticatePasswordIsFalse method + * + * @return void + */ + public function testAuthenticatePasswordIsFalse() { + $request = new CakeRequest('posts/index', false); + $request->data = array( + 'User' => array( + 'user' => 'mariano', + 'password' => null + )); + $this->assertFalse($this->auth->authenticate($request, $this->response)); + } + +/** + * testAuthenticateInjection method + * + * @return void + */ + public function testAuthenticateInjection() { + $request = new CakeRequest('posts/index', false); + $request->data = array('User' => array( + 'user' => '> 1', + 'password' => "' OR 1 = 1" + )); + $this->assertFalse($this->auth->authenticate($request, $this->response)); + } + +/** + * testAuthenticateSuccess method + * + * @return void + */ + public function testAuthenticateSuccess() { + $request = new CakeRequest('posts/index', false); + $request->data = array('User' => array( + 'user' => 'mariano', + 'password' => 'password' + )); + $result = $this->auth->authenticate($request, $this->response); + $expected = array( + 'id' => 1, + 'user' => 'mariano', + 'created' => '2007-03-17 01:16:23', + 'updated' => '2007-03-17 01:18:31', + ); + $this->assertEquals($expected, $result); + } + +/** + * testAuthenticateScopeFail method + * + * @return void + */ + public function testAuthenticateScopeFail() { + $this->auth->settings['scope'] = array('user' => 'nate'); + $request = new CakeRequest('posts/index', false); + $request->data = array('User' => array( + 'user' => 'mariano', + 'password' => 'password' + )); + $this->assertFalse($this->auth->authenticate($request, $this->response)); + } + +/** + * testPluginModel method + * + * @return void + */ + public function testPluginModel() { + Cache::delete('object_map', '_cake_core_'); + App::build(array( + 'Plugin' => array(CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS) + ), App::RESET); + CakePlugin::load('TestPlugin'); + + $PluginModel = ClassRegistry::init('TestPlugin.TestPluginAuthUser'); + $user['id'] = 1; + $user['username'] = 'gwoo'; + $user['password'] = Security::hash('password', 'blowfish'); + $PluginModel->save($user, false); + + $this->auth->settings['userModel'] = 'TestPlugin.TestPluginAuthUser'; + $this->auth->settings['fields']['username'] = 'username'; + + $request = new CakeRequest('posts/index', false); + $request->data = array('TestPluginAuthUser' => array( + 'username' => 'gwoo', + 'password' => 'password' + )); + + $result = $this->auth->authenticate($request, $this->response); + $expected = array( + 'id' => 1, + 'username' => 'gwoo', + 'created' => '2007-03-17 01:16:23' + ); + $this->assertEquals(self::date(), $result['updated']); + unset($result['updated']); + $this->assertEquals($expected, $result); + CakePlugin::unload(); + } +} diff --git a/lib/Cake/Test/Case/Controller/Component/Auth/FormAuthenticateTest.php b/lib/Cake/Test/Case/Controller/Component/Auth/FormAuthenticateTest.php index a65e04f28..4d2470a3b 100644 --- a/lib/Cake/Test/Case/Controller/Component/Auth/FormAuthenticateTest.php +++ b/lib/Cake/Test/Case/Controller/Component/Auth/FormAuthenticateTest.php @@ -99,6 +99,21 @@ class FormAuthenticateTest extends CakeTestCase { $this->assertFalse($this->auth->authenticate($request, $this->response)); } +/** + * test authenticate password is false method + * + * @return void + */ + public function testAuthenticatePasswordIsFalse() { + $request = new CakeRequest('posts/index', false); + $request->data = array( + 'User' => array( + 'user' => 'mariano', + 'password' => null + )); + $this->assertFalse($this->auth->authenticate($request, $this->response)); + } + /** * test the authenticate method * From 24b68ec1db681fb371279c2a6313a9621f4832db Mon Sep 17 00:00:00 2001 From: mark_story Date: Fri, 24 Aug 2012 09:35:33 -0400 Subject: [PATCH 089/256] Ensure = is removed from generated salt values. --- lib/Cake/Utility/Security.php | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Utility/Security.php b/lib/Cake/Utility/Security.php index 7f84c9687..339c88338 100644 --- a/lib/Cake/Utility/Security.php +++ b/lib/Cake/Utility/Security.php @@ -222,7 +222,12 @@ class Security { * @return string The generated salt */ public static function salt($length = 22) { - return substr(str_replace('+', '.', base64_encode(sha1(uniqid(Configure::read('Security.salt'), true), true))), 0, $length); + $salt = str_replace( + array('+', '='), + '.', + base64_encode(sha1(uniqid(Configure::read('Security.salt'), true), true)) + ); + return substr($salt, 0, $length); } /** From f3ba2bdb7d86c0f3809b342ffaf3bd54de8c3471 Mon Sep 17 00:00:00 2001 From: Thom Seddon Date: Fri, 24 Aug 2012 19:30:25 +0100 Subject: [PATCH 090/256] Remove legacy test for all actions allowed (*) in startup and tidy code --- lib/Cake/Controller/Component/AuthComponent.php | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/lib/Cake/Controller/Component/AuthComponent.php b/lib/Cake/Controller/Component/AuthComponent.php index c0869571f..e9e01b611 100644 --- a/lib/Cake/Controller/Component/AuthComponent.php +++ b/lib/Cake/Controller/Component/AuthComponent.php @@ -289,13 +289,7 @@ class AuthComponent extends Component { $url = Router::normalize($url); $loginAction = Router::normalize($this->loginAction); - $allowedActions = $this->allowedActions; - $isAllowed = ( - $this->allowedActions == array('*') || - in_array($action, array_map('strtolower', $allowedActions)) - ); - - if ($loginAction != $url && $isAllowed) { + if ($loginAction != $url && in_array($action, array_map('strtolower', $this->allowedActions))) { return true; } From 8e818c89b69799680ca2a11e5d619ef1641b3b6d Mon Sep 17 00:00:00 2001 From: Tigran Gabrielyan Date: Sun, 22 Jan 2012 16:54:34 -0800 Subject: [PATCH 091/256] Added `$prefix` generation in `core.php` for `cake bake` shell --- lib/Cake/Console/Command/Task/ProjectTask.php | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/lib/Cake/Console/Command/Task/ProjectTask.php b/lib/Cake/Console/Command/Task/ProjectTask.php index ebfe4e94e..b86c1b794 100644 --- a/lib/Cake/Console/Command/Task/ProjectTask.php +++ b/lib/Cake/Console/Command/Task/ProjectTask.php @@ -92,6 +92,13 @@ class ProjectTask extends AppShell { $success = false; } + if ($this->cachePrefix($path)) { + $this->out(__d('cake_console', ' * Cache prefix set')); + } else { + $this->err(__d('cake_console', 'The cache prefix was NOT set')); + $success = false; + } + if ($this->consolePath($path) === true) { $this->out(__d('cake_console', ' * app/Console/cake.php path set.')); } else { @@ -284,6 +291,26 @@ class ProjectTask extends AppShell { return false; } +/** + * Writes cache prefix using app's name + * + * @param string $dir Path to project + * @return boolean Success + */ + public function cachePrefix($dir) { + $app = basename($dir); + $File = new File($dir . 'Config' . DS . 'core.php'); + $contents = $File->read(); + if (preg_match('/(\$prefix = \'myapp_\';)/', $contents, $match)) { + $result = str_replace($match[0], '$prefix = \'' . $app . '_\';', $contents); + if ($File->write($result)) { + return true; + } + return false; + } + return false; + } + /** * Generates and writes CAKE_CORE_INCLUDE_PATH * From 0441c9f6c3899d7a4bc034038de41cf7cf0e99b2 Mon Sep 17 00:00:00 2001 From: Tigran Gabrielyan Date: Sun, 22 Jan 2012 17:23:42 -0800 Subject: [PATCH 092/256] Added tests for bake shell cache prefix generation --- .../Console/Command/Task/ProjectTaskTest.php | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/lib/Cake/Test/Case/Console/Command/Task/ProjectTaskTest.php b/lib/Cake/Test/Case/Console/Command/Task/ProjectTaskTest.php index 8fd1b33f0..b9fbe469b 100644 --- a/lib/Cake/Test/Case/Console/Command/Task/ProjectTaskTest.php +++ b/lib/Cake/Test/Case/Console/Command/Task/ProjectTaskTest.php @@ -249,6 +249,24 @@ class ProjectTaskTest extends CakeTestCase { $this->assertNotRegExp('/76859309657453542496749683645/', $contents, 'Default CipherSeed left behind. %s'); } +/** + * test generation of cache prefix + * + * @return void + */ + public function testCachePrefixGeneration() { + $this->_setupTestProject(); + + $path = $this->Task->path . 'bake_test_app' . DS; + $result = $this->Task->cachePrefix($path); + $this->assertTrue($result); + + $File = new File($path . 'Config' . DS . 'core.php'); + $contents = $File->read(); + $this->assertRegExp('/\$prefix = \'.+\';/', $contents, '$prefix is not defined'); + $this->assertNotRegExp('/\$prefix = \'myapp_\';/', $contents, 'Default cache prefix left behind. %s'); + } + /** * Test that index.php is generated correctly. * From 17ba71365159124383bdd18654ee3add261bc419 Mon Sep 17 00:00:00 2001 From: mark_story Date: Fri, 24 Aug 2012 22:48:45 -0400 Subject: [PATCH 093/256] Simplify code. --- lib/Cake/Console/Command/Task/ProjectTask.php | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/lib/Cake/Console/Command/Task/ProjectTask.php b/lib/Cake/Console/Command/Task/ProjectTask.php index b86c1b794..77afa983b 100644 --- a/lib/Cake/Console/Command/Task/ProjectTask.php +++ b/lib/Cake/Console/Command/Task/ProjectTask.php @@ -303,10 +303,7 @@ class ProjectTask extends AppShell { $contents = $File->read(); if (preg_match('/(\$prefix = \'myapp_\';)/', $contents, $match)) { $result = str_replace($match[0], '$prefix = \'' . $app . '_\';', $contents); - if ($File->write($result)) { - return true; - } - return false; + return $File->write($result); } return false; } From 27d83eedfe4b3a3e6bb93a3336f0c3d82ea2255a Mon Sep 17 00:00:00 2001 From: Ceeram Date: Sat, 25 Aug 2012 01:39:19 +0200 Subject: [PATCH 094/256] use new onlyAllow() method in baked code, to ensure 405 responses have required Allow header included --- .../Templates/default/actions/controller_actions.ctp | 12 +++++++----- .../Case/Console/Command/Task/ControllerTaskTest.php | 6 ++++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/Cake/Console/Templates/default/actions/controller_actions.ctp b/lib/Cake/Console/Templates/default/actions/controller_actions.ctp index e34c382d5..f30696796 100644 --- a/lib/Cake/Console/Templates/default/actions/controller_actions.ctp +++ b/lib/Cake/Console/Templates/default/actions/controller_actions.ctp @@ -47,10 +47,12 @@ /** * add method * + * @throws MethodNotAllowedException * @return void */ public function add() { - if ($this->request->is('post')) { + if ($this->request->data) { + $this->request->onlyAllow('post'); $this->->create(); if ($this->->save($this->request->data)) { @@ -86,6 +88,7 @@ /** * edit method * + * @throws MethodNotAllowedException * @throws NotFoundException * @param string $id * @return void @@ -95,7 +98,8 @@ if (!$this->->exists()) { throw new NotFoundException(__('Invalid ')); } - if ($this->request->is('post') || $this->request->is('put')) { + if ($this->request->data) { + $this->request->onlyAllow('post', 'put'); if ($this->->save($this->request->data)) { $this->Session->setFlash(__('The has been saved')); @@ -137,9 +141,7 @@ * @return void */ public function delete($id = null) { - if (!$this->request->is('post')) { - throw new MethodNotAllowedException(); - } + $this->request->onlyAllow('post', 'delete'); $this->->id = $id; if (!$this->->exists()) { throw new NotFoundException(__('Invalid ')); diff --git a/lib/Cake/Test/Case/Console/Command/Task/ControllerTaskTest.php b/lib/Cake/Test/Case/Console/Command/Task/ControllerTaskTest.php index a17d2bb9d..dd64f6252 100644 --- a/lib/Cake/Test/Case/Console/Command/Task/ControllerTaskTest.php +++ b/lib/Cake/Test/Case/Console/Command/Task/ControllerTaskTest.php @@ -353,7 +353,8 @@ class ControllerTaskTest extends CakeTestCase { $this->assertContains("\$this->set('bakeArticle', \$this->BakeArticle->read(null, \$id)", $result); $this->assertContains('function add()', $result); - $this->assertContains("if (\$this->request->is('post'))", $result); + $this->assertContains("if (\$this->request->data)", $result); + $this->assertContains("\$this->request->onlyAllow('post')", $result); $this->assertContains('if ($this->BakeArticle->save($this->request->data))', $result); $this->assertContains("\$this->Session->setFlash(__('The bake article has been saved'));", $result); @@ -392,7 +393,8 @@ class ControllerTaskTest extends CakeTestCase { $this->assertContains("\$this->set('bakeArticle', \$this->BakeArticle->read(null, \$id)", $result); $this->assertContains('function add()', $result); - $this->assertContains("if (\$this->request->is('post'))", $result); + $this->assertContains("if (\$this->request->data)", $result); + $this->assertContains("\$this->request->onlyAllow('post')", $result); $this->assertContains('if ($this->BakeArticle->save($this->request->data))', $result); $this->assertContains("\$this->flash(__('The bake article has been saved.'), array('action' => 'index'))", $result); From abe74adf8acbe9096c8f5e0339840ee68d2b0e81 Mon Sep 17 00:00:00 2001 From: Ceeram Date: Sat, 25 Aug 2012 14:43:12 +0200 Subject: [PATCH 095/256] partial remove onlyAllow from baked code, only keep in delete to be rfc compliant --- .../Templates/default/actions/controller_actions.ctp | 12 ++++-------- .../Case/Console/Command/Task/ControllerTaskTest.php | 7 +++---- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/lib/Cake/Console/Templates/default/actions/controller_actions.ctp b/lib/Cake/Console/Templates/default/actions/controller_actions.ctp index f30696796..21b6ab8ea 100644 --- a/lib/Cake/Console/Templates/default/actions/controller_actions.ctp +++ b/lib/Cake/Console/Templates/default/actions/controller_actions.ctp @@ -47,12 +47,10 @@ /** * add method * - * @throws MethodNotAllowedException * @return void */ public function add() { - if ($this->request->data) { - $this->request->onlyAllow('post'); + if ($this->request->is('post')) { $this->->create(); if ($this->->save($this->request->data)) { @@ -88,7 +86,6 @@ /** * edit method * - * @throws MethodNotAllowedException * @throws NotFoundException * @param string $id * @return void @@ -98,8 +95,7 @@ if (!$this->->exists()) { throw new NotFoundException(__('Invalid ')); } - if ($this->request->data) { - $this->request->onlyAllow('post', 'put'); + if ($this->request->is('post') || $this->request->is('put')) { if ($this->->save($this->request->data)) { $this->Session->setFlash(__('The has been saved')); @@ -135,17 +131,17 @@ /** * delete method * - * @throws MethodNotAllowedException * @throws NotFoundException + * @throws MethodNotAllowedException * @param string $id * @return void */ public function delete($id = null) { - $this->request->onlyAllow('post', 'delete'); $this->->id = $id; if (!$this->->exists()) { throw new NotFoundException(__('Invalid ')); } + $this->request->onlyAllow('post', 'delete'); if ($this->->delete()) { $this->Session->setFlash(__(' deleted')); diff --git a/lib/Cake/Test/Case/Console/Command/Task/ControllerTaskTest.php b/lib/Cake/Test/Case/Console/Command/Task/ControllerTaskTest.php index dd64f6252..bac5eb111 100644 --- a/lib/Cake/Test/Case/Console/Command/Task/ControllerTaskTest.php +++ b/lib/Cake/Test/Case/Console/Command/Task/ControllerTaskTest.php @@ -353,8 +353,7 @@ class ControllerTaskTest extends CakeTestCase { $this->assertContains("\$this->set('bakeArticle', \$this->BakeArticle->read(null, \$id)", $result); $this->assertContains('function add()', $result); - $this->assertContains("if (\$this->request->data)", $result); - $this->assertContains("\$this->request->onlyAllow('post')", $result); + $this->assertContains("if (\$this->request->is('post'))", $result); $this->assertContains('if ($this->BakeArticle->save($this->request->data))', $result); $this->assertContains("\$this->Session->setFlash(__('The bake article has been saved'));", $result); @@ -393,8 +392,7 @@ class ControllerTaskTest extends CakeTestCase { $this->assertContains("\$this->set('bakeArticle', \$this->BakeArticle->read(null, \$id)", $result); $this->assertContains('function add()', $result); - $this->assertContains("if (\$this->request->data)", $result); - $this->assertContains("\$this->request->onlyAllow('post')", $result); + $this->assertContains("if (\$this->request->is('post'))", $result); $this->assertContains('if ($this->BakeArticle->save($this->request->data))', $result); $this->assertContains("\$this->flash(__('The bake article has been saved.'), array('action' => 'index'))", $result); @@ -404,6 +402,7 @@ class ControllerTaskTest extends CakeTestCase { $this->assertContains("\$this->set(compact('bakeTags'))", $result); $this->assertContains('function delete($id = null)', $result); + $this->assertContains("\$this->request->onlyAllow('post', 'delete')", $result); $this->assertContains('if ($this->BakeArticle->delete())', $result); $this->assertContains("\$this->flash(__('Bake article deleted'), array('action' => 'index'))", $result); } From 028795eb2e9ae33a4a4c50e96b4971106177adc2 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 25 Aug 2012 17:31:21 -0400 Subject: [PATCH 096/256] Clarify docs. --- lib/Cake/Network/CakeResponse.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/lib/Cake/Network/CakeResponse.php b/lib/Cake/Network/CakeResponse.php index 57fae0c92..6b9854ec5 100644 --- a/lib/Cake/Network/CakeResponse.php +++ b/lib/Cake/Network/CakeResponse.php @@ -1083,12 +1083,11 @@ class CakeResponse { * is marked as so accordingly so the client can be informed of that. * * In order to mark a response as not modified, you need to set at least - * the Last-Modified response header or a response etag to be compared - * with the request itself + * the Last-Modified etag response header before calling this method. Otherwise + * a comparison will not be possible. * - * @return boolean whether the response was marked as not modified or - * not - **/ + * @return boolean whether the response was marked as not modified or not. + */ public function checkNotModified(CakeRequest $request) { $etags = preg_split('/\s*,\s*/', $request->header('If-None-Match'), null, PREG_SPLIT_NO_EMPTY); $modifiedSince = $request->header('If-Modified-Since'); From 934838f77c3cc72ffc3094d40c38e05817154f59 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sun, 26 Aug 2012 22:17:36 -0400 Subject: [PATCH 097/256] Fix whitespace. --- lib/Cake/Test/Case/Utility/StringTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Test/Case/Utility/StringTest.php b/lib/Cake/Test/Case/Utility/StringTest.php index 062005ec1..27bf9c34a 100644 --- a/lib/Cake/Test/Case/Utility/StringTest.php +++ b/lib/Cake/Test/Case/Utility/StringTest.php @@ -473,7 +473,7 @@ podeís adquirirla.

    )); $expected = '© 2005-2007, Cake Software...'; $this->assertEquals($expected, $result); - + $result = $this->Text->truncate($text, 31, array( 'html' => true, 'exact' => true, From f1ce3f9ae55479c3a7c87a6a869624c67681f488 Mon Sep 17 00:00:00 2001 From: Ceeram Date: Mon, 27 Aug 2012 11:22:06 +0200 Subject: [PATCH 098/256] remove settings parameter from initialize as this is not being passed. only the constructor gets settings passed --- lib/Cake/Controller/Component/RequestHandlerComponent.php | 8 +++----- .../Controller/Component/RequestHandlerComponentTest.php | 4 ++-- 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/lib/Cake/Controller/Component/RequestHandlerComponent.php b/lib/Cake/Controller/Component/RequestHandlerComponent.php index 89b2ca6cf..d3147af00 100644 --- a/lib/Cake/Controller/Component/RequestHandlerComponent.php +++ b/lib/Cake/Controller/Component/RequestHandlerComponent.php @@ -123,11 +123,10 @@ class RequestHandlerComponent extends Component { * and the requested mime-types, RequestHandler::$ext is set to that value. * * @param Controller $controller A reference to the controller - * @param array $settings Array of settings to _set(). * @return void * @see Router::parseExtensions() */ - public function initialize(Controller $controller, $settings = array()) { + public function initialize(Controller $controller) { if (isset($this->request->params['ext'])) { $this->ext = $this->request->params['ext']; } @@ -135,9 +134,8 @@ class RequestHandlerComponent extends Component { $this->_setExtension(); } $this->params = $controller->params; - $this->_set($settings); - if (!empty($settings['viewClassMap'])) { - $this->viewClassMap($settings['viewClassMap']); + if (!empty($this->settings['viewClassMap'])) { + $this->viewClassMap($this->settings['viewClassMap']); } } diff --git a/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php b/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php index ff3f98965..ca29f63b5 100644 --- a/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/RequestHandlerComponentTest.php @@ -281,8 +281,8 @@ class RequestHandlerComponentTest extends CakeTestCase { * @return void */ public function testViewClassMap() { - $settings = array('viewClassMap' => array('json' => 'CustomJson')); - $this->RequestHandler->initialize($this->Controller, $settings); + $this->RequestHandler->settings = array('viewClassMap' => array('json' => 'CustomJson')); + $this->RequestHandler->initialize($this->Controller); $result = $this->RequestHandler->viewClassMap(); $expected = array( 'json' => 'CustomJson', From fd2f3aed46122ffaf1c9554f9ab07f1374d0f016 Mon Sep 17 00:00:00 2001 From: Juan Basso Date: Tue, 28 Aug 2012 23:52:05 -0400 Subject: [PATCH 099/256] Changed to accept language do not return the qualifiers and order the values by the qualifier. Also, making the test case insensitive --- lib/Cake/Network/CakeRequest.php | 72 +++++++++++-------- .../Test/Case/Network/CakeRequestTest.php | 24 ++++++- 2 files changed, 66 insertions(+), 30 deletions(-) diff --git a/lib/Cake/Network/CakeRequest.php b/lib/Cake/Network/CakeRequest.php index a07abd24a..919e380a3 100644 --- a/lib/Cake/Network/CakeRequest.php +++ b/lib/Cake/Network/CakeRequest.php @@ -694,8 +694,50 @@ class CakeRequest implements ArrayAccess { * @return array An array of prefValue => array(content/types) */ public function parseAccept() { + return $this->_parseAcceptWithQualifier($this->header('accept')); + } + +/** + * Get the languages accepted by the client, or check if a specific language is accepted. + * + * Get the list of accepted languages: + * + * {{{ CakeRequest::acceptLanguage(); }}} + * + * Check if a specific language is accepted: + * + * {{{ CakeRequest::acceptLanguage('es-es'); }}} + * + * @param string $language The language to test. + * @return If a $language is provided, a boolean. Otherwise the array of accepted languages. + */ + public static function acceptLanguage($language = null) { + $raw = self::_parseAcceptWithQualifier(self::header('Accept-Language')); $accept = array(); - $header = explode(',', $this->header('accept')); + foreach ($raw as $qualifier => $languages) { + foreach ($languages as &$lang) { + if (strpos($lang, '_')) { + $lang = str_replace('_', '-', $lang); + } + $lang = strtolower($lang); + } + $accept = array_merge($accept, $languages); + } + if ($language === null) { + return $accept; + } + return in_array(strtolower($language), $accept); + } + +/** + * Parse Accept* headers with qualifier options + * + * @param string $header + * @return array + */ + protected static function _parseAcceptWithQualifier($header) { + $accept = array(); + $header = explode(',', $header); foreach (array_filter($header) as $value) { $prefPos = strpos($value, ';'); if ($prefPos !== false) { @@ -716,34 +758,6 @@ class CakeRequest implements ArrayAccess { return $accept; } -/** - * Get the languages accepted by the client, or check if a specific language is accepted. - * - * Get the list of accepted languages: - * - * {{{ CakeRequest::acceptLanguage(); }}} - * - * Check if a specific language is accepted: - * - * {{{ CakeRequest::acceptLanguage('es-es'); }}} - * - * @param string $language The language to test. - * @return If a $language is provided, a boolean. Otherwise the array of accepted languages. - */ - public static function acceptLanguage($language = null) { - $accepts = preg_split('/[;,]/', self::header('Accept-Language')); - foreach ($accepts as &$accept) { - $accept = strtolower($accept); - if (strpos($accept, '_') !== false) { - $accept = str_replace('_', '-', $accept); - } - } - if ($language === null) { - return $accepts; - } - return in_array($language, $accepts); - } - /** * Provides a read/write accessor for `$this->data`. Allows you * to use a syntax similar to `CakeSession` for reading post data. diff --git a/lib/Cake/Test/Case/Network/CakeRequestTest.php b/lib/Cake/Test/Case/Network/CakeRequestTest.php index d42cc152f..ae64aad6e 100644 --- a/lib/Cake/Test/Case/Network/CakeRequestTest.php +++ b/lib/Cake/Test/Case/Network/CakeRequestTest.php @@ -1746,19 +1746,41 @@ class CakeRequestTest extends CakeTestCase { * @return void */ public function testAcceptLanguage() { + // Weird language $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'inexistent,en-ca'; $result = CakeRequest::acceptLanguage(); $this->assertEquals(array('inexistent', 'en-ca'), $result, 'Languages do not match'); - $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'es_mx;en_ca'; + // No qualifier + $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'es_mx,en_ca'; $result = CakeRequest::acceptLanguage(); $this->assertEquals(array('es-mx', 'en-ca'), $result, 'Languages do not match'); + // With qualifier + $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'en-US,en;q=0.8,pt-BR;q=0.6,pt;q=0.4'; + $result = CakeRequest::acceptLanguage(); + $this->assertEquals(array('en-us', 'en', 'pt-br', 'pt'), $result, 'Languages do not match'); + + // With spaces + $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'da, en-gb;q=0.8, en;q=0.7'; + $result = CakeRequest::acceptLanguage(); + $this->assertEquals(array('da', 'en-gb', 'en'), $result, 'Languages do not match'); + + // Checking if requested + $_SERVER['HTTP_ACCEPT_LANGUAGE'] = 'es_mx,en_ca'; + $result = CakeRequest::acceptLanguage(); + $result = CakeRequest::acceptLanguage('en-ca'); $this->assertTrue($result); + $result = CakeRequest::acceptLanguage('en-CA'); + $this->assertTrue($result); + $result = CakeRequest::acceptLanguage('en-us'); $this->assertFalse($result); + + $result = CakeRequest::acceptLanguage('en-US'); + $this->assertFalse($result); } /** From 19c2a581858dc14e95c1cbde9d8a3b9ce6ceeb71 Mon Sep 17 00:00:00 2001 From: mark_story Date: Thu, 30 Aug 2012 14:46:29 +0100 Subject: [PATCH 100/256] Fix strict errors. --- lib/Cake/Controller/Component/Auth/DigestAuthenticate.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php b/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php index 5e0fb0ee5..3bd5cb618 100644 --- a/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php +++ b/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php @@ -157,7 +157,7 @@ class DigestAuthenticate extends BaseAuthenticate { * @param string $password Unused password, digest doesn't require passwords. * @return Mixed Either false on failure, or an array of user data. */ - protected function _findUser($username, $password) { + protected function _findUser($username, $password = null) { $userModel = $this->settings['userModel']; list($plugin, $model) = pluginSplit($userModel); $fields = $this->settings['fields']; From 6a95b5746ab50b43e0bf90eed3e418b6bbb3dd83 Mon Sep 17 00:00:00 2001 From: mark_story Date: Thu, 30 Aug 2012 14:48:13 +0100 Subject: [PATCH 101/256] Remove un-necessary parameter. --- lib/Cake/Controller/Component/Auth/DigestAuthenticate.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php b/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php index 3bd5cb618..b9c50691b 100644 --- a/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php +++ b/lib/Cake/Controller/Component/Auth/DigestAuthenticate.php @@ -138,7 +138,7 @@ class DigestAuthenticate extends BaseAuthenticate { if (empty($digest)) { return false; } - $user = $this->_findUser($digest['username'], null); + $user = $this->_findUser($digest['username']); if (empty($user)) { return false; } From 15555a73099e9e32d3e518d0588932863e41832c Mon Sep 17 00:00:00 2001 From: Tommy MacWilliam Date: Sun, 26 Aug 2012 01:32:17 -0400 Subject: [PATCH 102/256] added schema support for mysql bigints --- lib/Cake/Model/Datasource/Database/Mysql.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/Cake/Model/Datasource/Database/Mysql.php b/lib/Cake/Model/Datasource/Database/Mysql.php index 9506a8a94..cd352e34e 100644 --- a/lib/Cake/Model/Datasource/Database/Mysql.php +++ b/lib/Cake/Model/Datasource/Database/Mysql.php @@ -108,6 +108,7 @@ class Mysql extends DboSource { 'primary_key' => array('name' => 'NOT NULL AUTO_INCREMENT'), 'string' => array('name' => 'varchar', 'limit' => '255'), 'text' => array('name' => 'text'), + 'biginteger' => array('name' => 'bigint', 'limit' => '20'), 'integer' => array('name' => 'int', 'limit' => '11', 'formatter' => 'intval'), 'float' => array('name' => 'float', 'formatter' => 'floatval'), 'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'), @@ -646,6 +647,9 @@ class Mysql extends DboSource { if (($col === 'tinyint' && $limit == 1) || $col === 'boolean') { return 'boolean'; } + if (strpos($col, 'bigint') !== false || $col === 'bigint') { + return 'biginteger'; + } if (strpos($col, 'int') !== false) { return 'integer'; } From 68116f701708ef80e0baa102f57a3a768bccc203 Mon Sep 17 00:00:00 2001 From: Tommy MacWilliam Date: Sun, 26 Aug 2012 02:45:57 -0400 Subject: [PATCH 103/256] BIGINTs can also be primary keys --- lib/Cake/Model/Datasource/DboSource.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Model/Datasource/DboSource.php b/lib/Cake/Model/Datasource/DboSource.php index 64536c610..fc14ba4fb 100644 --- a/lib/Cake/Model/Datasource/DboSource.php +++ b/lib/Cake/Model/Datasource/DboSource.php @@ -3068,7 +3068,7 @@ class DboSource extends DataSource { } $out = $this->_buildFieldParameters($out, $column, 'beforeDefault'); - if (isset($column['key']) && $column['key'] === 'primary' && $type === 'integer') { + if (isset($column['key']) && $column['key'] === 'primary' && ($type === 'integer' || $type === 'biginteger')) { $out .= ' ' . $this->columns['primary_key']['name']; } elseif (isset($column['key']) && $column['key'] === 'primary') { $out .= ' NOT NULL'; From ec35e3158c20a489a53f8ae105ea284601c63d48 Mon Sep 17 00:00:00 2001 From: Tommy MacWilliam Date: Mon, 27 Aug 2012 20:34:02 -0400 Subject: [PATCH 104/256] added tests for bigints --- .../Test/Case/Model/Datasource/Database/MysqlTest.php | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php b/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php index c6645a3c5..0cbaf5164 100644 --- a/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/Database/MysqlTest.php @@ -268,6 +268,13 @@ class MysqlTest extends CakeTestCase { $this->Dbo->rawQuery('DROP TABLE ' . $name); $this->assertEquals($expected, $result); + $name = $this->Dbo->fullTableName('bigint'); + $this->Dbo->rawQuery('CREATE TABLE ' . $name . ' (id bigint(20) AUTO_INCREMENT, bool tinyint(1), small_int tinyint(2), primary key(id));'); + $expected = array('PRIMARY' => array('column' => 'id', 'unique' => 1)); + $result = $this->Dbo->index('bigint', false); + $this->Dbo->rawQuery('DROP TABLE ' . $name); + $this->assertEquals($expected, $result); + $name = $this->Dbo->fullTableName('with_a_key'); $this->Dbo->rawQuery('CREATE TABLE ' . $name . ' (id int(11) AUTO_INCREMENT, bool tinyint(1), small_int tinyint(2), primary key(id), KEY `pointless_bool` ( `bool` ));'); $expected = array( @@ -477,6 +484,10 @@ class MysqlTest extends CakeTestCase { $expected = 'integer'; $this->assertEquals($expected, $result); + $result = $this->Dbo->column('bigint(20)'); + $expected = 'biginteger'; + $this->assertEquals($expected, $result); + $result = $this->Dbo->column('tinyint(1)'); $expected = 'boolean'; $this->assertEquals($expected, $result); From 7bad865d6e4e89c114b04c14a92ac30599fb678b Mon Sep 17 00:00:00 2001 From: mark_story Date: Thu, 30 Aug 2012 12:39:14 +0100 Subject: [PATCH 105/256] Add bigint support for postgres --- lib/Cake/Model/Datasource/Database/Postgres.php | 17 ++++++++++++++++- .../Model/Datasource/Database/PostgresTest.php | 12 ++++++++++-- 2 files changed, 26 insertions(+), 3 deletions(-) diff --git a/lib/Cake/Model/Datasource/Database/Postgres.php b/lib/Cake/Model/Datasource/Database/Postgres.php index 74da3465b..7e16edb5b 100644 --- a/lib/Cake/Model/Datasource/Database/Postgres.php +++ b/lib/Cake/Model/Datasource/Database/Postgres.php @@ -59,6 +59,7 @@ class Postgres extends DboSource { 'string' => array('name' => 'varchar', 'limit' => '255'), 'text' => array('name' => 'text'), 'integer' => array('name' => 'integer', 'formatter' => 'intval'), + 'biginteger' => array('name' => 'bigint', 'limit' => '20'), 'float' => array('name' => 'float', 'formatter' => 'floatval'), 'datetime' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'), 'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'), @@ -637,6 +638,8 @@ class Postgres extends DboSource { return 'datetime'; case (strpos($col, 'time') === 0): return 'time'; + case ($col == 'bigint'): + return 'biginteger'; case (strpos($col, 'int') !== false && $col != 'interval'): return 'integer'; case (strpos($col, 'char') !== false || $col == 'uuid'): @@ -799,7 +802,19 @@ class Postgres extends DboSource { if (!isset($col['length']) && !isset($col['limit'])) { unset($column['length']); } - $out = preg_replace('/integer\([0-9]+\)/', 'integer', parent::buildColumn($column)); + $out = parent::buildColumn($column); + + $out = preg_replace( + '/integer\([0-9]+\)/', + 'integer', + $out + ); + $out = preg_replace( + '/bigint\([0-9]+\)/', + 'bigint', + $out + ); + $out = str_replace('integer serial', 'serial', $out); if (strpos($out, 'timestamp DEFAULT')) { if (isset($column['null']) && $column['null']) { diff --git a/lib/Cake/Test/Case/Model/Datasource/Database/PostgresTest.php b/lib/Cake/Test/Case/Model/Datasource/Database/PostgresTest.php index 2046e6b19..154920262 100644 --- a/lib/Cake/Test/Case/Model/Datasource/Database/PostgresTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/Database/PostgresTest.php @@ -307,6 +307,10 @@ class PostgresTest extends CakeTestCase { $this->assertEquals('string', $this->Dbo2->column('character varying')); $this->assertEquals('time', $this->Dbo2->column('time without time zone')); $this->assertEquals('datetime', $this->Dbo2->column('timestamp without time zone')); + + $result = $this->Dbo2->column('bigint'); + $expected = 'biginteger'; + $this->assertEquals($expected, $result); } /** @@ -530,6 +534,7 @@ class PostgresTest extends CakeTestCase { id serial NOT NULL, "varchar" character varying(40) NOT NULL, "full_length" character varying NOT NULL, + "huge_int" bigint NOT NULL, "timestamp" timestamp without time zone, "date" date, CONSTRAINT test_data_types_pkey PRIMARY KEY (id) @@ -541,12 +546,15 @@ class PostgresTest extends CakeTestCase { 'connection' => 'test', 'models' => array('DatatypeTest') )); - $schema->tables = array('datatype_tests' => $result['tables']['missing']['datatype_tests']); + $schema->tables = array( + 'datatype_tests' => $result['tables']['missing']['datatype_tests'] + ); $result = $db1->createSchema($schema, 'datatype_tests'); $this->assertNotRegExp('/timestamp DEFAULT/', $result); $this->assertRegExp('/\"full_length\"\s*text\s.*,/', $result); - $this->assertRegExp('/timestamp\s*,/', $result); + $this->assertContains('timestamp ,', $result); + $this->assertContains('"huge_int" bigint NOT NULL,', $result); $db1->query('DROP TABLE ' . $db1->fullTableName('datatype_tests')); From 8d8f4b5c5da3470058ea1848565e87f3c7cae4fc Mon Sep 17 00:00:00 2001 From: mark_story Date: Thu, 30 Aug 2012 14:26:17 +0100 Subject: [PATCH 106/256] Add bigint support for Sqlite. * Update SQLite for biginteger. * Update CakeSchema tests for integration purposes. --- lib/Cake/Model/Datasource/Database/Sqlite.php | 16 ++++- lib/Cake/Test/Case/Model/CakeSchemaTest.php | 1 + .../Model/Datasource/Database/SqliteTest.php | 58 ++++++++++++++++++- lib/Cake/Test/Fixture/DatatypeFixture.php | 3 +- 4 files changed, 74 insertions(+), 4 deletions(-) diff --git a/lib/Cake/Model/Datasource/Database/Sqlite.php b/lib/Cake/Model/Datasource/Database/Sqlite.php index 63ed60391..5d3bb4f3e 100644 --- a/lib/Cake/Model/Datasource/Database/Sqlite.php +++ b/lib/Cake/Model/Datasource/Database/Sqlite.php @@ -70,6 +70,7 @@ class Sqlite extends DboSource { 'string' => array('name' => 'varchar', 'limit' => '255'), 'text' => array('name' => 'text'), 'integer' => array('name' => 'integer', 'limit' => null, 'formatter' => 'intval'), + 'biginteger' => array('name' => 'bigint', 'limit' => 20), 'float' => array('name' => 'float', 'formatter' => 'floatval'), 'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'), 'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'), @@ -248,9 +249,22 @@ class Sqlite extends DboSource { $limit = null; @list($col, $limit) = explode('(', $col); - if (in_array($col, array('text', 'integer', 'float', 'boolean', 'timestamp', 'date', 'datetime', 'time'))) { + $standard = array( + 'text', + 'integer', + 'float', + 'boolean', + 'timestamp', + 'date', + 'datetime', + 'time' + ); + if (in_array($col, $standard)) { return $col; } + if ($col === 'bigint') { + return 'biginteger'; + } if (strpos($col, 'char') !== false) { return 'string'; } diff --git a/lib/Cake/Test/Case/Model/CakeSchemaTest.php b/lib/Cake/Test/Case/Model/CakeSchemaTest.php index 47effcc14..34c782e58 100644 --- a/lib/Cake/Test/Case/Model/CakeSchemaTest.php +++ b/lib/Cake/Test/Case/Model/CakeSchemaTest.php @@ -198,6 +198,7 @@ class TestAppSchema extends CakeSchema { public $datatypes = array( 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'), 'float_field' => array('type' => 'float', 'null' => false, 'length' => '5,2', 'default' => ''), + 'huge_int' => array('type' => 'biginteger'), 'bool' => array('type' => 'boolean', 'null' => false, 'default' => false), 'indexes' => array('PRIMARY' => array('column' => 'id', 'unique' => true)), 'tableParameters' => array() diff --git a/lib/Cake/Test/Case/Model/Datasource/Database/SqliteTest.php b/lib/Cake/Test/Case/Model/Datasource/Database/SqliteTest.php index f590cc7a0..007f2a883 100644 --- a/lib/Cake/Test/Case/Model/Datasource/Database/SqliteTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/Database/SqliteTest.php @@ -77,7 +77,7 @@ class SqliteTest extends CakeTestCase { * * @var object */ - public $fixtures = array('core.user', 'core.uuid'); + public $fixtures = array('core.user', 'core.uuid', 'core.datatype'); /** * Actual DB connection used in testing @@ -253,6 +253,16 @@ class SqliteTest extends CakeTestCase { $result = $this->Dbo->buildColumn($data); $expected = '"testName" integer(10) DEFAULT 10 NOT NULL'; $this->assertEquals($expected, $result); + + $data = array( + 'name' => 'huge', + 'type' => 'biginteger', + 'length' => 20, + 'null' => false, + ); + $result = $this->Dbo->buildColumn($data); + $expected = '"huge" bigint(20) NOT NULL'; + $this->assertEquals($expected, $result); } /** @@ -262,7 +272,11 @@ class SqliteTest extends CakeTestCase { */ public function testDescribe() { $this->loadFixtures('User'); - $Model = new Model(array('name' => 'User', 'ds' => 'test', 'table' => 'users')); + $Model = new Model(array( + 'name' => 'User', + 'ds' => 'test', + 'table' => 'users' + )); $this->Dbo->cacheSources = true; Configure::write('Cache.disable', false); @@ -310,6 +324,46 @@ class SqliteTest extends CakeTestCase { $this->assertEquals($expected, $result); } +/** + * Test that datatypes are reflected + * + * @return void + */ + public function testDatatypes() { + $this->loadFixtures('Datatype'); + $Model = new Model(array( + 'name' => 'Datatype', + 'ds' => 'test', + 'table' => 'datatypes' + )); + $result = $this->Dbo->describe($Model); + $expected = array( + 'id' => array( + 'type' => 'integer', + 'null' => false, + 'default' => 0, + 'key' => 'primary' + ), + 'float_field' => array( + 'type' => 'float', + 'length' => '5,2', + 'null' => false, + 'default' => null + ), + 'huge_int' => array( + 'type' => 'bigint', + 'length' => '20', + 'null' => true, + 'default' => null + ), + 'bool' => array( + 'type' => 'boolean', + 'null' => false, + 'default' => false + ), + ); + } + /** * test that describe does not corrupt UUID primary keys * diff --git a/lib/Cake/Test/Fixture/DatatypeFixture.php b/lib/Cake/Test/Fixture/DatatypeFixture.php index 0a9f2e067..5fb360e64 100644 --- a/lib/Cake/Test/Fixture/DatatypeFixture.php +++ b/lib/Cake/Test/Fixture/DatatypeFixture.php @@ -39,6 +39,7 @@ class DatatypeFixture extends CakeTestFixture { public $fields = array( 'id' => array('type' => 'integer', 'null' => false, 'default' => 0, 'key' => 'primary'), 'float_field' => array('type' => 'float', 'length' => '5,2', 'null' => false, 'default' => null), + 'huge_int' => array('type' => 'biginteger'), 'bool' => array('type' => 'boolean', 'null' => false, 'default' => false), ); @@ -48,6 +49,6 @@ class DatatypeFixture extends CakeTestFixture { * @var array */ public $records = array( - array('id' => 1, 'float_field' => 42.23, 'bool' => 0), + array('id' => 1, 'float_field' => 42.23, 'huge_int' => '123456789123456789123456789', 'bool' => 0), ); } From d4ee62be617b3f567e5d85cb681fe77912e68844 Mon Sep 17 00:00:00 2001 From: mark_story Date: Thu, 30 Aug 2012 16:35:36 +0100 Subject: [PATCH 107/256] Add support for biginteger on SQLserver. --- .../Model/Datasource/Database/Sqlserver.php | 24 +++++++++++-------- .../Datasource/Database/SqlserverTest.php | 8 +++++++ 2 files changed, 22 insertions(+), 10 deletions(-) diff --git a/lib/Cake/Model/Datasource/Database/Sqlserver.php b/lib/Cake/Model/Datasource/Database/Sqlserver.php index 3700ca2d0..8e6f23e5e 100644 --- a/lib/Cake/Model/Datasource/Database/Sqlserver.php +++ b/lib/Cake/Model/Datasource/Database/Sqlserver.php @@ -86,16 +86,17 @@ class Sqlserver extends DboSource { */ public $columns = array( 'primary_key' => array('name' => 'IDENTITY (1, 1) NOT NULL'), - 'string' => array('name' => 'nvarchar', 'limit' => '255'), - 'text' => array('name' => 'nvarchar', 'limit' => 'MAX'), - 'integer' => array('name' => 'int', 'formatter' => 'intval'), - 'float' => array('name' => 'numeric', 'formatter' => 'floatval'), - 'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'), + 'string' => array('name' => 'nvarchar', 'limit' => '255'), + 'text' => array('name' => 'nvarchar', 'limit' => 'MAX'), + 'integer' => array('name' => 'int', 'formatter' => 'intval'), + 'biginteger' => array('name' => 'bigint'), + 'float' => array('name' => 'numeric', 'formatter' => 'floatval'), + 'datetime' => array('name' => 'datetime', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'), 'timestamp' => array('name' => 'timestamp', 'format' => 'Y-m-d H:i:s', 'formatter' => 'date'), - 'time' => array('name' => 'datetime', 'format' => 'H:i:s', 'formatter' => 'date'), - 'date' => array('name' => 'datetime', 'format' => 'Y-m-d', 'formatter' => 'date'), - 'binary' => array('name' => 'varbinary'), - 'boolean' => array('name' => 'bit') + 'time' => array('name' => 'datetime', 'format' => 'H:i:s', 'formatter' => 'date'), + 'date' => array('name' => 'datetime', 'format' => 'Y-m-d', 'formatter' => 'date'), + 'binary' => array('name' => 'varbinary'), + 'boolean' => array('name' => 'bit') ); /** @@ -399,6 +400,9 @@ class Sqlserver extends DboSource { if ($col == 'bit') { return 'boolean'; } + if (strpos($col, 'bigint') !== false) { + return 'biginteger'; + } if (strpos($col, 'int') !== false) { return 'integer'; } @@ -643,7 +647,7 @@ class Sqlserver extends DboSource { */ public function buildColumn($column) { $result = parent::buildColumn($column); - $result = preg_replace('/(int|integer)\([0-9]+\)/i', '$1', $result); + $result = preg_replace('/(bigint|int|integer)\([0-9]+\)/i', '$1', $result); $result = preg_replace('/(bit)\([0-9]+\)/i', '$1', $result); if (strpos($result, 'DEFAULT NULL') !== false) { if (isset($column['default']) && $column['default'] === '') { diff --git a/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php b/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php index e31595bf3..18e3d6f9d 100644 --- a/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/Database/SqlserverTest.php @@ -553,6 +553,14 @@ class SqlserverTest extends CakeTestCase { $result = $this->db->buildColumn($column); $expected = "[checked] bit DEFAULT '1'"; $this->assertEquals($expected, $result); + + $column = array( + 'name' => 'huge', + 'type' => 'biginteger', + ); + $result = $this->db->buildColumn($column); + $expected = "[huge] bigint"; + $this->assertEquals($expected, $result); } /** From e64f5f15e22bfbbbf69dfacec4417cfaa846ad7a Mon Sep 17 00:00:00 2001 From: mark_story Date: Thu, 30 Aug 2012 19:18:25 +0100 Subject: [PATCH 108/256] Fix big int lengths on SQLserver SQLserver big ints aren't as big as other database servers. --- lib/Cake/Test/Fixture/DatatypeFixture.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/Cake/Test/Fixture/DatatypeFixture.php b/lib/Cake/Test/Fixture/DatatypeFixture.php index 5fb360e64..d583ce5d0 100644 --- a/lib/Cake/Test/Fixture/DatatypeFixture.php +++ b/lib/Cake/Test/Fixture/DatatypeFixture.php @@ -49,6 +49,6 @@ class DatatypeFixture extends CakeTestFixture { * @var array */ public $records = array( - array('id' => 1, 'float_field' => 42.23, 'huge_int' => '123456789123456789123456789', 'bool' => 0), + array('id' => 1, 'float_field' => 42.23, 'huge_int' => '1234567891234567891', 'bool' => 0), ); } From 072991d0da9430d0e9632330618c56cae1f0b988 Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 1 Sep 2012 14:34:10 +0100 Subject: [PATCH 109/256] Make test a bit more solid. --- lib/Cake/Test/Case/Network/CakeSocketTest.php | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Test/Case/Network/CakeSocketTest.php b/lib/Cake/Test/Case/Network/CakeSocketTest.php index 0cee94c38..cc30d3f60 100644 --- a/lib/Cake/Test/Case/Network/CakeSocketTest.php +++ b/lib/Cake/Test/Case/Network/CakeSocketTest.php @@ -179,11 +179,18 @@ class CakeSocketTest extends CakeTestCase { $config = array('host' => '127.0.0.1', 'timeout' => 0.5); $this->Socket = new CakeSocket($config); $this->assertTrue($this->Socket->connect()); + } +/** + * test timing out raises exception + * + * @expectedException SocketException + * @expectedExceptionMessage Operation timed out + */ + public function testTimeOutThrowException() { $config = array('host' => '127.0.0.1', 'timeout' => 0.00001); $this->Socket = new CakeSocket($config); - $this->assertFalse($this->Socket->read(1024 * 1024)); - $this->assertEquals('2: ' . __d('cake_dev', 'Connection timed out'), $this->Socket->lastError()); + $this->Socket->read(1024 * 1024); } /** From 21a51a374a9ef8e1cd8bf7f890e1e25b279016bb Mon Sep 17 00:00:00 2001 From: mark_story Date: Sat, 1 Sep 2012 14:43:11 +0100 Subject: [PATCH 110/256] Revert "Make test a bit more solid." This reverts commit 072991d0da9430d0e9632330618c56cae1f0b988. --- lib/Cake/Test/Case/Network/CakeSocketTest.php | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/lib/Cake/Test/Case/Network/CakeSocketTest.php b/lib/Cake/Test/Case/Network/CakeSocketTest.php index cc30d3f60..0cee94c38 100644 --- a/lib/Cake/Test/Case/Network/CakeSocketTest.php +++ b/lib/Cake/Test/Case/Network/CakeSocketTest.php @@ -179,18 +179,11 @@ class CakeSocketTest extends CakeTestCase { $config = array('host' => '127.0.0.1', 'timeout' => 0.5); $this->Socket = new CakeSocket($config); $this->assertTrue($this->Socket->connect()); - } -/** - * test timing out raises exception - * - * @expectedException SocketException - * @expectedExceptionMessage Operation timed out - */ - public function testTimeOutThrowException() { $config = array('host' => '127.0.0.1', 'timeout' => 0.00001); $this->Socket = new CakeSocket($config); - $this->Socket->read(1024 * 1024); + $this->assertFalse($this->Socket->read(1024 * 1024)); + $this->assertEquals('2: ' . __d('cake_dev', 'Connection timed out'), $this->Socket->lastError()); } /** From fca98e39f9041c1aee915968e0523dfc83e0c2c8 Mon Sep 17 00:00:00 2001 From: brq Date: Sun, 2 Sep 2012 12:50:08 -0500 Subject: [PATCH 111/256] Allow postLink() to support other HTTP methods; it defaults to POST --- lib/Cake/Test/Case/View/Helper/FormHelperTest.php | 13 +++++++++++++ lib/Cake/View/Helper/FormHelper.php | 9 +++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php index fcaf57d1e..75dff5068 100644 --- a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php @@ -6125,6 +6125,19 @@ class FormHelperTest extends CakeTestCase { '/a' )); + $result = $this->Form->postLink('Delete', '/posts/delete/1', array('method'=>'delete')); + $this->assertTags($result, array( + 'form' => array( + 'method' => 'post', 'action' => '/posts/delete/1', + 'name' => 'preg:/post_\w+/', 'id' => 'preg:/post_\w+/', 'style' => 'display:none;' + ), + 'input' => array('type' => 'hidden', 'name' => '_method', 'value' => 'DELETE'), + '/form', + 'a' => array('href' => '#', 'onclick' => 'preg:/document\.post_\w+\.submit\(\); event\.returnValue = false; return false;/'), + 'Delete', + '/a' + )); + $result = $this->Form->postLink('Delete', '/posts/delete/1', array(), 'Confirm?'); $this->assertTags($result, array( 'form' => array( diff --git a/lib/Cake/View/Helper/FormHelper.php b/lib/Cake/View/Helper/FormHelper.php index d78531fdf..de3824529 100644 --- a/lib/Cake/View/Helper/FormHelper.php +++ b/lib/Cake/View/Helper/FormHelper.php @@ -1578,7 +1578,7 @@ class FormHelper extends AppHelper { } /** - * Creates an HTML link, but access the url using method POST. + * Creates an HTML link, but access the url using the method you specify (defaults to POST). * Requires javascript to be enabled in browser. * * This method creates a `
    ` element. So do not use this method inside an existing form. @@ -1599,6 +1599,11 @@ class FormHelper extends AppHelper { * @link http://book.cakephp.org/2.0/en/core-libraries/helpers/form.html#FormHelper::postLink */ public function postLink($title, $url = null, $options = array(), $confirmMessage = false) { + $requestMethod = 'POST'; + if (!empty($options['method'])) { + $requestMethod = strtoupper($options['method']); + unset($options['method']); + } if (!empty($options['confirm'])) { $confirmMessage = $options['confirm']; unset($options['confirm']); @@ -1607,7 +1612,7 @@ class FormHelper extends AppHelper { $formName = uniqid('post_'); $formUrl = $this->url($url); $out = $this->Html->useTag('form', $formUrl, array('name' => $formName, 'id' => $formName, 'style' => 'display:none;', 'method' => 'post')); - $out .= $this->Html->useTag('hidden', '_method', ' value="POST"'); + $out .= $this->Html->useTag('hidden', '_method', ' value="' . $requestMethod . '"'); $out .= $this->_csrfField(); $fields = array(); From 387a974396dbae274f31dd68968980e813dd4d79 Mon Sep 17 00:00:00 2001 From: euromark Date: Mon, 3 Sep 2012 13:16:40 +0200 Subject: [PATCH 112/256] avoid path being made absolute twice --- lib/Cake/View/MediaView.php | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/lib/Cake/View/MediaView.php b/lib/Cake/View/MediaView.php index e4e6ea7e9..728d42a83 100644 --- a/lib/Cake/View/MediaView.php +++ b/lib/Cake/View/MediaView.php @@ -69,11 +69,7 @@ class MediaView extends View { $name = $download = $id = $modified = $path = $cache = $mimeType = $compress = null; extract($this->viewVars, EXTR_OVERWRITE); - if (is_dir($path)) { - $path = $path . $id; - } else { - $path = APP . $path . $id; - } + $path = $path . $id; if (is_array($mimeType)) { $this->response->type($mimeType); From 2170d87488017f3eb719289fcf11af07ee223f46 Mon Sep 17 00:00:00 2001 From: euromark Date: Tue, 4 Sep 2012 01:04:48 +0200 Subject: [PATCH 113/256] check() for CookieComponent and Configure (similar to `CakeSession::check()`) --- .../Controller/Component/CookieComponent.php | 14 +++++ lib/Cake/Core/Configure.php | 14 +++++ .../Component/CookieComponentTest.php | 54 +++++++++++++++++++ lib/Cake/Test/Case/Core/ConfigureTest.php | 54 +++++++++++++++++++ .../Case/Model/Datasource/CakeSessionTest.php | 2 +- 5 files changed, 137 insertions(+), 1 deletion(-) diff --git a/lib/Cake/Controller/Component/CookieComponent.php b/lib/Cake/Controller/Component/CookieComponent.php index 45551a8af..bdf344a5b 100644 --- a/lib/Cake/Controller/Component/CookieComponent.php +++ b/lib/Cake/Controller/Component/CookieComponent.php @@ -281,6 +281,20 @@ class CookieComponent extends Component { return $this->_values[$this->name][$key]; } +/** + * Returns true if given variable is set in cookie. + * + * @param string $var Variable name to check for + * @return boolean True if variable is there + */ + public function check($key = null) { + if (empty($key)) { + return false; + } + $result = $this->read($key); + return isset($result); + } + /** * Delete a cookie value * diff --git a/lib/Cake/Core/Configure.php b/lib/Cake/Core/Configure.php index 09615825c..f2101f795 100644 --- a/lib/Cake/Core/Configure.php +++ b/lib/Cake/Core/Configure.php @@ -170,6 +170,20 @@ class Configure { return Hash::get(self::$_values, $var); } +/** + * Returns true if given variable is set in Configure. + * + * @param string $var Variable name to check for + * @return boolean True if variable is there + */ + public static function check($var = null) { + if (empty($var)) { + return false; + } + $result = Hash::get(self::$_values, $var); + return isset($result); + } + /** * Used to delete a variable from Configure. * diff --git a/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php b/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php index 6ed65a673..7609b89ae 100644 --- a/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php +++ b/lib/Cake/Test/Case/Controller/Component/CookieComponentTest.php @@ -536,6 +536,60 @@ class CookieComponentTest extends CakeTestCase { $this->assertNull($this->Cookie->read('value')); } +/** + * testCheck method + * + * @return void + */ + public function testCheck() { + $this->Cookie->write('CookieComponentTestCase', 'value'); + $this->assertTrue($this->Cookie->check('CookieComponentTestCase')); + + $this->assertFalse($this->Cookie->check('NotExistingCookieComponentTestCase')); + } + +/** + * testCheckingSavedEmpty method + * + * @return void + */ + public function testCheckingSavedEmpty() { + $this->Cookie->write('CookieComponentTestCase', 0); + $this->assertTrue($this->Cookie->check('CookieComponentTestCase')); + + $this->Cookie->write('CookieComponentTestCase', '0'); + $this->assertTrue($this->Cookie->check('CookieComponentTestCase')); + + $this->Cookie->write('CookieComponentTestCase', false); + $this->assertTrue($this->Cookie->check('CookieComponentTestCase')); + + $this->Cookie->write('CookieComponentTestCase', null); + $this->assertFalse($this->Cookie->check('CookieComponentTestCase')); + } + +/** + * testCheckKeyWithSpaces method + * + * @return void + */ + public function testCheckKeyWithSpaces() { + $this->Cookie->write('CookieComponent Test', "test"); + $this->assertTrue($this->Cookie->check('CookieComponent Test')); + $this->Cookie->delete('CookieComponent Test'); + + $this->Cookie->write('CookieComponent Test.Test Case', "test"); + $this->assertTrue($this->Cookie->check('CookieComponent Test.Test Case')); + } + +/** + * testCheckEmpty + * + * @return void + */ + public function testCheckEmpty() { + $this->assertFalse($this->Cookie->check()); + } + /** * test that deleting a top level keys kills the child elements too. * diff --git a/lib/Cake/Test/Case/Core/ConfigureTest.php b/lib/Cake/Test/Case/Core/ConfigureTest.php index 7351f83f1..5dd1fe0b6 100644 --- a/lib/Cake/Test/Case/Core/ConfigureTest.php +++ b/lib/Cake/Test/Case/Core/ConfigureTest.php @@ -177,6 +177,60 @@ class ConfigureTest extends CakeTestCase { $this->assertTrue($result === null); } +/** + * testCheck method + * + * @return void + */ + public function testCheck() { + Configure::write('ConfigureTestCase', 'value'); + $this->assertTrue(Configure::check('ConfigureTestCase')); + + $this->assertFalse(Configure::check('NotExistingConfigureTestCase')); + } + +/** + * testCheckingSavedEmpty method + * + * @return void + */ + public function testCheckingSavedEmpty() { + $this->assertTrue(Configure::write('ConfigureTestCase', 0)); + $this->assertTrue(Configure::check('ConfigureTestCase')); + + $this->assertTrue(Configure::write('ConfigureTestCase', '0')); + $this->assertTrue(Configure::check('ConfigureTestCase')); + + $this->assertTrue(Configure::write('ConfigureTestCase', false)); + $this->assertTrue(Configure::check('ConfigureTestCase')); + + $this->assertTrue(Configure::write('ConfigureTestCase', null)); + $this->assertFalse(Configure::check('ConfigureTestCase')); + } + +/** + * testCheckKeyWithSpaces method + * + * @return void + */ + public function testCheckKeyWithSpaces() { + $this->assertTrue(Configure::write('Configure Test', "test")); + $this->assertTrue(Configure::check('Configure Test')); + Configure::delete('Configure Test'); + + $this->assertTrue(Configure::write('Configure Test.Test Case', "test")); + $this->assertTrue(Configure::check('Configure Test.Test Case')); + } + +/** + * testCheckEmpty + * + * @return void + */ + public function testCheckEmpty() { + $this->assertFalse(Configure::check()); + } + /** * testLoad method * diff --git a/lib/Cake/Test/Case/Model/Datasource/CakeSessionTest.php b/lib/Cake/Test/Case/Model/Datasource/CakeSessionTest.php index a2276972f..0c98febaa 100644 --- a/lib/Cake/Test/Case/Model/Datasource/CakeSessionTest.php +++ b/lib/Cake/Test/Case/Model/Datasource/CakeSessionTest.php @@ -231,7 +231,7 @@ class CakeSessionTest extends CakeTestCase { TestCakeSession::write('SessionTestCase', 'value'); $this->assertTrue(TestCakeSession::check('SessionTestCase')); - $this->assertFalse(TestCakeSession::check('NotExistingSessionTestCase'), false); + $this->assertFalse(TestCakeSession::check('NotExistingSessionTestCase')); } /** From 771cfde19631b7cb147b9c9af06b064f0b15d635 Mon Sep 17 00:00:00 2001 From: mark_story Date: Mon, 3 Sep 2012 20:09:13 -0400 Subject: [PATCH 114/256] Fix coding standards. --- lib/Cake/Test/Case/View/Helper/FormHelperTest.php | 2 +- lib/Cake/Test/Case/View/Helper/RssHelperTest.php | 2 +- lib/Cake/View/Helper/FormHelper.php | 13 ++++++++++--- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php index 75dff5068..fa7b75da4 100644 --- a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php @@ -6125,7 +6125,7 @@ class FormHelperTest extends CakeTestCase { '/a' )); - $result = $this->Form->postLink('Delete', '/posts/delete/1', array('method'=>'delete')); + $result = $this->Form->postLink('Delete', '/posts/delete/1', array('method' => 'delete')); $this->assertTags($result, array( 'form' => array( 'method' => 'post', 'action' => '/posts/delete/1', diff --git a/lib/Cake/Test/Case/View/Helper/RssHelperTest.php b/lib/Cake/Test/Case/View/Helper/RssHelperTest.php index 10b8820ec..6595757c0 100644 --- a/lib/Cake/Test/Case/View/Helper/RssHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/RssHelperTest.php @@ -647,7 +647,7 @@ class RssHelperTest extends CakeTestCase { } else { $type = mime_content_type($tmpFile); } - + $expected = array( 'url($url); - $out = $this->Html->useTag('form', $formUrl, array('name' => $formName, 'id' => $formName, 'style' => 'display:none;', 'method' => 'post')); - $out .= $this->Html->useTag('hidden', '_method', ' value="' . $requestMethod . '"'); + $out = $this->Html->useTag('form', $formUrl, array( + 'name' => $formName, + 'id' => $formName, + 'style' => 'display:none;', + 'method' => 'post' + )); + $out .= $this->Html->useTag('hidden', '_method', array( + 'value' => $requestMethod + )); $out .= $this->_csrfField(); $fields = array(); From 28951865c66e84efdb20065a13ecadf51cf0c0f1 Mon Sep 17 00:00:00 2001 From: ADmad Date: Mon, 3 Sep 2012 19:34:19 +0530 Subject: [PATCH 115/256] Hidden divs created by FormHelper can now be customized. --- .../Test/Case/View/Helper/FormHelperTest.php | 24 ++++++++++++++++--- .../Test/Case/View/Helper/HtmlHelperTest.php | 3 ++- .../Test/test_app/Config/htmlhelper_tags.php | 3 ++- lib/Cake/View/Helper/FormHelper.php | 4 ++-- lib/Cake/View/Helper/HtmlHelper.php | 1 + 5 files changed, 28 insertions(+), 7 deletions(-) diff --git a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php index fa7b75da4..2fd7c9866 100644 --- a/lib/Cake/Test/Case/View/Helper/FormHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/FormHelperTest.php @@ -792,14 +792,32 @@ class FormHelperTest extends CakeTestCase { $this->Form->request['_Token'] = array('key' => $key); $result = $this->Form->secure($fields); - $expected = Security::hash(serialize($fields) . Configure::read('Security.salt')); - $expected .= ':' . 'Model.valid'; + $hash = Security::hash(serialize($fields) . Configure::read('Security.salt')); + $hash .= ':' . 'Model.valid'; + $hash = urlencode($hash); $expected = array( 'div' => array('style' => 'display:none;'), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][fields]', - 'value' => urlencode($expected), 'id' => 'preg:/TokenFields\d+/' + 'value' => $hash, 'id' => 'preg:/TokenFields\d+/' + )), + array('input' => array( + 'type' => 'hidden', 'name' => 'data[_Token][unlocked]', + 'value' => '', 'id' => 'preg:/TokenUnlocked\d+/' + )), + '/div' + ); + $this->assertTags($result, $expected); + + $path = CAKE . 'Test' . DS . 'test_app' . DS . 'Config' . DS; + $this->Form->Html->loadConfig('htmlhelper_tags', $path); + $result = $this->Form->secure($fields); + $expected = array( + 'div' => array('class' => 'hidden'), + array('input' => array( + 'type' => 'hidden', 'name' => 'data[_Token][fields]', + 'value' => $hash, 'id' => 'preg:/TokenFields\d+/' )), array('input' => array( 'type' => 'hidden', 'name' => 'data[_Token][unlocked]', diff --git a/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php b/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php index fd4cb0a77..fcb299071 100644 --- a/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php +++ b/lib/Cake/Test/Case/View/Helper/HtmlHelperTest.php @@ -1863,7 +1863,8 @@ class HtmlHelperTest extends CakeTestCase { $expected = array( 'tags' => array( 'form' => 'start form', - 'formend' => 'finish form' + 'formend' => 'finish form', + 'hiddenblock' => '' ) ); $this->assertEquals($expected, $result); diff --git a/lib/Cake/Test/test_app/Config/htmlhelper_tags.php b/lib/Cake/Test/test_app/Config/htmlhelper_tags.php index abff9cdf5..850f26d12 100644 --- a/lib/Cake/Test/test_app/Config/htmlhelper_tags.php +++ b/lib/Cake/Test/test_app/Config/htmlhelper_tags.php @@ -3,6 +3,7 @@ $config = array( 'tags' => array( 'form' => 'start form', - 'formend' => 'finish form' + 'formend' => 'finish form', + 'hiddenblock' => '' ) ); \ No newline at end of file diff --git a/lib/Cake/View/Helper/FormHelper.php b/lib/Cake/View/Helper/FormHelper.php index 6431a0ad0..a1066a15d 100644 --- a/lib/Cake/View/Helper/FormHelper.php +++ b/lib/Cake/View/Helper/FormHelper.php @@ -428,7 +428,7 @@ class FormHelper extends AppHelper { $append .= $this->_csrfField(); if (!empty($append)) { - $append = $this->Html->useTag('block', ' style="display:none;"', $append); + $append = $this->Html->useTag('hiddenblock', $append); } if ($model !== false) { @@ -545,7 +545,7 @@ class FormHelper extends AppHelper { 'value' => urlencode($unlocked), 'id' => 'TokenUnlocked' . mt_rand() )); - return $this->Html->useTag('block', ' style="display:none;"', $out); + return $this->Html->useTag('hiddenblock', $out); } /** diff --git a/lib/Cake/View/Helper/HtmlHelper.php b/lib/Cake/View/Helper/HtmlHelper.php index fb53cf340..8cf545748 100644 --- a/lib/Cake/View/Helper/HtmlHelper.php +++ b/lib/Cake/View/Helper/HtmlHelper.php @@ -78,6 +78,7 @@ class HtmlHelper extends AppHelper { 'block' => '%s', 'blockstart' => '', 'blockend' => '', + 'hiddenblock' => '
    %s
    ', 'tag' => '<%s%s>%s', 'tagstart' => '<%s%s>', 'tagend' => '', From 99b798fa9a49c876721a9b6d60178f9c7e991f0c Mon Sep 17 00:00:00 2001 From: AD7six Date: Wed, 5 Sep 2012 16:43:24 +0200 Subject: [PATCH 116/256] make it possible to override all of basics.php --- lib/Cake/basics.php | 798 ++++++++++++++++++++++++-------------------- 1 file changed, 439 insertions(+), 359 deletions(-) diff --git a/lib/Cake/basics.php b/lib/Cake/basics.php index 1dc81245e..434629562 100644 --- a/lib/Cake/basics.php +++ b/lib/Cake/basics.php @@ -30,6 +30,8 @@ define('MONTH', 2592000); define('YEAR', 31536000); +if (!function_exists('config')) { + /** * Loads configuration files. Receives a set of configuration files * to load. @@ -40,24 +42,28 @@ * @return boolean Success * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#config */ -function config() { - $args = func_get_args(); - foreach ($args as $arg) { - if (file_exists(APP . 'Config' . DS . $arg . '.php')) { - include_once APP . 'Config' . DS . $arg . '.php'; + function config() { + $args = func_get_args(); + foreach ($args as $arg) { + if (file_exists(APP . 'Config' . DS . $arg . '.php')) { + include_once APP . 'Config' . DS . $arg . '.php'; - if (count($args) == 1) { - return true; - } - } else { - if (count($args) == 1) { - return false; + if (count($args) == 1) { + return true; + } + } else { + if (count($args) == 1) { + return false; + } } } + return true; } - return true; + } +if (!function_exists('debug')) { + /** * Prints out debug information about given variable. * @@ -69,18 +75,18 @@ function config() { * @link http://book.cakephp.org/2.0/en/development/debugging.html#basic-debugging * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#debug */ -function debug($var = false, $showHtml = null, $showFrom = true) { - if (Configure::read('debug') > 0) { - App::uses('Debugger', 'Utility'); - $file = ''; - $line = ''; - $lineInfo = ''; - if ($showFrom) { - $trace = Debugger::trace(array('start' => 1, 'depth' => 2, 'format' => 'array')); - $file = str_replace(array(CAKE_CORE_INCLUDE_PATH, ROOT), '', $trace[0]['file']); - $line = $trace[0]['line']; - } - $html = << 0) { + App::uses('Debugger', 'Utility'); + $file = ''; + $line = ''; + $lineInfo = ''; + if ($showFrom) { + $trace = Debugger::trace(array('start' => 1, 'depth' => 2, 'format' => 'array')); + $file = str_replace(array(CAKE_CORE_INCLUDE_PATH, ROOT), '', $trace[0]['file']); + $line = $trace[0]['line']; + } + $html = << %s
    @@ -88,32 +94,34 @@ function debug($var = false, $showHtml = null, $showFrom = true) {
     
    HTML; - $text = <<%s (line %s)', $file, $line); + if (php_sapi_name() == 'cli' || $showHtml === false) { + $template = $text; + if ($showFrom) { + $lineInfo = sprintf('%s (line %s)', $file, $line); + } } + if ($showHtml === null && $template !== $text) { + $showHtml = true; + } + $var = Debugger::exportVar($var, 25); + if ($showHtml) { + $template = $html; + $var = h($var); + if ($showFrom) { + $lineInfo = sprintf('%s (line %s)', $file, $line); + } + } + printf($template, $lineInfo, $var); } - printf($template, $lineInfo, $var); } + } if (!function_exists('sortByKey')) { @@ -151,6 +159,8 @@ if (!function_exists('sortByKey')) { } +if (!function_exists('h')) { + /** * Convenience method for htmlspecialchars. * @@ -162,36 +172,40 @@ if (!function_exists('sortByKey')) { * @return string Wrapped text * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#h */ -function h($text, $double = true, $charset = null) { - if (is_array($text)) { - $texts = array(); - foreach ($text as $k => $t) { - $texts[$k] = h($t, $double, $charset); + function h($text, $double = true, $charset = null) { + if (is_array($text)) { + $texts = array(); + foreach ($text as $k => $t) { + $texts[$k] = h($t, $double, $charset); + } + return $texts; + } elseif (is_object($text)) { + if (method_exists($text, '__toString')) { + $text = (string)$text; + } else { + $text = '(object)' . get_class($text); + } + } elseif (is_bool($text)) { + return $text; } - return $texts; - } elseif (is_object($text)) { - if (method_exists($text, '__toString')) { - $text = (string)$text; - } else { - $text = '(object)' . get_class($text); + + static $defaultCharset = false; + if ($defaultCharset === false) { + $defaultCharset = Configure::read('App.encoding'); + if ($defaultCharset === null) { + $defaultCharset = 'UTF-8'; + } } - } elseif (is_bool($text)) { - return $text; + if (is_string($double)) { + $charset = $double; + } + return htmlspecialchars($text, ENT_QUOTES, ($charset) ? $charset : $defaultCharset, $double); } - static $defaultCharset = false; - if ($defaultCharset === false) { - $defaultCharset = Configure::read('App.encoding'); - if ($defaultCharset === null) { - $defaultCharset = 'UTF-8'; - } - } - if (is_string($double)) { - $charset = $double; - } - return htmlspecialchars($text, ENT_QUOTES, ($charset) ? $charset : $defaultCharset, $double); } +if (!function_exists('pluginSplit')) { + /** * Splits a dot syntax plugin name into its plugin and classname. * If $name does not have a dot, then index 0 will be null. @@ -204,17 +218,21 @@ function h($text, $double = true, $charset = null) { * @return array Array with 2 indexes. 0 => plugin name, 1 => classname * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#pluginSplit */ -function pluginSplit($name, $dotAppend = false, $plugin = null) { - if (strpos($name, '.') !== false) { - $parts = explode('.', $name, 2); - if ($dotAppend) { - $parts[0] .= '.'; + function pluginSplit($name, $dotAppend = false, $plugin = null) { + if (strpos($name, '.') !== false) { + $parts = explode('.', $name, 2); + if ($dotAppend) { + $parts[0] .= '.'; + } + return $parts; } - return $parts; + return array($plugin, $name); } - return array($plugin, $name); + } +if (!function_exists('pr')) { + /** * Print_r convenience function, which prints out
     tags around
      * the output of given array. Similar to debug().
    @@ -223,14 +241,18 @@ function pluginSplit($name, $dotAppend = false, $plugin = null) {
      * @param array $var Variable to print out
      * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#pr
      */
    -function pr($var) {
    -	if (Configure::read('debug') > 0) {
    -		echo '
    ';
    -		print_r($var);
    -		echo '
    '; + function pr($var) { + if (Configure::read('debug') > 0) { + echo '
    ';
    +			print_r($var);
    +			echo '
    '; + } } + } +if (!function_exists('am')) { + /** * Merge a group of arrays * @@ -241,18 +263,22 @@ function pr($var) { * @return array All array parameters merged into one * @link http://book.cakephp.org/2.0/en/development/debugging.html#am */ -function am() { - $r = array(); - $args = func_get_args(); - foreach ($args as $a) { - if (!is_array($a)) { - $a = array($a); + function am() { + $r = array(); + $args = func_get_args(); + foreach ($args as $a) { + if (!is_array($a)) { + $a = array($a); + } + $r = array_merge($r, $a); } - $r = array_merge($r, $a); + return $r; } - return $r; + } +if (!function_exists('env')) { + /** * Gets an environment variable from available sources, and provides emulation * for unsupported or inconsistent environment variables (i.e. DOCUMENT_ROOT on @@ -263,105 +289,109 @@ function am() { * @return string Environment variable setting. * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#env */ -function env($key) { - if ($key === 'HTTPS') { - if (isset($_SERVER['HTTPS'])) { - return (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off'); - } - return (strpos(env('SCRIPT_URI'), 'https://') === 0); - } - - if ($key === 'SCRIPT_NAME') { - if (env('CGI_MODE') && isset($_ENV['SCRIPT_URL'])) { - $key = 'SCRIPT_URL'; - } - } - - $val = null; - if (isset($_SERVER[$key])) { - $val = $_SERVER[$key]; - } elseif (isset($_ENV[$key])) { - $val = $_ENV[$key]; - } elseif (getenv($key) !== false) { - $val = getenv($key); - } - - if ($key === 'REMOTE_ADDR' && $val === env('SERVER_ADDR')) { - $addr = env('HTTP_PC_REMOTE_ADDR'); - if ($addr !== null) { - $val = $addr; - } - } - - if ($val !== null) { - return $val; - } - - switch ($key) { - case 'SCRIPT_FILENAME': - if (defined('SERVER_IIS') && SERVER_IIS === true) { - return str_replace('\\\\', '\\', env('PATH_TRANSLATED')); + function env($key) { + if ($key === 'HTTPS') { + if (isset($_SERVER['HTTPS'])) { + return (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off'); } - break; - case 'DOCUMENT_ROOT': - $name = env('SCRIPT_NAME'); - $filename = env('SCRIPT_FILENAME'); - $offset = 0; - if (!strpos($name, '.php')) { - $offset = 4; - } - return substr($filename, 0, -(strlen($name) + $offset)); - break; - case 'PHP_SELF': - return str_replace(env('DOCUMENT_ROOT'), '', env('SCRIPT_FILENAME')); - break; - case 'CGI_MODE': - return (PHP_SAPI === 'cgi'); - break; - case 'HTTP_BASE': - $host = env('HTTP_HOST'); - $parts = explode('.', $host); - $count = count($parts); + return (strpos(env('SCRIPT_URI'), 'https://') === 0); + } - if ($count === 1) { - return '.' . $host; - } elseif ($count === 2) { - return '.' . $host; - } elseif ($count === 3) { - $gTLD = array( - 'aero', - 'asia', - 'biz', - 'cat', - 'com', - 'coop', - 'edu', - 'gov', - 'info', - 'int', - 'jobs', - 'mil', - 'mobi', - 'museum', - 'name', - 'net', - 'org', - 'pro', - 'tel', - 'travel', - 'xxx' - ); - if (in_array($parts[1], $gTLD)) { - return '.' . $host; + if ($key === 'SCRIPT_NAME') { + if (env('CGI_MODE') && isset($_ENV['SCRIPT_URL'])) { + $key = 'SCRIPT_URL'; + } + } + + $val = null; + if (isset($_SERVER[$key])) { + $val = $_SERVER[$key]; + } elseif (isset($_ENV[$key])) { + $val = $_ENV[$key]; + } elseif (getenv($key) !== false) { + $val = getenv($key); + } + + if ($key === 'REMOTE_ADDR' && $val === env('SERVER_ADDR')) { + $addr = env('HTTP_PC_REMOTE_ADDR'); + if ($addr !== null) { + $val = $addr; + } + } + + if ($val !== null) { + return $val; + } + + switch ($key) { + case 'SCRIPT_FILENAME': + if (defined('SERVER_IIS') && SERVER_IIS === true) { + return str_replace('\\\\', '\\', env('PATH_TRANSLATED')); } - } - array_shift($parts); - return '.' . implode('.', $parts); - break; + break; + case 'DOCUMENT_ROOT': + $name = env('SCRIPT_NAME'); + $filename = env('SCRIPT_FILENAME'); + $offset = 0; + if (!strpos($name, '.php')) { + $offset = 4; + } + return substr($filename, 0, -(strlen($name) + $offset)); + break; + case 'PHP_SELF': + return str_replace(env('DOCUMENT_ROOT'), '', env('SCRIPT_FILENAME')); + break; + case 'CGI_MODE': + return (PHP_SAPI === 'cgi'); + break; + case 'HTTP_BASE': + $host = env('HTTP_HOST'); + $parts = explode('.', $host); + $count = count($parts); + + if ($count === 1) { + return '.' . $host; + } elseif ($count === 2) { + return '.' . $host; + } elseif ($count === 3) { + $gTLD = array( + 'aero', + 'asia', + 'biz', + 'cat', + 'com', + 'coop', + 'edu', + 'gov', + 'info', + 'int', + 'jobs', + 'mil', + 'mobi', + 'museum', + 'name', + 'net', + 'org', + 'pro', + 'tel', + 'travel', + 'xxx' + ); + if (in_array($parts[1], $gTLD)) { + return '.' . $host; + } + } + array_shift($parts); + return '.' . implode('.', $parts); + break; + } + return null; } - return null; + } +if (!function_exists('cache')) { + /** * Reads/writes temporary data to cache files or session. * @@ -372,48 +402,52 @@ function env($key) { * @return mixed The contents of the temporary file. * @deprecated Please use Cache::write() instead */ -function cache($path, $data = null, $expires = '+1 day', $target = 'cache') { - if (Configure::read('Cache.disable')) { - return null; - } - $now = time(); - - if (!is_numeric($expires)) { - $expires = strtotime($expires, $now); - } - - switch (strtolower($target)) { - case 'cache': - $filename = CACHE . $path; - break; - case 'public': - $filename = WWW_ROOT . $path; - break; - case 'tmp': - $filename = TMP . $path; - break; - } - $timediff = $expires - $now; - $filetime = false; - - if (file_exists($filename)) { - $filetime = @filemtime($filename); - } - - if ($data === null) { - if (file_exists($filename) && $filetime !== false) { - if ($filetime + $timediff < $now) { - @unlink($filename); - } else { - $data = @file_get_contents($filename); - } + function cache($path, $data = null, $expires = '+1 day', $target = 'cache') { + if (Configure::read('Cache.disable')) { + return null; } - } elseif (is_writable(dirname($filename))) { - @file_put_contents($filename, $data, LOCK_EX); + $now = time(); + + if (!is_numeric($expires)) { + $expires = strtotime($expires, $now); + } + + switch (strtolower($target)) { + case 'cache': + $filename = CACHE . $path; + break; + case 'public': + $filename = WWW_ROOT . $path; + break; + case 'tmp': + $filename = TMP . $path; + break; + } + $timediff = $expires - $now; + $filetime = false; + + if (file_exists($filename)) { + $filetime = @filemtime($filename); + } + + if ($data === null) { + if (file_exists($filename) && $filetime !== false) { + if ($filetime + $timediff < $now) { + @unlink($filename); + } else { + $data = @file_get_contents($filename); + } + } + } elseif (is_writable(dirname($filename))) { + @file_put_contents($filename, $data, LOCK_EX); + } + return $data; } - return $data; + } +if (!function_exists('clearCache')) { + /** * Used to delete files in the cache directories, or clear contents of cache directories * @@ -424,58 +458,62 @@ function cache($path, $data = null, $expires = '+1 day', $target = 'cache') { * @param string $ext The file extension you are deleting * @return true if files found and deleted false otherwise */ -function clearCache($params = null, $type = 'views', $ext = '.php') { - if (is_string($params) || $params === null) { - $params = preg_replace('/\/\//', '/', $params); - $cache = CACHE . $type . DS . $params; + function clearCache($params = null, $type = 'views', $ext = '.php') { + if (is_string($params) || $params === null) { + $params = preg_replace('/\/\//', '/', $params); + $cache = CACHE . $type . DS . $params; - if (is_file($cache . $ext)) { - @unlink($cache . $ext); - return true; - } elseif (is_dir($cache)) { - $files = glob($cache . '*'); + if (is_file($cache . $ext)) { + @unlink($cache . $ext); + return true; + } elseif (is_dir($cache)) { + $files = glob($cache . '*'); - if ($files === false) { - return false; - } + if ($files === false) { + return false; + } - foreach ($files as $file) { - if (is_file($file) && strrpos($file, DS . 'empty') !== strlen($file) - 6) { - @unlink($file); + foreach ($files as $file) { + if (is_file($file) && strrpos($file, DS . 'empty') !== strlen($file) - 6) { + @unlink($file); + } } - } - return true; - } else { - $cache = array( - CACHE . $type . DS . '*' . $params . $ext, - CACHE . $type . DS . '*' . $params . '_*' . $ext - ); - $files = array(); - while ($search = array_shift($cache)) { - $results = glob($search); - if ($results !== false) { - $files = array_merge($files, $results); + return true; + } else { + $cache = array( + CACHE . $type . DS . '*' . $params . $ext, + CACHE . $type . DS . '*' . $params . '_*' . $ext + ); + $files = array(); + while ($search = array_shift($cache)) { + $results = glob($search); + if ($results !== false) { + $files = array_merge($files, $results); + } } - } - if (empty($files)) { - return false; - } - foreach ($files as $file) { - if (is_file($file) && strrpos($file, DS . 'empty') !== strlen($file) - 6) { - @unlink($file); + if (empty($files)) { + return false; } + foreach ($files as $file) { + if (is_file($file) && strrpos($file, DS . 'empty') !== strlen($file) - 6) { + @unlink($file); + } + } + return true; + } + } elseif (is_array($params)) { + foreach ($params as $file) { + clearCache($file, $type, $ext); } return true; } - } elseif (is_array($params)) { - foreach ($params as $file) { - clearCache($file, $type, $ext); - } - return true; + return false; } - return false; + } +if (!function_exists('stripslashes_deep')) { + /** * Recursively strips slashes from all values in an array * @@ -483,17 +521,21 @@ function clearCache($params = null, $type = 'views', $ext = '.php') { * @return mixed What is returned from calling stripslashes * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#stripslashes_deep */ -function stripslashes_deep($values) { - if (is_array($values)) { - foreach ($values as $key => $value) { - $values[$key] = stripslashes_deep($value); + function stripslashes_deep($values) { + if (is_array($values)) { + foreach ($values as $key => $value) { + $values[$key] = stripslashes_deep($value); + } + } else { + $values = stripslashes($values); } - } else { - $values = stripslashes($values); + return $values; } - return $values; + } +if (!function_exists('__')) { + /** * Returns a translated string if one is found; Otherwise, the submitted message. * @@ -502,21 +544,25 @@ function stripslashes_deep($values) { * @return mixed translated string * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__ */ -function __($singular, $args = null) { - if (!$singular) { - return; + function __($singular, $args = null) { + if (!$singular) { + return; + } + + App::uses('I18n', 'I18n'); + $translated = I18n::translate($singular); + if ($args === null) { + return $translated; + } elseif (!is_array($args)) { + $args = array_slice(func_get_args(), 1); + } + return vsprintf($translated, $args); } - App::uses('I18n', 'I18n'); - $translated = I18n::translate($singular); - if ($args === null) { - return $translated; - } elseif (!is_array($args)) { - $args = array_slice(func_get_args(), 1); - } - return vsprintf($translated, $args); } +if (!function_exists('__n')) { + /** * Returns correct plural form of message identified by $singular and $plural for count $count. * Some languages have more than one form for plural messages dependent on the count. @@ -528,21 +574,25 @@ function __($singular, $args = null) { * @return mixed plural form of translated string * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__n */ -function __n($singular, $plural, $count, $args = null) { - if (!$singular) { - return; + function __n($singular, $plural, $count, $args = null) { + if (!$singular) { + return; + } + + App::uses('I18n', 'I18n'); + $translated = I18n::translate($singular, $plural, null, 6, $count); + if ($args === null) { + return $translated; + } elseif (!is_array($args)) { + $args = array_slice(func_get_args(), 3); + } + return vsprintf($translated, $args); } - App::uses('I18n', 'I18n'); - $translated = I18n::translate($singular, $plural, null, 6, $count); - if ($args === null) { - return $translated; - } elseif (!is_array($args)) { - $args = array_slice(func_get_args(), 3); - } - return vsprintf($translated, $args); } +if (!function_exists('__d')) { + /** * Allows you to override the current domain for a single message lookup. * @@ -552,20 +602,24 @@ function __n($singular, $plural, $count, $args = null) { * @return translated string * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__d */ -function __d($domain, $msg, $args = null) { - if (!$msg) { - return; + function __d($domain, $msg, $args = null) { + if (!$msg) { + return; + } + App::uses('I18n', 'I18n'); + $translated = I18n::translate($msg, null, $domain); + if ($args === null) { + return $translated; + } elseif (!is_array($args)) { + $args = array_slice(func_get_args(), 2); + } + return vsprintf($translated, $args); } - App::uses('I18n', 'I18n'); - $translated = I18n::translate($msg, null, $domain); - if ($args === null) { - return $translated; - } elseif (!is_array($args)) { - $args = array_slice(func_get_args(), 2); - } - return vsprintf($translated, $args); + } +if (!function_exists('__dn')) { + /** * Allows you to override the current domain for a single plural message lookup. * Returns correct plural form of message identified by $singular and $plural for count $count @@ -579,20 +633,24 @@ function __d($domain, $msg, $args = null) { * @return plural form of translated string * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__dn */ -function __dn($domain, $singular, $plural, $count, $args = null) { - if (!$singular) { - return; + function __dn($domain, $singular, $plural, $count, $args = null) { + if (!$singular) { + return; + } + App::uses('I18n', 'I18n'); + $translated = I18n::translate($singular, $plural, $domain, 6, $count); + if ($args === null) { + return $translated; + } elseif (!is_array($args)) { + $args = array_slice(func_get_args(), 4); + } + return vsprintf($translated, $args); } - App::uses('I18n', 'I18n'); - $translated = I18n::translate($singular, $plural, $domain, 6, $count); - if ($args === null) { - return $translated; - } elseif (!is_array($args)) { - $args = array_slice(func_get_args(), 4); - } - return vsprintf($translated, $args); + } +if (!function_exists('__dc')) { + /** * Allows you to override the current domain for a single message lookup. * It also allows you to specify a category. @@ -617,20 +675,24 @@ function __dn($domain, $singular, $plural, $count, $args = null) { * @return translated string * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__dc */ -function __dc($domain, $msg, $category, $args = null) { - if (!$msg) { - return; + function __dc($domain, $msg, $category, $args = null) { + if (!$msg) { + return; + } + App::uses('I18n', 'I18n'); + $translated = I18n::translate($msg, null, $domain, $category); + if ($args === null) { + return $translated; + } elseif (!is_array($args)) { + $args = array_slice(func_get_args(), 3); + } + return vsprintf($translated, $args); } - App::uses('I18n', 'I18n'); - $translated = I18n::translate($msg, null, $domain, $category); - if ($args === null) { - return $translated; - } elseif (!is_array($args)) { - $args = array_slice(func_get_args(), 3); - } - return vsprintf($translated, $args); + } +if (!function_exists('__dcn')) { + /** * Allows you to override the current domain for a single plural message lookup. * It also allows you to specify a category. @@ -659,20 +721,24 @@ function __dc($domain, $msg, $category, $args = null) { * @return plural form of translated string * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__dcn */ -function __dcn($domain, $singular, $plural, $count, $category, $args = null) { - if (!$singular) { - return; + function __dcn($domain, $singular, $plural, $count, $category, $args = null) { + if (!$singular) { + return; + } + App::uses('I18n', 'I18n'); + $translated = I18n::translate($singular, $plural, $domain, $category, $count); + if ($args === null) { + return $translated; + } elseif (!is_array($args)) { + $args = array_slice(func_get_args(), 5); + } + return vsprintf($translated, $args); } - App::uses('I18n', 'I18n'); - $translated = I18n::translate($singular, $plural, $domain, $category, $count); - if ($args === null) { - return $translated; - } elseif (!is_array($args)) { - $args = array_slice(func_get_args(), 5); - } - return vsprintf($translated, $args); + } +if (!function_exists('__c')) { + /** * The category argument allows a specific category of the locale settings to be used for fetching a message. * Valid categories are: LC_CTYPE, LC_NUMERIC, LC_TIME, LC_COLLATE, LC_MONETARY, LC_MESSAGES and LC_ALL. @@ -693,20 +759,24 @@ function __dcn($domain, $singular, $plural, $count, $category, $args = null) { * @return translated string * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#__c */ -function __c($msg, $category, $args = null) { - if (!$msg) { - return; + function __c($msg, $category, $args = null) { + if (!$msg) { + return; + } + App::uses('I18n', 'I18n'); + $translated = I18n::translate($msg, null, null, $category); + if ($args === null) { + return $translated; + } elseif (!is_array($args)) { + $args = array_slice(func_get_args(), 2); + } + return vsprintf($translated, $args); } - App::uses('I18n', 'I18n'); - $translated = I18n::translate($msg, null, null, $category); - if ($args === null) { - return $translated; - } elseif (!is_array($args)) { - $args = array_slice(func_get_args(), 2); - } - return vsprintf($translated, $args); + } +if (!function_exists('LogError')) { + /** * Shortcut to Log::write. * @@ -714,13 +784,17 @@ function __c($msg, $category, $args = null) { * @return void * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#LogError */ -function LogError($message) { - App::uses('CakeLog', 'Log'); - $bad = array("\n", "\r", "\t"); - $good = ' '; - CakeLog::write('error', str_replace($bad, $good, $message)); + function LogError($message) { + App::uses('CakeLog', 'Log'); + $bad = array("\n", "\r", "\t"); + $good = ' '; + CakeLog::write('error', str_replace($bad, $good, $message)); + } + } +if (!function_exists('fileExistsInPath')) { + /** * Searches include path for files. * @@ -728,20 +802,24 @@ function LogError($message) { * @return Full path to file if exists, otherwise false * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#fileExistsInPath */ -function fileExistsInPath($file) { - $paths = explode(PATH_SEPARATOR, ini_get('include_path')); - foreach ($paths as $path) { - $fullPath = $path . DS . $file; + function fileExistsInPath($file) { + $paths = explode(PATH_SEPARATOR, ini_get('include_path')); + foreach ($paths as $path) { + $fullPath = $path . DS . $file; - if (file_exists($fullPath)) { - return $fullPath; - } elseif (file_exists($file)) { - return $file; + if (file_exists($fullPath)) { + return $fullPath; + } elseif (file_exists($file)) { + return $file; + } } + return false; } - return false; + } +if (!function_exists('convertSlash')) { + /** * Convert forward slashes to underscores and removes first and last underscores in a string * @@ -749,9 +827,11 @@ function fileExistsInPath($file) { * @return string with underscore remove from start and end of string * @link http://book.cakephp.org/2.0/en/core-libraries/global-constants-and-functions.html#convertSlash */ -function convertSlash($string) { - $string = trim($string, '/'); - $string = preg_replace('/\/\//', '/', $string); - $string = str_replace('/', '_', $string); - return $string; + function convertSlash($string) { + $string = trim($string, '/'); + $string = preg_replace('/\/\//', '/', $string); + $string = str_replace('/', '_', $string); + return $string; + } + } From 37068539bdddbe2558d0aa597b30eaa0e24378d4 Mon Sep 17 00:00:00 2001 From: euromark Date: Mon, 10 Sep 2012 10:23:52 +0200 Subject: [PATCH 117/256] allow Folder to merge recursivly and add scheme option --- lib/Cake/Test/Case/Utility/FolderTest.php | 346 +++++++++++++++++----- lib/Cake/Utility/Folder.php | 45 ++- 2 files changed, 307 insertions(+), 84 deletions(-) diff --git a/lib/Cake/Test/Case/Utility/FolderTest.php b/lib/Cake/Test/Case/Utility/FolderTest.php index 76ee08af4..0d86286cb 100644 --- a/lib/Cake/Test/Case/Utility/FolderTest.php +++ b/lib/Cake/Test/Case/Utility/FolderTest.php @@ -29,11 +29,16 @@ class FolderTest extends CakeTestCase { protected static $_tmp = array(); /** - * Save the directory names in TMP + * Save the directory names in TMP and make sure default directories exist * * @return void */ public static function setUpBeforeClass() { + $dirs = array('cache', 'logs', 'sessions', 'tests'); + foreach ($dirs as $dir) { + new Folder(TMP . $dir, true); + } + foreach (scandir(TMP) as $file) { if (is_dir(TMP . $file) && !in_array($file, array('.', '..'))) { self::$_tmp[] = $file; @@ -803,6 +808,62 @@ class FolderTest extends CakeTestCase { /** * testCopy method * + * Verify that subdirectories existing in both destination and source directory + * are merged recursivly. + * + */ + public function testCopy() { + extract($this->_setupFilesystem()); + + $Folder = new Folder($folderOne); + $result = $Folder->copy($folderThree); + $this->assertTrue($result); + $this->assertTrue(file_exists($folderThree . DS . 'file1.php')); + $this->assertTrue(file_exists($folderThree . DS . 'folderA' . DS . 'fileA.php')); + + $Folder = new Folder($folderTwo); + $result = $Folder->copy($folderThree); + $this->assertTrue($result); + $this->assertTrue(file_exists($folderThree . DS . 'file1.php')); + $this->assertTrue(file_exists($folderThree . DS . 'file2.php')); + $this->assertTrue(file_exists($folderThree . DS . 'folderA' . DS . 'fileA.php')); + $this->assertTrue(file_exists($folderThree . DS . 'folderB' . DS . 'fileB.php')); + + $Folder = new Folder($path); + $Folder->delete(); + } + +/** + * testCopyWithMerge method + * + * Verify that subdirectories existing in both destination and source directory + * are merged recursivly. + * + */ + public function testCopyWithMerge() { + extract($this->_setupFilesystem()); + + $Folder = new Folder($folderOne); + $result = $Folder->copy($folderThree); + $this->assertTrue($result); + $this->assertTrue(file_exists($folderThree . DS . 'file1.php')); + $this->assertTrue(file_exists($folderThree . DS . 'folderA' . DS . 'fileA.php')); + + $Folder = new Folder($folderTwo); + $result = $Folder->copy(array('to' => $folderThree, 'scheme' => Folder::MERGE)); + $this->assertTrue($result); + $this->assertTrue(file_exists($folderThree . DS . 'file1.php')); + $this->assertTrue(file_exists($folderThree . DS . 'file2.php')); + $this->assertTrue(file_exists($folderThree . DS . 'folderA' . DS . 'fileA.php')); + $this->assertTrue(file_exists($folderThree . DS . 'folderB' . DS . 'fileB.php')); + + $Folder = new Folder($path); + $Folder->delete(); + } + +/** + * testCopyWithSkip method + * * Verify that directories and files are copied recursively * even if the destination directory already exists. * Subdirectories existing in both destination and source directory @@ -810,125 +871,254 @@ class FolderTest extends CakeTestCase { * * @return void */ - public function testCopy() { - $path = TMP . 'folder_test'; - $folderOne = $path . DS . 'folder1'; - $folderTwo = $folderOne . DS . 'folder2'; - $folderThree = $path . DS . 'folder3'; - $fileOne = $folderOne . DS . 'file1.php'; - $fileTwo = $folderTwo . DS . 'file2.php'; + public function testCopyWithSkip() { + extract($this->_setupFilesystem()); + + $Folder = new Folder($folderOne); + $result = $Folder->copy(array('to' => $folderTwo, 'scheme' => Folder::SKIP)); + $this->assertTrue($result); + $this->assertTrue(file_exists($folderTwo . DS . 'file1.php')); + $this->assertTrue(file_exists($folderTwo . DS . 'folderA' . DS . 'fileA.php')); + + $Folder = new Folder($folderTwo); + $Folder->delete(); + + $Folder = new Folder($folderOne); + $result = $Folder->copy(array('to' => $folderTwo, 'scheme' => Folder::SKIP)); + $this->assertTrue($result); + $this->assertTrue(file_exists($folderTwo . DS . 'file1.php')); + $this->assertTrue(file_exists($folderTwo . DS . 'folderA' . DS . 'fileA.php')); + + $Folder = new Folder($folderTwo); + $Folder->delete(); - new Folder($path, true); - new Folder($folderOne, true); new Folder($folderTwo, true); - new Folder($folderThree, true); - touch($fileOne); - touch($fileTwo); + new Folder($folderTwo . DS . 'folderB', true); + file_put_contents($folderTwo . DS . 'file2.php', 'touched'); + file_put_contents($folderTwo . DS . 'folderB' . DS . 'fileB.php', 'untouched'); - $Folder = new Folder($folderOne); - $result = $Folder->copy($folderThree); + $Folder = new Folder($folderTwo); + $result = $Folder->copy(array('to' => $folderThree, 'scheme' => Folder::SKIP)); $this->assertTrue($result); - $this->assertTrue(file_exists($folderThree . DS . 'file1.php')); - $this->assertTrue(file_exists($folderThree . DS . 'folder2' . DS . 'file2.php')); - - $Folder = new Folder($folderThree); - $Folder->delete(); - - $Folder = new Folder($folderOne); - $result = $Folder->copy($folderThree); - $this->assertTrue($result); - $this->assertTrue(file_exists($folderThree . DS . 'file1.php')); - $this->assertTrue(file_exists($folderThree . DS . 'folder2' . DS . 'file2.php')); - - $Folder = new Folder($folderThree); - $Folder->delete(); - - new Folder($folderThree, true); - new Folder($folderThree . DS . 'folder2', true); - file_put_contents($folderThree . DS . 'folder2' . DS . 'file2.php', 'untouched'); - - $Folder = new Folder($folderOne); - $result = $Folder->copy($folderThree); - $this->assertTrue($result); - $this->assertTrue(file_exists($folderThree . DS . 'file1.php')); - $this->assertEquals('untouched', file_get_contents($folderThree . DS . 'folder2' . DS . 'file2.php')); + $this->assertTrue(file_exists($folderThree . DS . 'file2.php')); + $this->assertEquals('touched', file_get_contents($folderThree . DS . 'file2.php')); + $this->assertEquals('untouched', file_get_contents($folderThree . DS . 'folderB' . DS . 'fileB.php')); $Folder = new Folder($path); $Folder->delete(); } +/** + * testCopyWithOverwrite + * + * Verify that subdirectories existing in both destination and source directory + * are overwritten/replaced recursivly. + * + * $path: folder_test/ + * $folderOne: folder_test/folder1/ + * - file1.php + * $folderTwo: folder_test/folder2/ + * - file2.php + * $folderThree: folder_test/folder1/folder3/ + * - file3.php + * $folderFour: folder_test/folder2/folder4/ + * - file4.php + * $folderThree: folder_test/folder5/ + */ + function testCopyWithOverwrite() { + extract($this->_setupFilesystem()); + + $Folder = new Folder($folderOne); + $result = $Folder->copy(array('to' => $folderThree, 'scheme' => Folder::OVERWRITE)); + + $this->assertTrue(file_exists($folderThree . DS . 'file1.php')); + $this->assertTrue(file_exists($folderThree . DS . 'folderA' . DS . 'fileA.php')); + + $Folder = new Folder($folderTwo); + $result = $Folder->copy(array('to' => $folderThree, 'scheme' => Folder::OVERWRITE)); + $this->assertTrue($result); + + $this->assertTrue(file_exists($folderThree . DS . 'folderA' . DS . 'fileA.php')); + + $Folder = new Folder($folderOne); + unlink($fileOneA); + $result = $Folder->copy(array('to' => $folderThree, 'scheme' => Folder::OVERWRITE)); + $this->assertTrue($result); + + $this->assertTrue(file_exists($folderThree . DS . 'file1.php')); + $this->assertTrue(file_exists($folderThree . DS . 'file2.php')); + $this->assertTrue(!file_exists($folderThree . DS . 'folderA' . DS . 'fileA.php')); + $this->assertTrue(file_exists($folderThree . DS . 'folderB' . DS . 'fileB.php')); + + $Folder = new Folder($path); + $Folder->delete(); + } + +/** + * Setup filesystem for copy tests + * + * @return void + */ + protected function _setupFilesystem() { + $path = TMP . 'folder_test'; + + $folderOne = $path . DS . 'folder1'; + $folderOneA = $folderOne . DS . 'folderA'; + $folderTwo = $path . DS . 'folder2'; + $folderTwoB = $folderTwo . DS . 'folderB'; + $folderThree = $path . DS . 'folder3'; + + $fileOne = $folderOne . DS . 'file1.php'; + $fileTwo = $folderTwo . DS . 'file2.php'; + $fileOneA = $folderOneA . DS . 'fileA.php'; + $fileTwoB = $folderTwoB . DS . 'fileB.php'; + + new Folder($path, true); + new Folder($folderOne, true); + new Folder($folderOneA, true); + new Folder($folderTwo, true); + new Folder($folderTwoB, true); + new Folder($folderThree, true); + touch($fileOne); + touch($fileTwo); + touch($fileOneA); + touch($fileTwoB); + + return compact( + 'path', + 'folderOne', 'folderOneA', 'folderTwo', 'folderTwoB', 'folderThree', + 'fileOne', 'fileOneA', 'fileTwo', 'fileTwoB'); + } + /** * testMove method * * Verify that directories and files are moved recursively * even if the destination directory already exists. * Subdirectories existing in both destination and source directory - * are skipped and not merged or overwritten. + * are merged recursivly. * * @return void */ public function testMove() { - $path = TMP . 'folder_test'; - $folderOne = $path . DS . 'folder1'; - $folderTwo = $folderOne . DS . 'folder2'; - $folderThree = $path . DS . 'folder3'; - $fileOne = $folderOne . DS . 'file1.php'; - $fileTwo = $folderTwo . DS . 'file2.php'; - - new Folder($path, true); - new Folder($folderOne, true); - new Folder($folderTwo, true); - new Folder($folderThree, true); - touch($fileOne); - touch($fileTwo); + extract($this->_setupFilesystem()); $Folder = new Folder($folderOne); - $result = $Folder->move($folderThree); + $result = $Folder->move($folderTwo); $this->assertTrue($result); - $this->assertTrue(file_exists($folderThree . DS . 'file1.php')); - $this->assertTrue(is_dir($folderThree . DS . 'folder2')); - $this->assertTrue(file_exists($folderThree . DS . 'folder2' . DS . 'file2.php')); + $this->assertTrue(file_exists($folderTwo . DS . 'file1.php')); + $this->assertTrue(is_dir($folderTwo . DS . 'folderB')); + $this->assertTrue(file_exists($folderTwo . DS . 'folderB' . DS . 'fileB.php')); $this->assertFalse(file_exists($fileOne)); - $this->assertFalse(file_exists($folderTwo)); - $this->assertFalse(file_exists($fileTwo)); + $this->assertTrue(file_exists($folderTwo . DS . 'folderA')); + $this->assertFalse(file_exists($folderOneA)); + $this->assertFalse(file_exists($fileOneA)); - $Folder = new Folder($folderThree); + $Folder = new Folder($folderTwo); $Folder->delete(); new Folder($folderOne, true); - new Folder($folderTwo, true); + new Folder($folderOneA, true); touch($fileOne); - touch($fileTwo); + touch($fileOneA); $Folder = new Folder($folderOne); - $result = $Folder->move($folderThree); + $result = $Folder->move($folderTwo); $this->assertTrue($result); - $this->assertTrue(file_exists($folderThree . DS . 'file1.php')); - $this->assertTrue(is_dir($folderThree . DS . 'folder2')); - $this->assertTrue(file_exists($folderThree . DS . 'folder2' . DS . 'file2.php')); + $this->assertTrue(file_exists($folderTwo . DS . 'file1.php')); + $this->assertTrue(is_dir($folderTwo . DS . 'folderA')); + $this->assertTrue(file_exists($folderTwo . DS . 'folderA' . DS . 'fileA.php')); $this->assertFalse(file_exists($fileOne)); - $this->assertFalse(file_exists($folderTwo)); - $this->assertFalse(file_exists($fileTwo)); + $this->assertFalse(file_exists($folderOneA)); + $this->assertFalse(file_exists($fileOneA)); - $Folder = new Folder($folderThree); + $Folder = new Folder($folderTwo); $Folder->delete(); new Folder($folderOne, true); + new Folder($folderOneA, true); new Folder($folderTwo, true); - new Folder($folderThree, true); - new Folder($folderThree . DS . 'folder2', true); + new Folder($folderTwoB, true); touch($fileOne); - touch($fileTwo); - file_put_contents($folderThree . DS . 'folder2' . DS . 'file2.php', 'untouched'); + touch($fileOneA); + new Folder($folderOne . DS . 'folderB', true); + touch($folderOne . DS . 'folderB' . DS . 'fileB.php'); + file_put_contents($folderTwoB . DS . 'fileB.php', 'untouched'); $Folder = new Folder($folderOne); - $result = $Folder->move($folderThree); + $result = $Folder->move($folderTwo); $this->assertTrue($result); - $this->assertTrue(file_exists($folderThree . DS . 'file1.php')); - $this->assertEquals('untouched', file_get_contents($folderThree . DS . 'folder2' . DS . 'file2.php')); + $this->assertTrue(file_exists($folderTwo . DS . 'file1.php')); + $this->assertEquals('', file_get_contents($folderTwoB . DS . 'fileB.php')); $this->assertFalse(file_exists($fileOne)); - $this->assertFalse(file_exists($folderTwo)); - $this->assertFalse(file_exists($fileTwo)); + $this->assertFalse(file_exists($folderOneA)); + $this->assertFalse(file_exists($fileOneA)); + + $Folder = new Folder($path); + $Folder->delete(); + } + +/** + * testMoveWithSkip method + * + * Verify that directories and files are moved recursively + * even if the destination directory already exists. + * Subdirectories existing in both destination and source directory + * are skipped and not merged or overwritten. + * + * @return void + */ + public function testMoveWithSkip() { + extract($this->_setupFilesystem()); + + $Folder = new Folder($folderOne); + $result = $Folder->move(array('to' => $folderTwo, 'scheme' => Folder::SKIP)); + $this->assertTrue($result); + $this->assertTrue(file_exists($folderTwo . DS . 'file1.php')); + $this->assertTrue(is_dir($folderTwo . DS . 'folderB')); + $this->assertTrue(file_exists($folderTwoB . DS . 'fileB.php')); + $this->assertFalse(file_exists($fileOne)); + $this->assertFalse(file_exists($folderOneA)); + $this->assertFalse(file_exists($fileOneA)); + + $Folder = new Folder($folderTwo); + $Folder->delete(); + + new Folder($folderOne, true); + new Folder($folderOneA, true); + new Folder($folderTwo, true); + touch($fileOne); + touch($fileOneA); + + $Folder = new Folder($folderOne); + $result = $Folder->move(array('to' => $folderTwo, 'scheme' => Folder::SKIP)); + $this->assertTrue($result); + $this->assertTrue(file_exists($folderTwo . DS . 'file1.php')); + $this->assertTrue(is_dir($folderTwo . DS . 'folderA')); + $this->assertTrue(file_exists($folderTwo . DS . 'folderA' . DS . 'fileA.php')); + $this->assertFalse(file_exists($fileOne)); + $this->assertFalse(file_exists($folderOneA)); + $this->assertFalse(file_exists($fileOneA)); + + $Folder = new Folder($folderTwo); + $Folder->delete(); + + new Folder($folderOne, true); + new Folder($folderOneA, true); + new Folder($folderTwo, true); + new Folder($folderTwoB, true); + touch($fileOne); + touch($fileOneA); + file_put_contents($folderTwoB . DS . 'fileB.php', 'untouched'); + + $Folder = new Folder($folderOne); + $result = $Folder->move(array('to' => $folderTwo, 'scheme' => Folder::SKIP)); + $this->assertTrue($result); + $this->assertTrue(file_exists($folderTwo . DS . 'file1.php')); + $this->assertEquals('untouched', file_get_contents($folderTwoB . DS . 'fileB.php')); + $this->assertFalse(file_exists($fileOne)); + $this->assertFalse(file_exists($folderOneA)); + $this->assertFalse(file_exists($fileOneA)); $Folder = new Folder($path); $Folder->delete(); diff --git a/lib/Cake/Utility/Folder.php b/lib/Cake/Utility/Folder.php index 08895bf2e..e331bd2d4 100644 --- a/lib/Cake/Utility/Folder.php +++ b/lib/Cake/Utility/Folder.php @@ -21,6 +21,30 @@ */ class Folder { +/** + * Default scheme for Folder::copy + * Recursivly merges subfolders with the same name + * + * @constant MERGE + */ + const MERGE = 'merge'; + +/** + * Overwrite scheme for Folder::copy + * subfolders with the same name will be replaced + * + * @constant OVERWRITE + */ + const OVERWRITE = 'overwrite'; + +/** + * Skip scheme for Folder::copy + * if a subfolder with the same name exists it will be skipped + * + * @constant SKIP + */ + const SKIP = 'skip'; + /** * Path to Folder. * @@ -594,6 +618,7 @@ class Folder { * - `from` The directory to copy from, this will cause a cd() to occur, changing the results of pwd(). * - `mode` The mode to copy the files/directories with. * - `skip` Files/directories to skip. + * - `scheme` Folder::MERGE, Folder::OVERWRITE, Folder::SKIP * * @param array|string $options Either an array of options (see above) or a string of the destination directory. * @return boolean Success @@ -608,7 +633,7 @@ class Folder { $to = $options; $options = array(); } - $options = array_merge(array('to' => $to, 'from' => $this->path, 'mode' => $this->mode, 'skip' => array()), $options); + $options = array_merge(array('to' => $to, 'from' => $this->path, 'mode' => $this->mode, 'skip' => array(), 'scheme' => Folder::MERGE), $options); $fromDir = $options['from']; $toDir = $options['to']; @@ -630,10 +655,10 @@ class Folder { $exceptions = array_merge(array('.', '..', '.svn'), $options['skip']); if ($handle = @opendir($fromDir)) { - while (false !== ($item = readdir($handle))) { - if (!in_array($item, $exceptions)) { - $from = Folder::addPathElement($fromDir, $item); - $to = Folder::addPathElement($toDir, $item); + while (($item = readdir($handle)) !== false) { + $to = Folder::addPathElement($toDir, $item); + if (($options['scheme'] != Folder::SKIP || !is_dir($to)) && !in_array($item, $exceptions)) { + $from = Folder::addPathElement($fromDir, $item); if (is_file($from)) { if (copy($from, $to)) { chmod($to, intval($mode, 8)); @@ -643,6 +668,10 @@ class Folder { $this->_errors[] = __d('cake_dev', '%s NOT copied to %s', $from, $to); } } + + if (is_dir($from) && file_exists($to) && $options['scheme'] == Folder::OVERWRITE) { + $this->delete($to); + } if (is_dir($from) && !file_exists($to)) { $old = umask(0); @@ -657,6 +686,9 @@ class Folder { } else { $this->_errors[] = __d('cake_dev', '%s not created', $to); } + } elseif (is_dir($from) && $options['scheme'] == Folder::MERGE) { + $options = array_merge($options, array('to' => $to, 'from' => $from)); + $this->copy($options); } } } @@ -680,8 +712,9 @@ class Folder { * - `from` The directory to copy from, this will cause a cd() to occur, changing the results of pwd(). * - `chmod` The mode to copy the files/directories with. * - `skip` Files/directories to skip. + * - `scheme` Folder::MERGE, Folder::OVERWRITE, Folder::SKIP * - * @param array $options (to, from, chmod, skip) + * @param array $options (to, from, chmod, skip, scheme) * @return boolean Success * @link http://book.cakephp.org/2.0/en/core-utility-libraries/file-folder.html#Folder::move */ From f7acab7caed04e105286e03bafb3230b3cdd6343 Mon Sep 17 00:00:00 2001 From: euromark Date: Mon, 10 Sep 2012 19:20:15 +0200 Subject: [PATCH 118/256] doc block update --- lib/Cake/Test/Case/Utility/FolderTest.php | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/lib/Cake/Test/Case/Utility/FolderTest.php b/lib/Cake/Test/Case/Utility/FolderTest.php index 0d86286cb..26aeeac4e 100644 --- a/lib/Cake/Test/Case/Utility/FolderTest.php +++ b/lib/Cake/Test/Case/Utility/FolderTest.php @@ -811,6 +811,7 @@ class FolderTest extends CakeTestCase { * Verify that subdirectories existing in both destination and source directory * are merged recursivly. * + * @return void */ public function testCopy() { extract($this->_setupFilesystem()); @@ -839,6 +840,7 @@ class FolderTest extends CakeTestCase { * Verify that subdirectories existing in both destination and source directory * are merged recursivly. * + * @return void */ public function testCopyWithMerge() { extract($this->_setupFilesystem()); @@ -914,16 +916,7 @@ class FolderTest extends CakeTestCase { * Verify that subdirectories existing in both destination and source directory * are overwritten/replaced recursivly. * - * $path: folder_test/ - * $folderOne: folder_test/folder1/ - * - file1.php - * $folderTwo: folder_test/folder2/ - * - file2.php - * $folderThree: folder_test/folder1/folder3/ - * - file3.php - * $folderFour: folder_test/folder2/folder4/ - * - file4.php - * $folderThree: folder_test/folder5/ + * @return void */ function testCopyWithOverwrite() { extract($this->_setupFilesystem()); @@ -956,8 +949,14 @@ class FolderTest extends CakeTestCase { /** * Setup filesystem for copy tests + * $path: folder_test/ + * - folder1/file1.php + * - folder1/folderA/fileA.php + * - folder2/file2.php + * - folder2/folderB/fileB.php + * - folder3/ * - * @return void + * @return array Filenames to extract in the test methods */ protected function _setupFilesystem() { $path = TMP . 'folder_test'; From 2d9d400ecbd6d1bca8848da9a8a9d74d2033b996 Mon Sep 17 00:00:00 2001 From: euromark Date: Mon, 10 Sep 2012 23:08:14 +0200 Subject: [PATCH 119/256] correct spelling --- lib/Cake/Test/Case/Utility/FolderTest.php | 8 ++++---- lib/Cake/Utility/Folder.php | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/lib/Cake/Test/Case/Utility/FolderTest.php b/lib/Cake/Test/Case/Utility/FolderTest.php index 26aeeac4e..f5e8c65b6 100644 --- a/lib/Cake/Test/Case/Utility/FolderTest.php +++ b/lib/Cake/Test/Case/Utility/FolderTest.php @@ -809,7 +809,7 @@ class FolderTest extends CakeTestCase { * testCopy method * * Verify that subdirectories existing in both destination and source directory - * are merged recursivly. + * are merged recursively. * * @return void */ @@ -838,7 +838,7 @@ class FolderTest extends CakeTestCase { * testCopyWithMerge method * * Verify that subdirectories existing in both destination and source directory - * are merged recursivly. + * are merged recursively. * * @return void */ @@ -914,7 +914,7 @@ class FolderTest extends CakeTestCase { * testCopyWithOverwrite * * Verify that subdirectories existing in both destination and source directory - * are overwritten/replaced recursivly. + * are overwritten/replaced recursively. * * @return void */ @@ -995,7 +995,7 @@ class FolderTest extends CakeTestCase { * Verify that directories and files are moved recursively * even if the destination directory already exists. * Subdirectories existing in both destination and source directory - * are merged recursivly. + * are merged recursively. * * @return void */ diff --git a/lib/Cake/Utility/Folder.php b/lib/Cake/Utility/Folder.php index e331bd2d4..74c0d5b87 100644 --- a/lib/Cake/Utility/Folder.php +++ b/lib/Cake/Utility/Folder.php @@ -23,7 +23,7 @@ class Folder { /** * Default scheme for Folder::copy - * Recursivly merges subfolders with the same name + * Recursively merges subfolders with the same name * * @constant MERGE */ From 0cae19a14e089f49285d600098c5238bb1941f12 Mon Sep 17 00:00:00 2001 From: Rachman Chavik Date: Wed, 12 Sep 2012 21:17:10 +0700 Subject: [PATCH 120/256] enable PluginDot for routeClass parameter --- lib/Cake/Routing/Router.php | 7 ++++++- lib/Cake/Test/Case/Routing/RouterTest.php | 20 +++++++++++++++++++ .../Lib/Routing/Route/TestRoute.php | 7 +++++++ 3 files changed, 33 insertions(+), 1 deletion(-) create mode 100644 lib/Cake/Test/test_app/Plugin/TestPlugin/Lib/Routing/Route/TestRoute.php diff --git a/lib/Cake/Routing/Router.php b/lib/Cake/Routing/Router.php index 880057e05..662ed0af0 100644 --- a/lib/Cake/Routing/Router.php +++ b/lib/Cake/Routing/Router.php @@ -304,7 +304,12 @@ class Router { } $routeClass = self::$_routeClass; if (isset($options['routeClass'])) { - $routeClass = self::_validateRouteClass($options['routeClass']); + if (strpos($options['routeClass'], '.') === false) { + $routeClass = $options['routeClass']; + } else { + list($plugin, $routeClass) = pluginSplit($options['routeClass'], true); + } + $routeClass = self::_validateRouteClass($routeClass); unset($options['routeClass']); } if ($routeClass == 'RedirectRoute' && isset($defaults['redirect'])) { diff --git a/lib/Cake/Test/Case/Routing/RouterTest.php b/lib/Cake/Test/Case/Routing/RouterTest.php index 512ab0565..053fd57c4 100644 --- a/lib/Cake/Test/Case/Routing/RouterTest.php +++ b/lib/Cake/Test/Case/Routing/RouterTest.php @@ -2282,6 +2282,26 @@ class RouterTest extends CakeTestCase { $this->assertEquals($expected, $result); } +/** + * test using custom route class in PluginDot notation + */ + public function testUsingCustomRouteClassPluginDotSyntax() { + App::build(array( + 'Plugin' => array( + CAKE . 'Test' . DS . 'test_app' . DS . 'Plugin' . DS + ) + )); + CakePlugin::load('TestPlugin'); + App::uses('TestRoute', 'TestPlugin.Routing/Route'); + $routes = Router::connect( + '/:slug', + array('controller' => 'posts', 'action' => 'view'), + array('routeClass' => 'TestPlugin.TestRoute', 'slug' => '[a-z_-]+') + ); + $this->assertInstanceOf('TestRoute', $routes[0]); + CakePlugin::unload('TestPlugin'); + } + /** * test that route classes must extend CakeRoute * diff --git a/lib/Cake/Test/test_app/Plugin/TestPlugin/Lib/Routing/Route/TestRoute.php b/lib/Cake/Test/test_app/Plugin/TestPlugin/Lib/Routing/Route/TestRoute.php new file mode 100644 index 000000000..efd890a5f --- /dev/null +++ b/lib/Cake/Test/test_app/Plugin/TestPlugin/Lib/Routing/Route/TestRoute.php @@ -0,0 +1,7 @@ + Date: Wed, 12 Sep 2012 18:10:50 +0100 Subject: [PATCH 121/256] simplify the code in the string class removing else statements and variables that are not needed. eg: return something(); vs $foo = something(); return $foo; --- lib/Cake/Utility/String.php | 76 ++++++++++++++++--------------------- 1 file changed, 33 insertions(+), 43 deletions(-) diff --git a/lib/Cake/Utility/String.php b/lib/Cake/Utility/String.php index d3c6b0868..ecf0100af 100644 --- a/lib/Cake/Utility/String.php +++ b/lib/Cake/Utility/String.php @@ -72,10 +72,6 @@ class String { } elseif ($node !== '127.0.0.1') { $node = ip2long($node); } else { - $node = null; - } - - if (empty($node)) { $node = crc32(Configure::read('Security.salt')); } @@ -92,12 +88,10 @@ class String { } list($timeMid, $timeLow) = explode(' ', microtime()); - $uuid = sprintf( + return sprintf( "%08x-%04x-%04x-%02x%02x-%04x%08x", (int)$timeLow, (int)substr($timeMid, 2) & 0xffff, mt_rand(0, 0xfff) | 0x4000, mt_rand(0, 0x3f) | 0x80, mt_rand(0, 0xff), $pid, $node ); - - return $uuid; } /** @@ -156,7 +150,6 @@ class String { $open = true; } else { $depth--; - $open = false; } } } @@ -171,11 +164,10 @@ class String { } if (!empty($results)) { - $data = array_map('trim', $results); - } else { - $data = array(); + return array_map('trim', $results); } - return $data; + + return array(); } /** @@ -227,25 +219,25 @@ class String { $str = substr_replace($str, $val, $pos, 1); } return ($options['clean']) ? String::cleanInsert($str, $options) : $str; - } else { - asort($data); + } - $hashKeys = array(); - foreach ($data as $key => $value) { - $hashKeys[] = crc32($key); - } + asort($data); - $tempData = array_combine(array_keys($data), array_values($hashKeys)); - krsort($tempData); - foreach ($tempData as $key => $hashVal) { - $key = sprintf($format, preg_quote($key, '/')); - $str = preg_replace($key, $hashVal, $str); - } - $dataReplacements = array_combine($hashKeys, array_values($data)); - foreach ($dataReplacements as $tmpHash => $tmpValue) { - $tmpValue = (is_array($tmpValue)) ? '' : $tmpValue; - $str = str_replace($tmpHash, $tmpValue, $str); - } + $hashKeys = array(); + foreach ($data as $key => $value) { + $hashKeys[] = crc32($key); + } + + $tempData = array_combine(array_keys($data), array_values($hashKeys)); + krsort($tempData); + foreach ($tempData as $key => $hashVal) { + $key = sprintf($format, preg_quote($key, '/')); + $str = preg_replace($key, $hashVal, $str); + } + $dataReplacements = array_combine($hashKeys, array_values($data)); + foreach ($dataReplacements as $tmpHash => $tmpValue) { + $tmpValue = (is_array($tmpValue)) ? '' : $tmpValue; + $str = str_replace($tmpHash, $tmpValue, $str); } if (!isset($options['format']) && isset($options['before'])) { @@ -397,14 +389,14 @@ class String { } return preg_replace($replace, $with, $text); - } else { - $phrase = '(' . preg_quote($phrase, '|') . ')'; - if ($html) { - $phrase = "(?![^<]+>)$phrase(?![^<]+>)"; - } - - return preg_replace(sprintf($options['regex'], $phrase), $format, $text); } + + $phrase = '(' . preg_quote($phrase, '|') . ')'; + if ($html) { + $phrase = "(?![^<]+>)$phrase(?![^<]+>)"; + } + + return preg_replace(sprintf($options['regex'], $phrase), $format, $text); } /** @@ -447,9 +439,9 @@ class String { if (mb_strlen($text) <= $length) { return $text; - } else { - $truncate = mb_substr($text, mb_strlen($text) - $length + mb_strlen($ellipsis)); } + + $truncate = mb_substr($text, mb_strlen($text) - $length + mb_strlen($ellipsis)); if (!$exact) { $spacepos = mb_strpos($truncate, ' '); $truncate = $spacepos === false ? '' : trim(mb_substr($truncate, $spacepos)); @@ -542,9 +534,8 @@ class String { } else { if (mb_strlen($text) <= $length) { return $text; - } else { - $truncate = mb_substr($text, 0, $length - mb_strlen($ellipsis)); } + $truncate = mb_substr($text, 0, $length - mb_strlen($ellipsis)); } if (!$exact) { $spacepos = mb_strrpos($truncate, ' '); @@ -642,9 +633,8 @@ class String { public static function toList($list, $and = 'and', $separator = ', ') { if (count($list) > 1) { return implode($separator, array_slice($list, null, -1)) . ' ' . $and . ' ' . array_pop($list); - } else { - return array_pop($list); } - } + return array_pop($list); + } } From 44f8f84cd7e334535fda8edb725ad10b6e8f9bac Mon Sep 17 00:00:00 2001 From: dogmatic69 Date: Wed, 12 Sep 2012 18:26:04 +0100 Subject: [PATCH 122/256] Simplify the code for sanitize class removing else statements and variables that are not needed. eg: return something(); vs $foo = something(); return $foo; --- lib/Cake/Utility/Sanitize.php | 102 +++++++++++++++++----------------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/lib/Cake/Utility/Sanitize.php b/lib/Cake/Utility/Sanitize.php index dfb55f34b..26db0d558 100644 --- a/lib/Cake/Utility/Sanitize.php +++ b/lib/Cake/Utility/Sanitize.php @@ -46,14 +46,15 @@ class Sanitize { } } - if (is_array($string)) { - $cleaned = array(); - foreach ($string as $key => $clean) { - $cleaned[$key] = preg_replace("/[^{$allow}a-zA-Z0-9]/", '', $clean); - } - } else { - $cleaned = preg_replace("/[^{$allow}a-zA-Z0-9]/", '', $string); + if (!is_array($string)) { + return preg_replace("/[^{$allow}a-zA-Z0-9]/", '', $string); } + + $cleaned = array(); + foreach ($string as $key => $clean) { + $cleaned[$key] = preg_replace("/[^{$allow}a-zA-Z0-9]/", '', $clean); + } + return $cleaned; } @@ -70,14 +71,12 @@ class Sanitize { return $string; } $string = $db->value($string, 'string'); - if ($string[0] === 'N') { - $string = substr($string, 2); - } else { - $string = substr($string, 1); + $start = 1; + if ($string{0} === 'N') { + $start = 2; } - $string = substr($string, 0, -1); - return $string; + return substr(substr($string, 1), 0, -1); } /** @@ -128,8 +127,7 @@ class Sanitize { * @return string whitespace sanitized string */ public static function stripWhitespace($str) { - $r = preg_replace('/[\n\r\t]+/', '', $str); - return preg_replace('/\s{2,}/u', ' ', $r); + return preg_replace('/\s{2,}/u', ' ', preg_replace('/[\n\r\t]+/', '', $str)); } /** @@ -139,10 +137,13 @@ class Sanitize { * @return string Sting with images stripped. */ public static function stripImages($str) { - $str = preg_replace('/(]*>)(]+alt=")([^"]*)("[^>]*>)(<\/a>)/i', '$1$3$5
    ', $str); - $str = preg_replace('/(]+alt=")([^"]*)("[^>]*>)/i', '$2
    ', $str); - $str = preg_replace('/]*>/i', '', $str); - return $str; + $preg = array( + '/(]*>)(]+alt=")([^"]*)("[^>]*>)(<\/a>)/i' => '$1$3$5
    ', + '/(]+alt=")([^"]*)("[^>]*>)/i' => '$2
    ', + '/]*>/i' => '' + ); + + return preg_replace(array_keys($preg), array_values($preg), $str); } /** @@ -152,7 +153,8 @@ class Sanitize { * @return string String with