diff --git a/README.md b/README.md index fc6f0df2f0..dba2ed4f18 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,14 @@ Pi Engine ================= -Xoops/Pi Engine (The Engine, hereafter) is a role oriented modularized framework, an application development engine for web and mobile, designed as the next generation of XOOPS. +Pi Engine is a role oriented application development engine for web and mobile, designed as the next generation and a successor to Xoops. +Pi is developed upon PHP and MySQL with selected third-party frameworks including but not limited to [Zend Framework library](https://github.com/zendframework/zf2), [jQuery](https://github.com/jquery/jquery), [Bootstrap](https://github.com/twitter/bootstrap) and [Backbone](https://github.com/documentcloud/backbone). -The Engine is released under a New BSD License and the project is intended to promote a sustainable ecosystem that benefits all contributors and users. +Pi Project follows the philosophy of open standard, open design, open development and open structure. Pi is born as a complete open source project and intended to build a sustainable ecosystem that benefits all contributors and users. -The Xoops/Pi Engine is a successor of the XOOPS Project led by Ono Kazumi (onokazu), skalpa and Taiwen Jiang (phppp). The Pi Team is inspired by them and benefits from their experiences and spirit. Pi Engine will continue to inherit and promote XOOPS brand. +[Pi Team](https://github.com/pi-engine/pi/wiki/Pi-Team) is highly inspired by the Xoops led by onokazu (Ono Kazumi), skalpa and phppp (Taiwen Jiang, or D.J.) successively since 2001 and will continue to support and promote Xoops. -**Check out the [Pi Day Release](https://github.com/pi-engine/pi/blob/master/doc/pi-day-release.txt).** +**Check out [Latest Release](https://github.com/pi-engine/pi/blob/master/doc/releasenotes.txt).** @@ -19,159 +20,24 @@ Features and practices 4. Design-friendly templating 5. DevOps oriented architecture -To get started, check out [Pi Engine Repository](https://github.com/pi-engine/pi). - - Quick start ----------- - -Clone the repo, `git clone git://github.com/pi-engine/pi.git`, or [download the latest release](https://github.com/xoops/pi/zipball/master). - - - -Versioning ----------- - -For transparency and insight into our release cycle, and striving to maintain backward compatibility, Xoops/Pi Engine will be maintained under the Semantic Versioning guidelines as much as possible. - -Releases will be numbered in the following format: - -`..` - -And constructed with the following guidelines: - -* Breaking backward compatibility bumps the major (and resets the minor and patch) -* New additions without breaking backward compatibility bumps the minor (and resets the patch) -* Bug fixes and misc changes bumps the patch - -For more information on SemVer, please visit http://semver.org/. - - - -Bug/feature tracker ------------ - -To report a bug or request a feature, please create an issue here on GitHub [Pi Issues](https://github.com/pi-engine/pi/issues) that conforms with [necolas's guidelines](https://github.com/necolas/issue-guidelines). - - - -Twitter -------- - -Keep up to date on announcements and more by following Pi Engine on Twitter, [@XoopsProject](http://twitter.com/XoopsProject). - - - -Blog ----- - -Read more detailed announcements, discussions, and more on [Xoops/Pi Engine Dev Blog](http://dev.xoopsengine.org). - - - - +* Check documents at [Pi Wiki](https://github.com/pi-engine/pi/wiki) +* Download the [latest code](https://github.com/xoops/pi/zipball/master). +* Clone Pi repo `git clone git://github.com/pi-engine/pi.git` and [keep updated](https://help.github.com/articles/fork-a-repo#pull-in-upstream-changes). Development ---------- -Beyond production and application, the Engine also strives to be strictly standard compliant, including but not limited to: - -1. Versioning - [Semantic Versioning Specification](http://semver.org) -2. PHP - [PSR compliant](https://github.com/php-fig/fig-standards), [Zend Framework Coding Standards](http://framework.zend.com/wiki/display/ZFDEV2/Coding+Standards) -3. HTML/CSS - [Google HTML/CSS Style Guide](http://google-styleguide.googlecode.com/svn/trunk/htmlcssguide.xml) -4. JavaScript - [Google JavaScript Style Guide](http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml) -5. All code must be strictly compliant to its corresponding standards, no warning/notice messages allowed - - -Third-party libraries utilized in this framework: - -1. PHP - [Zend Framework 2](https://github.com/zendframework/zf2) -2. JavaScript - [jQuery](https://github.com/jquery/jquery) -3. CSS/JS - [Bootstrap](https://github.com/twitter/bootstrap)/[Backbone](https://github.com/documentcloud/backbone) - - - - -Contributing ------------- - -If you wish to contribute to Xoops/Pi Engine, please read both the CONTRIBUTING.md and README-GIT.md file. - - -Authors -------- - -**[Taiwen Jiang (D.J.)](http://github.com/taiwen)** -+ XOOPS account: phppp -+ http://twitter.com/taiwen -+ http://github.com/pi-engine -+ http://weibo.com/nope -+ https://www.facebook.com/xoops +Pi Engine is started by Taiwen Jiang (Xoops Project Lead and Dev Lead), Marc Desrousseaux (Xoops QA Lead), Hossein Azizabadi (Xoops Persian Lead), Kris (Xoops Council Member and Xoops France Lead), etc. You are welcome to join **[Pi Team](https://github.com/pi-engine/pi/wiki/Pi-Team)**. -**[Hossein Azizabadi](http://github.com/voltan)** -+ XOOPS account: voltan - -**[marco](http://github.com/MarcoXoops)** -+ XOOPS account: marco_fr - -**[kris](http://github.com/krisxoofoo)** -+ XOOPS account: kris - -**[Lin Zongshu](http://github.com/linzongshu)** - -**[EEFOCUS Team](http://www.eefocus.com)** -+ [Dong Lijun](https://github.com/donglijun) -+ [Liu Chuang](https://github.com/liuchuangww) -+ [Liao Wei](https://github.com/sexnothing) -+ [Simon Zhang](https://github.com/zhangsimon) -+ [Danyi Feng](https://github.com/d4ny1) - -**[Longquan Monastery Team](http://weibo.com/lqsit)** -+ [Master Xianxin](https://github.com/htouch) -+ [Xiandu](https://github.com/gwisdomroof) -+ [Zhang Jing](https://github.com/zhangjing1117) - -**[Wen.org.cn Team](http://wen.org.cn)** -+ [Liot](https://github.com/liot) liot@wen.org.cn - - -Acknowledgements ----------------- - -The Pi Team would like to thank Mr. Su Gongyu from EEFOCUS.com and Master Xianxin from Longquan Monastery for their ultimate support. The Wen.org.cn Team has been a great support since early days of Xoops Project and continues to be a part of the Pi Team. +You may contribute to Pi at github by submitting your code to Pi repo with **[Pull Request](https://help.github.com/articles/using-pull-requests)** or submitting bug reports and feature requests to **[Issue Tracker](https://github.com/pi-engine/pi/issues)**. Copyright and License --------------------- -The Engine is released under a New BSD License and the project is intended to promote a sustainable ecosystem that benefits all contributors and users. - -New BSD License -Copyright (c) 2011, Pi Engine Project -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. +The Engine is released under a [New BSD License](https://github.com/pi-engine/pi/blob/master/doc/license.txt). - * Neither the name of Pi Engine nor the names of its - contributors may be used to endorse or promote products derived from this - software without specific prior written permission. -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/doc/changelog.txt b/doc/changelog.txt index db48e99608..e552231688 100644 --- a/doc/changelog.txt +++ b/doc/changelog.txt @@ -1,10 +1,40 @@ Pi Engine Changelog +April 19th, 2013 +============================= +1. Upgraded ZF2 to 2.1.5 +2. Improved Intl functions for BC by @voltan +3. Imported "test" module for module dependency test +4. Refactored HTML head/foot rendering to expose section positions +5. Added convenient methods for setting custom head title, keywords and description suggested by @voltan +6. Moved Pi\Debug to Pi\Debug\Debug +7. Refactored Pi\Security with Pi::service('Security') and Pi\Security\Security +8. Added files: var/config/service.security.php +9. Modified files: var/config/resource.security.php +10. Added convenient methods and syntactic sugar for parameter filtering and sanitizing + + +April 8th, 2013 +============================= +1. Fixed Issue #21 reported by @voltan: duplicated head keywords and description +2. Added missing head style in view renderer +3. Changed empty result of navigation registry from false to array() to avoid crash in backend with no-nav module +4. Refactored title/meta rendering +5. Improved cache option files +6. Added Pi\Cache\Storage\Adapter\Filesystem to record file expiration so that TTL is not required any more for reading cache +7. Added support for Intl extension with intlDateFormatter and NumberFormatter suggested by @voltan in Issue #24 +8. Improved support for multi-host config +9. Fixed ACL resource bugs in module installation/uninstallation +10. Changed configuration related table fields from tinytext to text in System module v3.1.0 +11. Added missing module_dependency table in System module v3.1.1 + + March 23rd, 2013 ============================= 1. Fixed Issue #2 reported by @jemz: set default timezone in case not set in php.ini 2. Fixed BC issues caused by ZF2 including Issue #5 reported by @jemz +3. Upgraded Boostrap to 1.0.0 and Backbone to 2.3.1 by @sexnothing March 14th, 2013 diff --git a/doc/pi-day-release.txt b/doc/pi-day-release.txt index 951f3574a0..a75356bbe1 100644 --- a/doc/pi-day-release.txt +++ b/doc/pi-day-release.txt @@ -2,11 +2,11 @@ Pi Day Release for Pi Engine The Pi Team is pleased to present the Pi Day Release as the first public release of Xoops/Pi Engine as the next generation of XOOPS in years. -Check out https://github.com/pi-engine/pi/blob/master/doc/pi-day-release.txt for full announcement. +Pi Engine is a role oriented application development engine for web and mobile, designed as the next generation and a successor to Xoops. Pi is developed upon PHP and MySQL with selected third-party frameworks including but not limited to Zend Framework library, jQuery, Bootstrap and Backbone. -Xoops/Pi Engine (The Engine, hereafter) is a role oriented modularized framework, an application development engine for web and mobile, designed as the next generation of XOOPS. +Pi Project follows the philosophy of open standard, open design, open development and open structure. Pi is born as a complete open source project and intended to build a sustainable ecosystem that benefits all contributors and users. -The Xoops/Pi Engine is a successor of the XOOPS Project led by Ono Kazumi (onokazu), skalpa and Taiwen Jiang (phppp). The Pi Team is inspired by them and benefits from their experiences and spirit. Pi Engine will continue to inherit and promote XOOPS brand. +Pi Team is highly inspired by the Xoops led by onokazu (Ono Kazumi), skalpa and phppp (Taiwen Jiang, or D.J.) successively since 2001 and will continue to support and promote Xoops. Selected features and practices: 1. Modularization for functionality and applications diff --git a/doc/readme.txt b/doc/readme.txt index d0b0721608..824ec1a8ca 100644 --- a/doc/readme.txt +++ b/doc/readme.txt @@ -1,6 +1,10 @@ -Xoops/Pi Engine (The Engine, hereafter) is a role oriented modularized framework, an application development engine for web and mobile, designed as the next generation of XOOPS. -The Engine is released under a New BSD License and the project is intended to promote a sustainable ecosystem that benefits all contributors and users. +Pi Engine is a role oriented application development engine for web and mobile, designed as the next generation and a successor to Xoops. Pi is developed upon PHP and MySQL with selected third-party frameworks including but not limited to Zend Framework library, jQuery, Bootstrap and Backbone. +Pi Project follows the philosophy of open standard, open design, open development and open structure. Pi is born as a complete open source project and intended to build a sustainable ecosystem that benefits all contributors and users. + +Pi Team is highly inspired by the Xoops led by onokazu (Ono Kazumi), skalpa and phppp (Taiwen Jiang, or D.J.) successively since 2001 and will continue to support and promote Xoops. Pi is started by Taiwen Jiang (Xoops Project Lead and Dev Lead), Marc Desrousseaux (Xoops QA Lead), Hossein Azizabadi (Xoops Persian Lead), Kris (Xoops Council Member and Xoops French Lead), etc. You are welcome to join Pi Team. + +The Engine is released under a New BSD License. Selected features and practices: 1. Modularization for functionality and applications diff --git a/doc/releasenotes.txt b/doc/releasenotes.txt index e69de29bb2..f79ba1d460 100644 --- a/doc/releasenotes.txt +++ b/doc/releasenotes.txt @@ -0,0 +1,9 @@ +Pi Day Release for Pi Engine + +The Pi Team is pleased to present the Pi Day Release as the first public release of Xoops/Pi Engine as the next generation of XOOPS in years. + +Check out [Pi Day Release Announcement](https://github.com/pi-engine/pi/blob/master/doc/pi-day-release.txt) for details. + +Taiwen Jiang +Lead for Pi Development Team +March 14th, 2013 diff --git a/lib/Pi.php b/lib/Pi.php index 94361a581a..1a27bdcc24 100644 --- a/lib/Pi.php +++ b/lib/Pi.php @@ -224,8 +224,9 @@ public static function init() static::autoloader($options); /**#@-*/ - // Load debugger - Pi\Debug::load(); + // Load debugger and filter + Pi\Debug\Debug::load(); + Pi\Utility\Filter::load(); /**#@+ * Load engine global config diff --git a/lib/Pi/Application/Db.php b/lib/Pi/Application/Db.php index cc2fbbdd94..7fd5f8ae75 100644 --- a/lib/Pi/Application/Db.php +++ b/lib/Pi/Application/Db.php @@ -110,12 +110,6 @@ class Db */ public function __construct($options) { - /* - if (isset($options['schema'])) { - $this->setSchema($options['schema']); - $options['connection']['dsn'] .= ';dbname=' . $options['schema']; - } - */ $this->loadAdapter($options['connection']); if (isset($options['table_prefix'])) { $this->setTablePrefix($options['table_prefix']); @@ -237,15 +231,8 @@ public function createAdapter(array $config, $platform = null) $config['driver_options'][PDO::ATTR_STATEMENT_CLASS] = array(static::STATEMENT_CLASS, array($this->profiler())); } - //$driver = $this->createDriver($config); $adapter = new Adapter($config, $platform); - // Build connection onload if not disabled explicitly - if (!isset($options['connect_onload']) || !empty($options['connect_onload'])) { - $adapter->driver->getConnection()->connect(); - $adapter->platform->setDriver($adapter->driver); - } - return $adapter; } diff --git a/lib/Pi/Application/Engine/Standard.php b/lib/Pi/Application/Engine/Standard.php index 5d0a981640..5368d37882 100644 --- a/lib/Pi/Application/Engine/Standard.php +++ b/lib/Pi/Application/Engine/Standard.php @@ -60,11 +60,13 @@ public function run() return false; } + /* $response = $this->application->getResponse(); $response->getHeaders()->addHeaders(array( 'content-type' => sprintf('text/html; charset=%s', Pi::config('charset')), 'content-language' => Pi::config('locale'), )); + */ $this->application->run(); diff --git a/lib/Pi/Application/Host.php b/lib/Pi/Application/Host.php index 7da65da11b..02b7703b08 100644 --- a/lib/Pi/Application/Host.php +++ b/lib/Pi/Application/Host.php @@ -19,14 +19,35 @@ namespace Pi\Application; +/** + * Host handler + * + * Single host + * 1. In www/boot.php: + * + * define('PI_PATH_HOST', '/path/to/pi/var/config/host.php'); + * + * 2. In /path/to/pi/var/config/host.php: + * + * return array( + * 'uri' => array( + * ... + * ), + * 'path' => array( + * ... + * ), + * ); + * + * + * Multiple hosts + * 1. In www/boot.php: + * + * define('PI_PATH_HOST', '/path/to/pi/var/config/hosts.php'); + * + * 2. In /path/to/pi/var/config/hosts.php, see /var/config/hosts.php + */ class Host { - /** - * Default host identifier - * @var string - */ - const DEFAULT_HOST_FILE = 'Default.php'; - /** * Base URL, segment after baseLocation in installed URL which is: ($scheme:://$hostName[:$port])$baseUrl with leading slash * @var string @@ -116,66 +137,46 @@ protected function getBaseLocation() * @param string $hostIdentifier * @return array */ - protected function lookup($hostIdentifier = null) + protected function lookup($config, $hostIdentifier = '') { + // Valid host data, return directly + if (isset($config['path']) || isset($config['uri'])) { + return $config; + } + // Invalid hosts data, return empty data + if (!isset($config['hosts']) || !isset($config['alias'])) { + trigger_error('Invalid hosts config.', E_USER_ERROR); + return array(); + } + // Build current request URI - /* - $scheme = ($_SERVER['HTTPS'] == 'on') ? 'https' : 'http'; $uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : $_SERVER['SCRIPT_NAME']; - $requestUri = sprintf('%s://%s%s', $scheme, $_SERVER['HTTP_HOST'], ($uri ? '/' . ltrim($uri, '/') : '')); - */ - $uri = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : $_SERVER['SCRIPT_NAME']; - $requestUri = $this->getBaseLocation() . ($uri ? '/' . ltrim($uri, '/') : ''); + $requestUri = rtrim($this->getBaseLocation() . ($uri ? '/' . trim($uri, '/') : ''), '/') . '/'; - // Lookup again alias list + // Lookup identifier against alias list $lookup = function ($conf) use ($requestUri) { foreach($conf as $uri => $identifier) { - if (0 === strpos($uri, $requestUri)) { + $uri = rtrim($uri, '/') . '/'; + if (0 === strpos($requestUri, $uri)) { return $identifier; } } return false; }; - $host = ''; - $identifier = ''; - // Lookup against specified host - if ($hostIdentifier) { - $config = include sprintf('%s/Host/%sHost.php', __DIR__, ucfirst($hostIdentifier)); - $identifier = $lookup($config['alias']); - if ($identifier) { - $host = $config['location'][$identifier]; - // Load default host if specified host is not found - } else { - $configDefault = include sprintf('%s/Host/%s', __DIR__, static::DEFAULT_HOST_FILE); - $identifier = 'default'; - $host = $configDefault['location'][$identifier]; - } - } else { - // Lookup against default host first - $configDefault = include sprintf('%s/Host/%s', __DIR__, static::DEFAULT_HOST_FILE); - $identifier = $lookup($configDefault['alias']); - if ($identifier) { - $host = $configDefault['location'][$identifier]; - } else { - // Lookup against rest hosts in Host folder - foreach (glob(__DIR__ . '/Host/*Host.php') as $file) { - $config = include $file; - $identifier = $lookup($config['alias']); - if ($identifier) { - $host = $config['location'][$identifier]; - break; - } - } - if (!$host) { - $identifier = 'default'; - $host = $configDefault['location'][$identifier]; - } - } + // Find identifier + if (!$hostIdentifier) { + $hostIdentifier = $lookup($config['alias']) ?: 'default'; + } + // Get host data + $hostData = $config['hosts'][$hostIdentifier]; + // Read from file + if (is_string($hostData)) { + $hostData = include $hostData; } - return $host; + return $hostData; } /** @@ -184,45 +185,47 @@ protected function lookup($hostIdentifier = null) * @param string|array $config Host file path or array of path settings * @return void */ - public function setHost($config = null) + public function setHost($config) { $hostConfig = array(); $hostFile = ''; - // Nothing set, so do a traversal lookup to find host file - if (!$config) { - $hostFile = $this->lookup(); + $hostIdentifier = ''; + // Host file path is specified - } elseif (is_string($config)) { - $hostFile = $config; - // Host file path specified - } elseif (!empty($config['file'])) { + if (is_string($config)) { + $config['file'] = $config; + } + if (isset($config['file'])) { $hostFile = $config['file']; - $hostConfig = !empty($config['host']) ? $config['host'] : array(); - // Host identifier specified - } elseif (!empty($config['identifier'])) { - $hostFile = $this->lookup($config['identifier']); - $hostConfig = !empty($config['host']) ? $config['host'] : array(); - // Host config specified partially - } elseif (!empty($config['host'])) { - $hostFile = $this->lookup(); + unset($config['file']); + } + // Get host identifier + if (isset($config['identifier'])) { + $hostIdentifier = $config['identifier']; + unset($config['identifier']); + } + // Get custom host config + if (isset($config['host'])) { $hostConfig = $config['host']; - // Host config specified directly - } else { - $hostConfig = $config; + unset($config['host']); } - // Load configs from file if specified + // Load host data from file if ($hostFile) { - $configs = include $hostFile; - if (isset($hostConfig['path'])) { - $hostConfig['path'] = array_merge($configs['path'], $hostConfig['path']); - } else { - $hostConfig['path'] = $configs['path']; - } - if (isset($hostConfig['uri'])) { - $hostConfig['uri'] = array_merge($configs['uri'], $hostConfig['uri']); - } else { - $hostConfig['uri'] = $configs['uri']; - } + $config = include $hostFile; + } + + // Find host config data + $configs = $this->lookup($config, $hostIdentifier); + // Merge with custom host config + if (isset($hostConfig['path'])) { + $hostConfig['path'] = array_merge($configs['path'], $hostConfig['path']); + } else { + $hostConfig['path'] = $configs['path']; + } + if (isset($hostConfig['uri'])) { + $hostConfig['uri'] = array_merge($configs['uri'], $hostConfig['uri']); + } else { + $hostConfig['uri'] = $configs['uri']; } // Canonize www URI diff --git a/lib/Pi/Application/Host/Default.php b/lib/Pi/Application/Host/Default.php deleted file mode 100644 index 067e189ed9..0000000000 --- a/lib/Pi/Application/Host/Default.php +++ /dev/null @@ -1,19 +0,0 @@ - host path - 'location' => array( - 'default' => '/path/to/default/path/to/host', - 'site' => '/path/to/site/path/to/host', - ), - // URI alias list: associative array pair: URI => identifier - 'alias' => array( - 'http://domain.pi' => 'default', - 'http://domain.test' => 'default', - 'http://www.domain.pi' => 'default', - 'http://www.domain.test' => 'default', - - 'http://domain.site/www' => 'site', - 'http://www.domain.site/www' => 'site', - ), -); diff --git a/lib/Pi/Application/Host/DemoHost.php b/lib/Pi/Application/Host/DemoHost.php deleted file mode 100644 index 2c1b6a05d8..0000000000 --- a/lib/Pi/Application/Host/DemoHost.php +++ /dev/null @@ -1,10 +0,0 @@ - array( - 'demo' => '/path/to/demo//path/to/host', - ), - 'alias' => array( - 'http://domain.demo/www' => 'demo', - ), -); diff --git a/lib/Pi/Application/Installer/Action/AbstractAction.php b/lib/Pi/Application/Installer/Action/AbstractAction.php index bbfad4046d..20c3253e3a 100644 --- a/lib/Pi/Application/Installer/Action/AbstractAction.php +++ b/lib/Pi/Application/Installer/Action/AbstractAction.php @@ -76,7 +76,6 @@ protected function attachDefaultListeners() public function checkDependent(Event $e) { - //$options = $e->getParam('options'); $model = Pi::model('module_dependency'); $rowset = $model->select(array('independent' => $e->getParam('module'))); if ($rowset->count() > 0) { @@ -97,15 +96,14 @@ public function checkIndependent(Event $e) if (empty($config['dependency'])) { return true; } - //$options = $e->getParam('options'); - $model = Pi::model('module_dependency'); - $rowset = $model->select(array('dependent' => $e->getParam('module'))); $independents = $config['dependency']; - $available = array(); - while ($row = $rowset->current()) { - $available[] = $row->independent; + $modules = Pi::service('registry')->modulelist->read(); + $missing = array(); + foreach ($independents as $indenpendent) { + if (!isset($modules[$indenpendent])) { + $missing[] = $indenpendent; + } } - $missing = array_diff($independents, $available); if ($missing) { $result = $e->getParam('result'); $result['dependency'] = array( @@ -121,11 +119,10 @@ public function checkIndependent(Event $e) public function createDependency(Event $e) { $config = $this->event->getParam('config'); - $module = $e->getParam('module'); if (empty($config['dependency'])) { return true; } - //$options = $e->getParam('options'); + $module = $e->getParam('module'); $model = Pi::model('module_dependency'); foreach ($config['dependency'] as $independent) { $row = $model->createRow(array( @@ -149,12 +146,9 @@ public function createDependency(Event $e) public function removeDependency(Event $e) { $config = $this->event->getParam('config'); - if (empty($config['dependency'])) { - return true; - } - //$options = $e->getParam('options'); $model = Pi::model('module_dependency'); $ret = $model->delete(array('dependent' => $e->getParam('module'))); + /* if ($ret < count($config['dependency'])) { $result = $e->getParam('result'); $result['dependency'] = array( @@ -164,6 +158,8 @@ public function removeDependency(Event $e) $e->setParam('result', $result); return false; } + */ return true; } + } diff --git a/lib/Pi/Application/Installer/Action/Activate.php b/lib/Pi/Application/Installer/Action/Activate.php index 2e33427bb6..43f1b3d08f 100644 --- a/lib/Pi/Application/Installer/Action/Activate.php +++ b/lib/Pi/Application/Installer/Action/Activate.php @@ -27,8 +27,8 @@ class Activate extends AbstractAction protected function attachDefaultListeners() { $events = $this->events; - $events->attach('install.pre', array($this, 'checkIndependent')); - $events->attach('install.post', array($this, 'createDependency')); + $events->attach('activate.pre', array($this, 'checkIndependent')); + $events->attach('activate.post', array($this, 'createDependency')); return $this; } diff --git a/lib/Pi/Application/Installer/Action/Deactivate.php b/lib/Pi/Application/Installer/Action/Deactivate.php index c7dc700f21..b2b9ff51ec 100644 --- a/lib/Pi/Application/Installer/Action/Deactivate.php +++ b/lib/Pi/Application/Installer/Action/Deactivate.php @@ -27,8 +27,8 @@ class Deactivate extends AbstractAction protected function attachDefaultListeners() { $events = $this->events; - $events->attach('install.pre', array($this, 'checkDependent')); - $events->attach('install.post', array($this, 'removeDependency')); + $events->attach('deactivate.pre', array($this, 'checkDependent')); + $events->attach('deactivate.post', array($this, 'removeDependency')); return $this; } diff --git a/lib/Pi/Application/Installer/Action/Uninstall.php b/lib/Pi/Application/Installer/Action/Uninstall.php index d2f12511f9..1a87a1f0d5 100644 --- a/lib/Pi/Application/Installer/Action/Uninstall.php +++ b/lib/Pi/Application/Installer/Action/Uninstall.php @@ -28,8 +28,8 @@ protected function attachDefaultListeners() { $events = $this->events; //$events->attach('install.pre', array($this, 'loadConfig')); - $events->attach('install.pre', array($this, 'checkDependent')); - $events->attach('install.post', array($this, 'removeDependency')); + $events->attach('uninstall.pre', array($this, 'checkDependent')); + $events->attach('uninstall.post', array($this, 'removeDependency')); //$events->attach('install.post', array($this->installer, 'updateMeta')); return $this; } diff --git a/lib/Pi/Application/Installer/Resource/Acl.php b/lib/Pi/Application/Installer/Resource/Acl.php index a84d3cec53..9db99cdd67 100644 --- a/lib/Pi/Application/Installer/Resource/Acl.php +++ b/lib/Pi/Application/Installer/Resource/Acl.php @@ -101,6 +101,7 @@ public function installAction() { $module = $this->event->getParam('module'); // Create module access permissions + // System module permissions if ('system' == $module) { $modulePerms = array( 'front' => array( @@ -122,6 +123,7 @@ public function installAction() 'staff' => 0, ) ); + // Regular module permissions } else { $modulePerms = array( 'front' => array( @@ -144,21 +146,11 @@ public function installAction() ) ); } + // Add permission rules $modelRule = Pi::model('acl_rule'); foreach ($modulePerms as $section => $access) { foreach ($access as $role => $rule) { AclHandler::addRule($rule, $role, 'module-' . $section, $module, $module); - /* - $data = array( - 'role' => $role, - 'resource' => $module, - 'section' => 'module-' . $section, - 'module' => $module, - 'deny' => empty($rule) ? 1 : 0, - ); - $row = $modelRule->createRow($data); - $row->save(); - */ } } @@ -168,6 +160,7 @@ public function installAction() return true; } + // Add roles if (!empty($this->config['roles'])) { $inheritance = array(); foreach ($this->config['roles'] as $name => $role) { @@ -205,6 +198,7 @@ public function installAction() } } + // Add resources $resources = isset($this->config['resources']) ? $this->config['resources'] : array(); foreach ($resources as $section => $resourceList) { foreach ($resourceList as $name => $resource) { @@ -399,17 +393,19 @@ public function uninstallAction() 'module' => $module, 'type' => 'system' )); - $resources = array(); + //$resources = array(); foreach ($rowset as $row) { - $resources[] = $row->id; + //$resources[] = $row->id; $this->deleteResource($row); } + /* if ($resources) { $where = array('module' => $module, 'resource' => $resources); foreach (array('acl_rule', 'acl_privilege') as $modelName) { Pi::model($modelName)->delete($where); } } + */ Pi::model('acl_rule')->delete(array('module' => $module)); Pi::service('registry')->moduleperm->flush(); @@ -459,7 +455,7 @@ protected function insertInherit($pair, &$message) protected function insertResource($resource, &$message) { $modelResource = Pi::model('acl_resource'); - $modelRule = Pi::model('acl_rule'); + //$modelRule = Pi::model('acl_rule'); $modelPrivilege = Pi::model('acl_privilege'); $data = $this->canonizeResource($resource); @@ -509,22 +505,6 @@ protected function insertResource($resource, &$message) if (isset($privilege['access'])) { foreach ($privilege['access'] as $role => $rule) { AclHandler::addRule($rule, $role, $resource['section'], $resource['module'], $resourceId, $name); - /* - $data = array( - 'role' => $role, - 'resource' => $resourceId, - 'section' => $resource['section'], - 'module' => $resource['module'], - 'deny' => empty($rule) ? 1 : 0, - ); - $data['privilege'] = $name; - $row = $modelRule->createRow($data); - $row->save(); - if (!$row->id) { - $message[] = sprintf('Rule "%s" is not created.', implode('-', array_values($data))); - return false; - } - */ } } } @@ -532,21 +512,6 @@ protected function insertResource($resource, &$message) } elseif (isset($resource['access'])) { foreach ($resource['access'] as $role => $rule) { AclHandler::addRule($rule, $role, $resource['section'], $resource['module'], $resourceId); - /* - $data = array( - 'role' => $role, - 'resource' => $resourceId, - 'section' => $resource['section'], - 'module' => $resource['module'], - 'deny' => empty($rule) ? 1 : 0, - ); - $row = $modelRule->createRow($data); - $row->save(); - if (!$row->id) { - $message[] = sprintf('Rule "%s" is not created.', implode('-', array_values($data))); - return false; - } - */ } } @@ -600,22 +565,6 @@ protected function updateResource($resource, &$message) if (isset($privilege['access'])) { foreach ($privilege['access'] as $role => $rule) { AclHandler::addRule($rule, $role, $resource['section'], $resource['module'], $resourceId, $name); - /* - $data = array( - 'role' => $role, - 'resource' => $resourceId, - 'section' => $resource['section'], - 'module' => $resource['module'], - 'deny' => empty($rule) ? 1 : 0, - ); - $data['privilege'] = $name; - $row = $modelRule->createRow($data); - $row->save(); - if (!$row->id) { - $message[] = sprintf('Rule "%s" is not created.', implode('-', array_values($data))); - return false; - } - */ } } } @@ -632,11 +581,24 @@ protected function deleteResource($resource, &$message = null) if (is_scalar($resource)) { $resourceRow = $modelResource->find($resource); } else { - $resourceRow = $resource; + $resourceRow = $modelResource->find($resource->id); + } + $resources = array(); + $children = $modelResource->getChildren($resourceRow); + foreach ($children as $row) { + $resources[] = array( + 'section' => $row->section, + 'module' => $row->module, + 'resource' => $row->id, + ); + } + $modelResource->remove($resourceRow, true); + foreach ($resources as $data) { + $modelRule->delete($data); + + unset($data['section']); + $modelPrivilege->delete($data); } - $modelResource->remove($resourceRow); - $modelRule->delete(array('section' => $resourceRow->section, 'resource' => $resource->id)); - $modelPrivilege->delete(array('resource' => $resource->id)); return true; } } diff --git a/lib/Pi/Application/Installer/Resource/Config.php b/lib/Pi/Application/Installer/Resource/Config.php index 844c68bc27..8616f16b50 100644 --- a/lib/Pi/Application/Installer/Resource/Config.php +++ b/lib/Pi/Application/Installer/Resource/Config.php @@ -144,11 +144,18 @@ protected function canonize($config) ); } - // Check item name + // Formulate config name and order + $order = 1; foreach ($ret['item'] as $key => &$item) { if (!isset($item['name'])) { $item['name'] = strval($key); } + $item['order'] = $order++; + } + // Formulate category order + $order = 1; + foreach ($ret['category'] as $key => &$item) { + $item['order'] = $order++; } return $ret; @@ -181,12 +188,14 @@ public function installAction() $config = $this->canonize($this->config); if (!empty($config['category'])) { $modelCategory = Pi::model('config_category'); - $order = 0; + //$order = 0; foreach ($config['category'] as $category) { $category['module'] = $module; + /* if (!isset($category['order'])) { $category['order'] = ++$order; } + */ $status = $modelCategory->insert($category); if (!$status) { return array( @@ -198,11 +207,13 @@ public function installAction() } $model = Pi::model('config'); - $order = 0; + //$order = 0; foreach ($config['item'] as $item) { + /* if (!isset($item['order'])) { $item['order'] = ++$order; } + */ $item = $this->canonizeConfig($item); $row = $model->createRow($item); $status = $row->save(); @@ -256,7 +267,7 @@ public function updateAction() $row->name = $categories[$key]['name']; $isChanged = true; } - if (isset($categories[$key]['order']) && $categories[$key]['order'] != $row->order) { + if ($categories[$key]['order'] != $row->order) { $row->order = $categories[$key]['order']; $isChanged = true; } diff --git a/lib/Pi/Application/Installer/Resource/Navigation.php b/lib/Pi/Application/Installer/Resource/Navigation.php index ac2efd7bdd..825c272915 100644 --- a/lib/Pi/Application/Installer/Resource/Navigation.php +++ b/lib/Pi/Application/Installer/Resource/Navigation.php @@ -297,16 +297,6 @@ public function updateAction() // Delete deprecated node } else { $row->delete(); - /* - $status = $this->deleteNavigationNode($row, $message); - if (!$status) { - $message[] = sprintf('Deprecated navigation node "%s" is not deleted.', $row->navigation); - return array( - 'status' => false, - 'message' => $message - ); - } - */ } } // Add new nodes @@ -347,16 +337,6 @@ public function uninstallAction() $rowset = $model->select(array('module' => $module)); foreach ($rowset as $row) { $row->delete(); - /* - $status = $this->deleteNavigationNode($row, $message); - if (!$status) { - $message[] = sprintf('Deprecated navigation node "%s" is not deleted.', $row->navigation); - return array( - 'status' => false, - 'message' => $message - ); - } - */ } Pi::service('registry')->navigation->flush(); @@ -370,7 +350,6 @@ public function activateAction() // update role active => 1 $where = array('module' => $module); Pi::model('navigation')->update(array('active' => 1), $where); - //Pi::model('navigation_node')->update(array('active' => 1), $where); Pi::service('registry')->navigation->flush(); Pi::service('cache')->clearByNamespace('nav'); } @@ -382,7 +361,6 @@ public function deactivateAction() // update role active => 1 $where = array('module' => $module); Pi::model('navigation')->update(array('active' => 0), $where); - //Pi::model('navigation_node')->update(array('active' => 0), $where); Pi::service('registry')->navigation->flush(); Pi::service('cache')->clearByNamespace('nav'); } @@ -449,7 +427,6 @@ protected function deleteNavigation($navigationRow, &$message) if ($row) { $row->delete(); } - //$this->deleteNavigationNode($navigationRow->name, $message); return true; } diff --git a/lib/Pi/Application/Installer/Resource/Page.php b/lib/Pi/Application/Installer/Resource/Page.php index de57d1edad..ef1e33abd9 100644 --- a/lib/Pi/Application/Installer/Resource/Page.php +++ b/lib/Pi/Application/Installer/Resource/Page.php @@ -146,16 +146,22 @@ protected function canonizePage($config) { $moduleTitle = $this->event->getParam('title'); $pageEntry = array( - 'title' => $moduleTitle, + 'title' => $moduleTitle . ' *', ); // Set module exception for admin if (empty($config['admin']) && !isset($config['exception'])) { $config['exception'] = array($pageEntry); } if (!isset($config['front']) || false !== $config['front']) { + if (!isset($config['front'])) { + $config['front'] = array(); + } $config['front'][] = $pageEntry; } if (!isset($config['admin']) || false !== $config['admin']) { + if (!isset($config['admin'])) { + $config['admin'] = array(); + } $config['admin'][] = $pageEntry; } @@ -169,7 +175,7 @@ public function installAction() return; } $module = $this->event->getParam('module'); - $moduleTitle = $this->event->getParam('title'); + //$moduleTitle = $this->event->getParam('title'); Pi::service('registry')->page->clear($module); $pages = $this->canonizePage($this->config); @@ -192,18 +198,6 @@ public function installAction() } $pageList[$pageName] = $page; } - /* - // Set up module pseudo page - if (!isset($pageList[$module])) { - $pageList[$module] = array( - 'section' => $section, - 'module' => $module, - 'name' => $module, - 'title' => $moduleTitle, - 'block' => ('front' == $section) ? 1 : 0, - ); - } - */ // Sort page list by module-controller-action ksort($pageList); $pages[$section] = $pageList; @@ -431,21 +425,7 @@ protected function insertPage($page, &$message) // Set rules of accessing the resource by each role if (isset($page['permission']['access'])) { foreach ($page['permission']['access'] as $role => $rule) { - AclHandler::addRule($rule, $role, $resource['section'], $resourceId, $module); - /* - $data = array(); - $data['role'] = $role; - $data['resource'] = $resourceId; - $data['section'] = $resource['section']; - $data['module'] = $module; - $data['deny'] = empty($rule) ? 1 : 0; - $rowRule = $modelRule->createRow($data); - $rowRule->save(); - if (!$rowRule->id) { - $message[] = sprintf('Rule "%s" is not saved', implode('-', array_values($data))); - return false; - } - */ + AclHandler::addRule($rule, $role, $resource['section'], $module, $resourceId); } } diff --git a/lib/Pi/Application/Registry/Modulelist.php b/lib/Pi/Application/Registry/Modulelist.php index 4c0adcc286..8cb0aed135 100644 --- a/lib/Pi/Application/Registry/Modulelist.php +++ b/lib/Pi/Application/Registry/Modulelist.php @@ -51,7 +51,7 @@ protected function loadDynamic($options) 'version' => $module->version, 'directory' => $module->directory, 'update' => $module->update, - 'logo' => $info['logo'], + 'logo' => isset($info['logo']) ? $info['logo'] : '', ); } diff --git a/lib/Pi/Application/Registry/Navigation.php b/lib/Pi/Application/Registry/Navigation.php index 2a9f990bf3..0237e5f88e 100644 --- a/lib/Pi/Application/Registry/Navigation.php +++ b/lib/Pi/Application/Registry/Navigation.php @@ -117,7 +117,7 @@ protected function loadNavigation($options) $row = Pi::model('navigation_node')->find($name, 'navigation'); if (!$row) { - return false; + return array(); } $this->module = $row->module; @@ -214,13 +214,15 @@ protected function translateConfig($config, $domain, $locale) } */ - Pi::service('i18n')->load($domain, $locale); + if ($config) { + Pi::service('i18n')->load($domain, $locale); - //d($config); - foreach ($config as $p => &$page) { - $this->translatePage($page, $config, $p, true); + //d($config); + foreach ($config as $p => &$page) { + $this->translatePage($page, $config, $p, true); + } + //d($config); } - //d($config); return $config; } diff --git a/lib/Pi/Application/Resource/I18n.php b/lib/Pi/Application/Resource/I18n.php index 9360338f88..13c7f1f1af 100644 --- a/lib/Pi/Application/Resource/I18n.php +++ b/lib/Pi/Application/Resource/I18n.php @@ -42,11 +42,11 @@ public function boot() $locale = $locale ?: (isset($this->options['locale']) ? $this->options['locale'] : null); $charset = $charset ?: (isset($this->options['charset']) ? $this->options['charset'] : null); + // Set default locale Pi::service('i18n')->setLocale($locale); - //$locale = new Locale($locale, $charset); setlocale(LC_ALL, $locale); - //Pi::registry('locale', $locale); + // Preload translations if (!empty($this->options['translator'])) { $translator = Pi::service('i18n')->translator; if (!empty($this->options['translator']['global'])) { diff --git a/lib/Pi/Application/Resource/Security.php b/lib/Pi/Application/Resource/Security.php index e446aed80e..23b805ace1 100644 --- a/lib/Pi/Application/Resource/Security.php +++ b/lib/Pi/Application/Resource/Security.php @@ -20,7 +20,8 @@ namespace Pi\Application\Resource; -use Pi\Security as SecurityUtility; +use Pi; +//use Pi\Security\Security as SecurityUtility; class Security extends AbstractResource { @@ -33,14 +34,14 @@ public function boot() { $options = $this->options; foreach ($options as $type => $opt) { - if (empty($opt)) { + if (false === $opt) { continue; } - $status = SecurityUtility::$type($opt); + $status = Pi::service('security')->{$type}($opt); if ($status) return true; if (false === $status) { return false; - SecurityUtility::deny($type); + //Pi::service('security')->deny($type); } } } diff --git a/lib/Pi/Application/Resource/Session.php b/lib/Pi/Application/Resource/Session.php index 04a685c6f5..723914ba6e 100644 --- a/lib/Pi/Application/Resource/Session.php +++ b/lib/Pi/Application/Resource/Session.php @@ -29,7 +29,21 @@ class Session extends AbstractResource */ public function boot() { - Pi::service('session')->manager()->start(); + try { + // Attempt to start session + Pi::service('session')->manager()->start(); + } catch (\Exception $e) { + // Clear session data for current request on failure + // Empty session for current request + Pi::service('session')->manager()->getStorage()->clear(); + // Disconnect cookie for current user + Pi::service('session')->manager()->expireSessionCookie(); + // Log error attempts + if (Pi::service()->hasService('log')) { + Pi::service('log')->audit($e->getMessage()); + } + trigger_error($e->getMessage(), E_USER_ERROR); + } return; } } diff --git a/lib/Pi/Application/Service/Cache.php b/lib/Pi/Application/Service/Cache.php index 56976dd9b9..d5d8840625 100644 --- a/lib/Pi/Application/Service/Cache.php +++ b/lib/Pi/Application/Service/Cache.php @@ -19,8 +19,9 @@ */ namespace Pi\Application\Service; + use Pi; -//use Pi\Cache\Storage\AdapterPluginManager; +use Pi\Cache\Storage\AdapterPluginManager; use Zend\Cache\StorageFactory; use Zend\Cache\Storage\Adapter\AbstractAdapter; @@ -66,7 +67,7 @@ public function loadStorage($config = array()) $config['adapter']['options']['namespace'] = ''; } $config['adapter']['options']['namespace'] = $this->getNamespace($config['adapter']['options']['namespace']); - //StorageFactory::setAdapterPluginManager(new AdapterPluginManager); + StorageFactory::setAdapterPluginManager(new AdapterPluginManager); $storage = StorageFactory::factory($config); return $storage; diff --git a/lib/Pi/Application/Service/I18n.php b/lib/Pi/Application/Service/I18n.php index f1edf8987e..e12527921f 100644 --- a/lib/Pi/Application/Service/I18n.php +++ b/lib/Pi/Application/Service/I18n.php @@ -137,6 +137,75 @@ * * __('A test message', 'theme/default', 'en'); * + * + * 7. Format a date + * + * _date(time(), 'fa-IR', 'long', 'short', 'Asia/Tehran', 'persian'); + * _date(time(), array('locale' => 'fa-IR', 'datetype' => 'long', 'timetype' => 'short', 'timezone' => 'Asia/Tehran', 'calendar' => 'persian')); + * + * _date(time(), null, 'long', 'short', 'Asia/Tehran', 'persian'); + * _date(time(), array('datetype' => 'long', 'timetype' => 'short', 'timezone' => 'Asia/Tehran', 'calendar' => 'persian')); + * + * _date(time(), 'fa-IR@calendar=persian', 'long', 'short', 'Asia/Tehran'); + * _date(time(), array('locale' => 'fa-IR@calendar=persian', 'datetype' => 'long', 'timetype' => 'short', 'timezone' => 'Asia/Tehran')); + * + * _date(time(), null, null, null, null, 'persian'); + * _date(time(), array('calendar' => 'persian')); + * + * _date(time(), 'fa-IR', null, null, null, null, 'yyyy-MM-dd HH:mm:ss'); + * _date(time(), array('locale' => 'fa-IR', 'pattern' => 'yyyy-MM-dd HH:mm:ss')); + * + * _date(time(), null, null, null, null, null, 'yyyy-MM-dd HH:mm:ss'); + * _date(time(), array('pattern' => 'yyyy-MM-dd HH:mm:ss')); + * + * _date(time()); + * + * // In case Intl is not available, pass a format string for legacy date() function + * _date(time(), 'fa-IR', null, null, null, null, 'yyyy-MM-dd HH:mm:ss', 'Y-m-d H:i:s'); + * _date(time(), array('locale' => 'fa-IR', 'pattern' => 'yyyy-MM-dd HH:mm:ss', 'format' => 'Y-m-d H:i:s')); + * // Format defined in system intl config (Pi::config('date_format', 'intl')) will be used if format is not specified + * _date(time(), ...); + * + * + * 8. Format a number + * + * _number(123.4567, 'decimal', '#0.# kg', 'zh-CN', 'default'); + * _number(123.4567, 'decimal', '#0.# kg', 'zh-CN'); + * _number(123.4567, 'scientific'); + * _number(123.4567, 'spellout'); + * + * + * 9. Format a currency + * + * _currency(123.45, 'USD', 'en-US'); + * _currency(123.45, 'USD'); + * _currency(123.45); + * + * + * 10. Get a date formatter + * + * Pi::service('i18n')->getDateFormatter('fa-IR', 'long', 'short', 'Asia/Tehran', 'persian'); + * Pi::service('i18n')->getDateFormatter(array('locale' => 'fa-IR', 'datetype' => 'long', 'timetype' => 'short', 'timezone' => 'Asia/Tehran', 'calendar' => 'persian')); + * + * Pi::service('i18n')->getDateFormatter('fa-IR@calendar=persian', 'long', 'short', 'Asia/Tehran'); + * Pi::service('i18n')->getDateFormatter(array('locale' => 'fa-IR@calendar=persian', 'datetype' => 'long', 'timetype' => 'short', 'timezone' => 'Asia/Tehran')); + * + * Pi::service('i18n')->getDateFormatter(null, null, null, null, null, 'yyyy-MM-dd HH:mm:ss'); + * Pi::service('i18n')->getDateFormatter(array('pattern' => 'yyyy-MM-dd HH:mm:ss')); + * + * + * 11. Get a number formatter + * + * // Get a number formatter + * Pi::service('i18n')->getNumberFormatter('decimal', '#0.# kg', 'zh-CN'); + * Pi::service('i18n')->getNumberFormatter('decimal', '', 'zh-CN'); + * Pi::service('i18n')->getNumberFormatter('decimal'); + * Pi::service('i18n')->getNumberFormatter('scientific'); + * Pi::service('i18n')->getNumberFormatter('spellout'); + * // Get a currency formatter + * Pi::service('i18n')->getNumberFormatter('currency', '', 'zh-CN'); + * Pi::service('i18n')->getNumberFormatter('currency'); + * */ namespace Pi\Application\Service @@ -145,6 +214,15 @@ use Pi\I18n\Translator\LoaderPluginManager; use Pi\I18n\Translator\Translator; + /**#@+ + * Internationalization Functions + * @see http://www.php.net/manual/en/book.intl.php + */ + use IntlDateFormatter; + use NumberFormatter; + use Collator; + /**#@-*/ + class I18n extends AbstractService { //const NAMESPACE_GLOBAL = '_usr'; @@ -167,27 +245,6 @@ class I18n extends AbstractService */ protected $__translator; - /** - * \Collator - */ - protected $__collator; - /* - * \NumberFormatter - */ - protected $__numberFormatter; - /* - * \MessageFormatter - */ - protected $__messageFormatter; - /* - * \IntlDateFormatter - */ - protected $__dateFormatter; - /* - * \Transliterator - */ - protected $__transliterator; - /** * Get translator, instantiate it if not available * @@ -270,21 +327,19 @@ public function __get($name) case 'locale': return $this->getLocale(); break; - case 'collator': - if (!$this->__collator) { - $this->__collator = new \Collator($this->locale); - } - return $this->__collator; + case 'numberFormatter': + return $this->getNumberFormatter(); + break; + case 'dateFormatter': + return $this->getDateFormatter(); break; /**#@+ * @todo To implement the Intl extensions */ - case 'numberFormatter': + case 'collator': break; case 'messageFormatter': break; - case 'dateFormatter': - break; case 'transliterator': break; default: @@ -421,7 +476,95 @@ public function translate($message, $domain = null, $locale = null) return $this->getTranslator()->translate($message, $domain, $locale); } + + /** + * Load date formatter + * + * @see IntlDateFormatter + * + * @param array|string|null $locale + * @param string|null $datetype Valid values: 'NULL', 'FULL', 'LONG', 'MEDIUM', 'SHORT' + * @param string|null $timetype Valid values: 'NULL', 'FULL', 'LONG', 'MEDIUM', 'SHORT' + * @param string|null $timezone + * @param int|string|null $calendar + * @param string|null $pattern Be aware that both datetype and timetype are ignored if the pattern is set. + * @return IntlDateFormatter + */ + public function getDateFormatter($locale = null, $datetype = null, $timetype = null, $timezone = null, $calendar = null, $pattern = null) + { + if (!class_exists('IntlDateFormatter')) { + return null; + } + + if (is_array($locale)) { + $params = $locale; + foreach (array('locale', 'datetype', 'timetype', 'timezone', 'calendar', 'pattern') as $key) { + ${$key} = isset($params[$key]) ? $params[$key] : null; + } + } + + if (!$locale) { + $locale = $this->getLocale(); + } elseif (strpos($locale, '@')) { + $calendar = IntlDateFormatter::TRADITIONAL; + } + + if (null === $calendar) { + $calendar = Pi::config('date_calendar', 'intl'); + if (!$calendar) { + $calendar = IntlDateFormatter::GREGORIAN; + } + } + if ($calendar && !is_numeric($calendar)) { + $locale .= '@calendar=' . $calendar; + $calendar = IntlDateFormatter::TRADITIONAL; + } + if (null === $calendar) { + $calendar = IntlDateFormatter::GREGORIAN; + } + + $datetype = constant('IntlDateFormatter::' . strtoupper($datetype ?: Pi::config('date_datetype', 'intl'))); + $timetype = constant('IntlDateFormatter::' . strtoupper($timetype ?: Pi::config('date_timetype', 'intl'))); + $timezone = $timezone ?: Pi::config('timezone'); + + $formatter = new IntlDateFormatter($locale, $datetype, $timetype, $timezone, $calendar); + + if ($pattern) { + $formatter->setPattern($pattern); + } + + return $formatter; + } + + /** + * Load number formatter + * + * @see NumberFormatter + * + * @param string|null $style + * @param string|null $pattern + * @param string|null $locale + * @return NumberFormatter + */ + public function getNumberFormatter($style = null, $pattern = null, $locale = null) + { + if (!class_exists('NumberFormatter')) { + return null; + } + + $locale = $locale ?: $this->getLocale(); + $style = $style ?: Pi::config('number_style', 'intl'); + $style = $style ? constant('NumberFormatter::' . strtoupper($style)) : NumberFormatter::DEFAULT_STYLE; + $formatter = new NumberFormatter($locale, $style); + + if ($pattern) { + $formatter->setPattern($pattern); + } + + return $formatter; + } } + } /**#@+ @@ -453,5 +596,96 @@ function _e($message, $domain = null, $locale = null) { echo __($message, $domain, $locale); } + + /** + * Check if Intl functions are available + */ + function _intl() + { + return extension_loaded('intl') ? true : false; + } + + /** + * Locale-dependent formatting/parsing of date-time using pattern strings and/or canned patterns + * + * @param array|string|null $locale + * @param string|null $datetype Valid values: 'NULL', 'FULL', 'LONG', 'MEDIUM', 'SHORT' + * @param string|null $timetype Valid values: 'NULL', 'FULL', 'LONG', 'MEDIUM', 'SHORT' + * @param string|null $timezone + * @param int|string|null $calendar + * @param string|null $pattern Be aware that both datetype and timetype are ignored if the pattern is set. + * @param string|null $format Legacy format for date() in case Intl is not available + * @return string + */ + function _date($value, $locale = null, $datetype = null, $timetype = null, $timezone = null, $calendar = null, $pattern = null, $format = null) + { + // Formatted using date() in case Intl is not available + if (!_intl()) { + if (is_array($locale)) { + $format = isset($locale['format']) ? $locale['format'] : $format; + } + if (!$format) { + $format = Pi::config('date_format', 'intl'); + } + $result = date($format, $value); + + return $result; + } + + $formatter = Pi::service('i18n')->getDateFormatter($locale, $datetype, $timetype, $timezone, $calendar, $pattern); + $result = $formatter->format($value); + + return $result; + } + + /** + * Locale-dependent formatting/parsing of number using pattern strings and/or canned patterns + * + * @param string|null $style + * @param string|null $pattern + * @param string|null $locale + * @param string|null $type + * @return mixed + */ + function _number($value, $style = null, $pattern = null, $locale = null, $type = null) + { + // Return raw data in case Intl is not available + if (!_intl()) { + return $value; + } + + $formatter = Pi::service('i18n')->getNumberFormatter($style, $pattern, $locale); + if ($type) { + $type = constant('NumberFormatter::TYPE_' . strtoupper($type)); + $result = $formatter->format($value, $type); + } else { + $result = $formatter->format($value); + } + + return $result; + } + + /** + * Locale-dependent formatting/parsing of number using pattern strings and/or canned patterns + * + * @param string|null $currency + * @param string|null $locale + * @return string + */ + function _currency($value, $currency = null, $locale = null) + { + if (!_intl()) { + return false; + } + $result = $value; + $currency = (null === $currency) ? Pi::config('number_currency', 'intl') : $currency; + if ($currency) { + $style = 'CURRENCY'; + $formatter = Pi::service('i18n')->getNumberFormatter($style, $locale); + $result = $formatter->formatCurrency($value, $currency); + } + + return $result; + } } -/**#@-*/ +/**#@-*/ \ No newline at end of file diff --git a/lib/Pi/Application/Service/Log.php b/lib/Pi/Application/Service/Log.php index 1ed614d0d7..a6636aceb0 100644 --- a/lib/Pi/Application/Service/Log.php +++ b/lib/Pi/Application/Service/Log.php @@ -125,7 +125,7 @@ public function active($flag = null) } } elseif (null === $this->active) { if (!empty($this->options['ip'])) { - $this->active = (bool) Pi\Security::ip(array('good' => $this->options['ip'])); + $this->active = (bool) Pi::service('security')->ip(array('good' => $this->options['ip'])); } else { $this->active = true; } diff --git a/lib/Pi/Application/Service/Security.php b/lib/Pi/Application/Service/Security.php new file mode 100644 index 0000000000..c35b8bb790 --- /dev/null +++ b/lib/Pi/Application/Service/Security.php @@ -0,0 +1,151 @@ + + * @package Pi\Application + * @subpackage Service + */ + +namespace Pi\Application\Service; + +use Pi; +use Pi\Security\Security as SecurityUtility; +use Zend\Escaper\Escaper; + +class Security extends AbstractService +{ + protected $fileIdentifier = 'security'; + protected $paths; + + /** + * Header outputs on deny + * + * @param string $message The message to be displayed + * @return void + */ + public function deny($message = '') + { + if (!headers_sent()) { + if (substr(PHP_SAPI, 0, 3) == 'cgi') { + header('Status: 403 Forbidden'); + } else { + header('HTTP/1.1 403 Forbidden'); + } + } + exit('Access denied' . ($message ? ': ' . $message : '.')); + } + + /** + * Remove path prefix for security considerations + * + * @param string $str + * @return string + */ + public function path($str) + { + if (!isset($this->paths)) { + // Loads all path settings from host data + $paths = Pi::host()->get('path'); + $lengths = array(); + foreach ($paths as $root => $v) { + $lengths[] = strlen($v); + } + // Sort the paths by their lengths in reverse + array_multisort($lengths, SORT_NUMERIC, SORT_DESC, $paths); + $this->paths = $paths; + } + if (DIRECTORY_SEPARATOR != '/') { + $str = str_replace(DIRECTORY_SEPARATOR, '/', $str); + } + foreach ($this->paths as $root => $v) { + if (empty($v) || empty($root)) { + continue; + } + $str = str_replace($v . '/', $root . '/', $str); + } + return $str; + } + + /** + * Remove DB database name and table prefix for security considerations + * + * @param string $str + * @return string + */ + public function db($str) + { + $pattern = '/\b' . preg_quote(Pi::db()->getTablePrefix()) . '/i'; + $return = preg_replace($pattern, '', $str); + return $return; + } + + /** + * Get escaper, and escape HTML content if specified + * + * @param string|null $content + * @return Escaper|string + */ + public function escape($content = null) + { + $escaper = new Escaper(Pi::config('charset')); + if (null === $content) { + return $escaper; + } + return $escaper->escapeHtml($content); + } + + /**#@++ + * Check security settings + * + * Policy: Returns TRUE will cause process quite and the current request will be approved; returns FALSE will cause process quit and request will be denied + */ + + /** + * Check for IPs + */ + public function ip($options = null) + { + if (!is_array($options) && isset($this->options['ip'])) { + $options = $this->options['ip']; + } + return SecurityUtility::ip($options); + } + + /** + * Check for super globals + */ + public function globals($options = null) + { + if (!is_array($options) && isset($this->options['globals'])) { + $options = $this->options['globals']; + } + return SecurityUtility::globals($options); + } + + /** + * Magic method to access custom security settings + * + * @param string $method The security setting to be checked + * @param array $args arguments for the setting + */ + public function __call($method, $args = array()) + { + $options = $args ? $args[0] : null; + if (!is_array($options) && isset($this->options[$method])) { + $options = $this->options[$method]; + } + return SecurityUtility::$method($options); + } + /*#@-*/ + +} diff --git a/lib/Pi/Cache/Storage/Adapter/Filesystem.php b/lib/Pi/Cache/Storage/Adapter/Filesystem.php new file mode 100644 index 0000000000..060b024849 --- /dev/null +++ b/lib/Pi/Cache/Storage/Adapter/Filesystem.php @@ -0,0 +1,260 @@ + + * @since 3.0 + * @package Pi\Cache + * @version $Id$ + */ + +namespace Pi\Cache\Storage\Adapter; + +use Zend\Cache\Storage\Adapter\Filesystem as ZendFilesystem; +use Exception as BaseException; +use Zend\Cache\Storage\Adapter\Exception; + +class Filesystem extends ZendFilesystem +{ + /** + * Internal method to get an item. + * + * @param string $normalizedKey + * @param bool $success + * @param mixed $casToken + * @return mixed Data on success, null on failure + * @throws Exception\ExceptionInterface + */ + protected function internalGetItem(& $normalizedKey, & $success = null, & $casToken = null) + { + /* + if (!$this->internalHasItem($normalizedKey)) { + $success = false; + return null; + } + */ + + try { + $filespec = $this->getFileSpec($normalizedKey); + $data = $this->getFileData($filespec . '.dat'); + + // use filemtime + filesize as CAS token + if (func_num_args() > 2) { + $casToken = filemtime($filespec . '.dat') . filesize($filespec . '.dat'); + } + $success = (null === $data) ? false : true; + return $data; + + } catch (BaseException $e) { + $success = false; + throw $e; + } + } + + /** + * Internal method to get multiple items. + * + * @param array $normalizedKeys + * @return array Associative array of keys and values + * @throws Exception\ExceptionInterface + */ + protected function internalGetItems(array & $normalizedKeys) + { + //$options = $this->getOptions(); + $keys = $normalizedKeys; // Don't change argument passed by reference + $result = array(); + while ($keys) { + + // LOCK_NB if more than one items have to read + $nonBlocking = count($keys) > 1; + $wouldblock = null; + + // read items + foreach ($keys as $i => $key) { + /* + if (!$this->internalHasItem($key)) { + unset($keys[$i]); + continue; + } + */ + + $filespec = $this->getFileSpec($key); + $data = $this->getFileData($filespec . '.dat', $nonBlocking, $wouldblock); + if ($nonBlocking && $wouldblock) { + continue; + } else { + unset($keys[$i]); + } + + $result[$key] = $data; + } + + // TODO: Don't check ttl after first iteration + // $options['ttl'] = 0; + } + + return $result; + } + + /** + * Internal method to test if an item exists. + * + * @param string $normalizedKey + * @return bool + */ + protected function internalHasItem(& $normalizedKey) + { + $file = $this->getFileSpec($normalizedKey) . '.dat'; + if (!$this->fileValid($file)) { + return false; + } + + return true; + } + + /** + * Internal method to store an item. + * + * @param string $normalizedKey + * @param mixed $value + * @return bool + * @throws Exception\ExceptionInterface + */ + protected function internalSetItem(& $normalizedKey, & $value) + { + $filespec = $this->getFileSpec($normalizedKey); + + $this->prepareDirectoryStructure($filespec); + + // write data in non-blocking mode + $wouldblock = null; + $this->putFileData($filespec . '.dat', $value, true, $wouldblock); + + // delete related tag file (if present) + $this->unlink($filespec . '.tag'); + + // Retry writing data in blocking mode if it was blocked before + if ($wouldblock) { + $this->putFileData($filespec . '.dat', $value); + } + + return true; + } + + /** + * Internal method to store multiple items. + * + * @param array $normalizedKeyValuePairs + * @return array Array of not stored keys + * @throws Exception\ExceptionInterface + */ + protected function internalSetItems(array & $normalizedKeyValuePairs) + { + //$oldUmask = null; + + // create an associated array of files and contents to write + $contents = array(); + foreach ($normalizedKeyValuePairs as $key => & $value) { + $filespec = $this->getFileSpec($key); + $this->prepareDirectoryStructure($filespec); + + // *.dat file + $contents[$filespec . '.dat'] = & $value; + + // *.tag file + $this->unlink($filespec . '.tag'); + } + + // write to disk + while ($contents) { + $nonBlocking = count($contents) > 1; + $wouldblock = null; + + foreach ($contents as $file => & $content) { + $this->putFileData($file, $content, $nonBlocking, $wouldblock); + if (!$nonBlocking || !$wouldblock) { + unset($contents[$file]); + } + } + } + + // return OK + return array(); + } + + /** + * Read valid cache data + * + * @param string $file File complete path + * @param bool $nonBlocking Don't block script if file is locked + * @param bool $wouldblock The optional argument is set to TRUE if the lock would block + * @return string|null + */ + protected function getFileData($file, $nonBlocking = false, & $wouldblock = null) + { + $result = null; + if (file_exists($file)) { + $content = $this->getFileContent($file, $nonBlocking, $wouldblock); + list($expire, $data) = explode(':', $content, 2); + if (empty($expire) || time() < $expire) { + $result = $data; + } + } + + return $result; + } + + /** + * Check if cache file valid + * + * @param string $file File complete path + * @return bool + */ + protected function fileValid($file) + { + if (!file_exists($file)) { + return false; + } + + $content = $this->getFileContent($file); + $pos = strpos($content, ':'); + if (false === $pos) { + return false; + } + $expire = (int) substr($content, 0, $pos); + if ($expire && time() >= $expire) { + return false; + } + + return true; + } + + /** + * Write cache data to a file + * + * @param string $file File complete path + * @param string $data Data to write + * @param bool $nonBlocking Don't block script if file is locked + * @param bool $wouldblock The optional argument is set to TRUE if the lock would block + * @return void + */ + protected function putFileData($file, $data, $nonBlocking = false, & $wouldblock = null) + { + $expire = 0; + $options = $this->getOptions(); + if ($options->ttl) { + $expire = time() + $options->ttl; + } + $data = $expire . ':' . $data; + $this->putFileContent($file, $data, $nonBlocking, $wouldblock); + } +} \ No newline at end of file diff --git a/lib/Pi/Db/Table/AbstractNest.php b/lib/Pi/Db/Table/AbstractNest.php index a404b1de20..3839a86fcb 100644 --- a/lib/Pi/Db/Table/AbstractNest.php +++ b/lib/Pi/Db/Table/AbstractNest.php @@ -339,11 +339,11 @@ public function reconcile($start = 1, $end = null) $primary = $this->quoteIdentifier($this->primaryKeyColumn); $leftCol = $this->quoteColumn('left'); $rightCol = $this->quoteColumn('right'); - $depthCol = $this->quoteColumn('depth'); + //$depthCol = $this->quoteColumn('depth'); $node = /*'node'*/$this->table; $parent = 'parent'; - $nodeTable = $this->quoteIdentifier($node); + //$nodeTable = $this->quoteIdentifier($node); $parentTable = $this->quoteIdentifier($parent); $select = new Select; $select->columns(array( @@ -580,6 +580,7 @@ public function getRoots($where = null, $order = array()) * * @param mixed $objective target node ID or Node * @param array $cols + * @return Rowset */ public function getAncestors($objective, $cols = null) { @@ -606,6 +607,7 @@ public function getAncestors($objective, $cols = null) * * @param mixed $objective target node ID or Node * @param array $cols + * @return Rowset */ public function getChildren($objective, $cols = null) { diff --git a/lib/Pi/Debug.php b/lib/Pi/Debug/Debug.php similarity index 85% rename from lib/Pi/Debug.php rename to lib/Pi/Debug/Debug.php index 3680021879..bf94fde37b 100644 --- a/lib/Pi/Debug.php +++ b/lib/Pi/Debug/Debug.php @@ -17,18 +17,30 @@ * @version $Id$ */ -namespace Pi +namespace Pi\Debug { + use Pi; + class Debug { protected static $inProcess = null; - public static function enable($flag) + /** + * Loads debugger, nothing to do at this moment + */ + public static function load() + {} + + /** + * Enable/Disable conditional debugging + * + * @param bool $flag + */ + public static function enable($flag = true) { static::$inProcess = $flag; - //echo static::render(sprintf('Conditional debug %s', $flag ? 'enabled' : 'disabled'), 2); $message = static::render(sprintf('Conditional debug %s', $flag ? 'enabled' : 'disabled'), 2); - \Pi::service('log')->debug($message); + Pi::service('log')->debug($message); } /** @@ -46,13 +58,6 @@ public static function conditional($data, $skip = 0) return static::render($data, $skip); } - /** - * Loads debugger, nothing to do at this moment - */ - public static function load() - { - } - /** * Syntatic sugar for displaying debugger information * @@ -62,7 +67,7 @@ public static function e($data) { //echo static::render($data); $message = static::render($data); - \Pi::service('log')->debug($message); + Pi::service('log')->debug($message); } /** @@ -83,9 +88,8 @@ public static function _($data) */ public static function display($data) { - //echo static::render($data); $message = static::render($data); - \Pi::service('log')->debug($message); + Pi::service('log')->debug($message); } /** @@ -102,8 +106,8 @@ public static function render($data, $skip = 0) $list = debug_backtrace(); foreach ($list as $item) { if ($skip-- > 0) continue; - //$location .= basename($item['file']) . ':' . $item['line']; - $location .= $item['file'] . ':' . $item['line']; + $file = Pi::service('security')->path($item['file']); + $location .= $file . ':' . $item['line']; break; } @@ -151,22 +155,24 @@ public static function backtrace($display = true, $skip = 0) $bt = PHP_EOL; $bt .= 'Backtrace at: ' . microtime(true) . PHP_EOL . PHP_EOL; foreach ($list as $backtrace) { - $bt .= (empty($backtrace['file']) ? 'Internal' : $backtrace['file'] . '(' . $backtrace['line'] . ')') . ': ' . (empty($backtrace['class']) ? '' : $backtrace['class'] . '::') . $backtrace['function'] . '()' . PHP_EOL; + $location = empty($backtrace['file']) ? 'Internal' : Pi::service('security')->path($backtrace['file']) . '(' . $backtrace['line'] . ')'; + $bt .= $location . ': ' . (empty($backtrace['class']) ? '' : $backtrace['class'] . '::') . $backtrace['function'] . '()' . PHP_EOL; } $bt .= PHP_EOL; } else { $bt = '
';
                 $bt .= 'Backtrace at: ' . microtime(true) . '
    '; foreach ($list as $backtrace) { - $bt .= '
  • ' . (empty($backtrace['file']) ? 'Internal' : $backtrace['file'] . '(' . $backtrace['line'] . ')') . ': ' . (empty($backtrace['class']) ? '' : $backtrace['class'] . '::') . $backtrace['function'] . '()
  • '; + $location = empty($backtrace['file']) ? 'Internal' : Pi::service('security')->path($backtrace['file']) . '(' . $backtrace['line'] . ')'; + $bt .= '
  • ' . $location . ': ' . (empty($backtrace['class']) ? '' : $backtrace['class'] . '::') . $backtrace['function'] . '()
  • '; } $bt .= '
'; $bt .= '
'; } if ($display) { - if (\Pi::service()->hasService('log')) { - \Pi::service('log')->debug($bt); + if (Pi::service()->hasService('log')) { + Pi::service('log')->debug($bt); } else { echo $bt; } @@ -204,8 +210,7 @@ public static function dump($var, $echo = true) } if ($echo) { - //echo($output); - \Pi::service('log')->debug($output); + Pi::service('log')->debug($output); } return $output; } @@ -240,7 +245,7 @@ public static function dump($var, $echo = true) */ namespace { - use Pi\Debug; + use Pi\Debug\Debug; /** * Displays a debug message @@ -272,7 +277,6 @@ function b() */ function dc($data = '') { - //echo Debug::conditional($data, 2); $output = Debug::conditional($data, 2); if (null !== $output) { Pi::service('log')->debug($output); diff --git a/lib/Pi/File/Transfer/Upload.php b/lib/Pi/File/Transfer/Upload.php index 1c3722f9b4..0c7e97a966 100644 --- a/lib/Pi/File/Transfer/Upload.php +++ b/lib/Pi/File/Transfer/Upload.php @@ -202,51 +202,4 @@ public function getUploaded($name = null, $path = false) } return $result; } - - /** - * Get file(s) info - * - * @return array - */ - public function getInfo() - { - $ret = array(); - $files = $this->getAdapter()->getFileList(); - foreach ($files as $key => $data) { - $ret['name'] = $data['name']; - $ret['size'] = $data['size']; - $ret['type'] = $data['type']; - } - return $ret; - } - - /** - * Get file size - * - * @return size number - */ - public function getSize() - { - return $this->getInfo()['size']; - } - - /** - * Get file name - * - * @return file name - */ - public function getName() - { - return $this->getInfo()['name']; - } - - /** - * Get file Type - * - * @return file Type - */ - public function getType() - { - return $this->getInfo()['type']; - } -} \ No newline at end of file +} diff --git a/lib/Pi/I18n/Translator/Translator.php b/lib/Pi/I18n/Translator/Translator.php index 776bf2334a..6801f3af55 100644 --- a/lib/Pi/I18n/Translator/Translator.php +++ b/lib/Pi/I18n/Translator/Translator.php @@ -226,14 +226,12 @@ public function translatePlural( * @param string $message * @param string $locale * @param string $textDomain - * @param boolean $returnPluralRule * @return string|null */ protected function getTranslatedMessage( $message, $locale = null, - $textDomain = null, - $returnPluralRule = false + $textDomain = null ) { if ($message === '') { return ''; @@ -251,7 +249,7 @@ protected function getTranslatedMessage( return $this->messages[''][$locale][$message]; } - //return parent::getTranslatedMessage($message, $locale, $textDomain, $returnPluralRule); + //return parent::getTranslatedMessage($message, $locale, $textDomain); return null; } diff --git a/lib/Pi/Log/Formatter/DbProfiler.php b/lib/Pi/Log/Formatter/DbProfiler.php index 0a7aca27fd..5680fb25c2 100644 --- a/lib/Pi/Log/Formatter/DbProfiler.php +++ b/lib/Pi/Log/Formatter/DbProfiler.php @@ -21,7 +21,7 @@ namespace Pi\Log\Formatter; use Pi; -use Pi\Security; +//use Pi\Security\Security; use Pi\Log\Logger; use Zend\Log\Formatter\FormatterInterface; @@ -66,8 +66,8 @@ public function format($event) /**#@++ * Remove DB table prefix for security considerations */ - $event['message'] = isset($event['message']) ? Security::sanitizeDb($event['message']) : ''; - $event['sql'] = Security::sanitizeDb($event['sql']); + $event['message'] = isset($event['message']) ? Pi::service('security')->db($event['message']) : ''; + $event['sql'] = Pi::service('security')->db($event['sql']); /**#@-*/ $event['params'] = ''; diff --git a/lib/Pi/Log/Formatter/Debugger.php b/lib/Pi/Log/Formatter/Debugger.php index cd996618d5..c16cb6886e 100644 --- a/lib/Pi/Log/Formatter/Debugger.php +++ b/lib/Pi/Log/Formatter/Debugger.php @@ -20,7 +20,7 @@ namespace Pi\Log\Formatter; use Pi; -use Pi\Security; +//use Pi\Security\Security; use Zend\Log\Formatter\FormatterInterface; class Debugger implements FormatterInterface @@ -75,8 +75,7 @@ public function format($event) /**#@++ * Remove path prefix for security considerations */ - //$location .= sprintf(' in %s', $this->sanitizePaths($event['extra']['file'])); - $location .= sprintf(' in %s', Security::sanitizePath($event['extra']['file'])); + $location .= sprintf(' in %s', Pi::service('security')->path($event['extra']['file'])); /**#@-*/ } $event['location'] = $location; @@ -91,36 +90,6 @@ public function format($event) return $output; } - /** - * Remove path prefix for security considerations - * - * @staticvar array $paths - * @param string $str - * @return string - */ - protected function sanitizePaths($str) - { - static $paths; - - if (!isset($paths)) { - // Loads all path settings from host data - $paths = Pi::host()->get('path'); - $lens = array(); - foreach ($paths as $root => $v) { - $lens[] = strlen($v); - } - // Sort the paths by their lengths in reverse - array_multisort($lens, SORT_NUMERIC, SORT_DESC, $paths); - } - if (DIRECTORY_SEPARATOR != '/') { - $str = str_replace(DIRECTORY_SEPARATOR, '/', $str); - } - foreach ($paths as $root => $v) { - $str = str_replace($v . '/', $root . '/', $str); - } - return $str; - } - /** * {@inheritDoc} */ diff --git a/lib/Pi/Log/Writer/Debugger.php b/lib/Pi/Log/Writer/Debugger.php index 99831ece33..2d3ab43b3c 100644 --- a/lib/Pi/Log/Writer/Debugger.php +++ b/lib/Pi/Log/Writer/Debugger.php @@ -195,7 +195,7 @@ public function systemInfo() $system['Cache Storage'] = $class; } if (Pi::service()->hasService('module')) { - $system['Module'] = Pi::service('module')->current(); + $system['Module'] = Pi::service('module')->current() ?: 'N/A'; } if (Pi::service()->hasService('theme')) { $system['Theme'] = Pi::service('theme')->current(); diff --git a/lib/Pi/Markup/Renderer/Text.php b/lib/Pi/Markup/Renderer/Text.php index a2d64e8939..6a5c137f1b 100644 --- a/lib/Pi/Markup/Renderer/Text.php +++ b/lib/Pi/Markup/Renderer/Text.php @@ -20,7 +20,7 @@ namespace Pi\Markup\Renderer; use Pi\Markup\Parser\AbstractParser; -use Pi\Security; +//use Pi\Security\Security; class Text extends AbstractRenderer { @@ -35,11 +35,11 @@ protected function parse($content) { if ($this->parser instanceof AbstractParser) { $content = $this->parser->parse($content); - $content = Security::escape($content); + $content = Pi::service('security')->escape($content); } elseif ('html' == $this->parser) { $content = strip_tags($content); } else { - $content = Security::escape($content); + $content = Pi::service('security')->escape($content); } if (!isset($this->options['newline']) || !empty($this->options['newline'])) { $content = nl2br($content); diff --git a/lib/Pi/Mvc/Controller/Plugin/Alias.php b/lib/Pi/Mvc/Controller/Plugin/Alias.php deleted file mode 100644 index 32c7912117..0000000000 --- a/lib/Pi/Mvc/Controller/Plugin/Alias.php +++ /dev/null @@ -1,92 +0,0 @@ - - * @since 3.0 - * @package Pi\Mvc - * @version $Id$ - */ - -namespace Pi\Mvc\Controller\Plugin; - -use Pi; -use Zend\Mvc\Controller\Plugin\AbstractPlugin; -use Zend\Mvc\MvcEvent; - -class Alias extends AbstractPlugin -{ - public $_search = array(" ","\t","\r\n","\r","\n",",",".","'",";",":",")", - "(",'"','?','!','{','}','[',']','<','>','/','+','-','_', - '\\','*','=','@','#','$','%','^','&'); - public $_replace = array(' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ', - ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ', - ' ',' ',' ',' ',' ',''); - - /* - * $this->alias($alias); - */ - public function __invoke($alias, $id, $model) - { - $alias = $this->setAlias($alias); - $alias = $this->checkAlias($alias, $id, $model); - return $alias; - } - - /** - * Returns the alias - * - * @return boolean - */ - public function setAlias($alias) - { - $alias = strip_tags($alias); - $alias = strtolower($alias); - $alias = htmlentities($alias, ENT_COMPAT, 'utf-8'); - $alias = preg_replace('`\[.*\]`U', ' ', $alias); - $alias = preg_replace('`&(amp;)?#?[a-z0-9]+;`i', ' ', $alias); - $alias = preg_replace('`&([a-z])(acute|uml|circ|grave|ring|cedil|slash|tilde|caron|lig);`i', '\\1', $alias); - $alias = str_replace($this->_search, $this->_replace, $alias); - $alias = explode(' ',$alias); - foreach($alias as $word) { - if(!empty($word)) { - $key[] = $word; - } - } - $alias = implode('-',$key); - return $alias; - } - - /** - * Check alias exit ot not - * - * @return boolean - */ - public function checkAlias($alias, $id, $model) - { - if (empty($id)) { - $select = $model->select()->columns(array('id', 'alias'))->where(array('alias' => $alias)); - } else { - $select = $model->select()->columns(array('id', 'alias'))->where(array('alias' => $alias, 'id != ?' => $id)); - } - $rowset = $model->selectWith($select); - if($rowset->count()) { - /* - * This part need improvment - * replace rand function whit method for add number - */ - $alias = $this->setAlias($alias . ' ' . rand(1, 9999)); - $alias = $this->checkAlias($alias, $id, $model); - } - return $alias; - } -} \ No newline at end of file diff --git a/lib/Pi/Mvc/Controller/Plugin/Meta.php b/lib/Pi/Mvc/Controller/Plugin/Meta.php deleted file mode 100644 index 01536637d8..0000000000 --- a/lib/Pi/Mvc/Controller/Plugin/Meta.php +++ /dev/null @@ -1,73 +0,0 @@ - - * @since 3.0 - * @package Pi\Mvc - * @version $Id$ - */ - -namespace Pi\Mvc\Controller\Plugin; - -use Zend\Mvc\Controller\Plugin\AbstractPlugin; - -class Meta extends AbstractPlugin -{ - public $_search = array(" ","\t","\r\n","\r","\n",",",".","'",";",":",")", - "(",'"','?','!','{','}','[',']','<','>','/','+','-','_', - '\\','*','=','@','#','$','%','^','&'); - public $_replace = array(' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ', - ' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',' ', - ' ',' ',' ',' ',' ',''); - - /* - * $this->meta()->keywords($keywords); - * $this->meta()->keywords($keywords, $number, $limit); - */ - public function keywords($keywords, $number = '6', $limit = '3') - { - $keywords = strip_tags($keywords); - $keywords = strtolower($keywords); - $keywords = htmlentities($keywords, ENT_COMPAT, 'utf-8'); - $keywords = preg_replace('`\[.*\]`U', '', $keywords); - $keywords = preg_replace('`&(amp;)?#?[a-z0-9]+;`i', '', $keywords); - $keywords = preg_replace('`&([a-z])(acute|uml|circ|grave|ring|cedil|slash|tilde|caron|lig);`i', '\\1', $keywords); - $keywords = str_replace($this->_search, $this->_replace, $keywords); - $keywords = explode(' ',$keywords); - $keywords = array_unique($keywords); - foreach($keywords as $keyword) { - if(mb_strlen($keyword) >= $limit && !empty($keyword) && !is_numeric($keyword)) { - $key[] = $keyword; - } - } - $key = array_slice($key, 0, $number); - $keywords = implode(',',$key); - $keywords = trim($keywords, ','); - return $keywords; - } - - /* - * $this->meta()->description($description); - */ - public function description($description) - { - $description = strip_tags($description); - $description = strtolower($description); - $description = htmlentities($description, ENT_COMPAT, 'utf-8'); - $description = preg_replace('`\[.*\]`U', '', $description); - $description = preg_replace('`&(amp;)?#?[a-z0-9]+;`i', '-', $description); - $description = preg_replace('`&([a-z])(acute|uml|circ|grave|ring|cedil|slash|tilde|caron|lig);`i', '\\1', $description); - $description = str_replace($this->_search, $this->_replace, $description); - return $description; - } -} \ No newline at end of file diff --git a/lib/Pi/Mvc/Controller/Plugin/Params.php b/lib/Pi/Mvc/Controller/Plugin/Params.php index 5511fc9380..c0e538d5b6 100644 --- a/lib/Pi/Mvc/Controller/Plugin/Params.php +++ b/lib/Pi/Mvc/Controller/Plugin/Params.php @@ -21,6 +21,22 @@ use Zend\Mvc\Controller\Plugin\Params as ZendParams; +/**#@+ + * Syntactic sugar for params + * + * Retrieve a request variable: + * + * $paramGet = $this->params()->get('var', 'int'); + * $paramPost = $this->params()->post('var', 'email'); + * $paramPut = $this->params()->put('var', 'url'); + * $paramAuto = $this->params()->request('var', 'ip'); + * + * + * Filter a value: + * + * $paramFiltered = $this->params()->filter('+1234.5', 'float'); + * + */ class Params extends ZendParams { protected $putParams; @@ -41,7 +57,7 @@ public function __invoke($param = null, $default = null) if ($result !== null) { return $result; } - + $value = $default; foreach ($this->variablesOrder as $method) { if (method_exists($this, 'from' . $method)) { @@ -96,4 +112,110 @@ public function fromRequest($param = null, $default = null) return null; } + + /**#@+ + * Retrieve request params with PHP filter_var + */ + /** + * Retrieve a variable from query + * + * @param string $variable + * @param int|string $filter + * @param mixed $options + * @return mixed + */ + public function get($variable, $filter, $options = null) + { + $value = $this->fromRoute($variable); + if (null === $value) { + $value = $this->fromQuery($variable); + } + if (null !== $value) { + $value = $this->filter($value, $filter, $options); + } + + return $value; + } + + /** + * Retrieve a variable from POST + * + * @param string $variable + * @param int|string $filter + * @param mixed $options + * @return mixed + */ + public function post($variable, $filter, $options = null) + { + $value = $this->fromPost($variable); + if (null !== $value) { + $value = $this->filter($value, $filter, $options); + } + + return $value; + } + + /** + * Retrieve a variable from PUT + * + * @param string $variable + * @param int|string $filter + * @param mixed $options + * @return mixed + */ + public function put($variable, $filter, $options = null) + { + $value = $this->fromPut($variable); + if (null !== $value) { + $value = $this->filter($value, $filter, $options); + } + + return $value; + } + + /** + * Retrieve a variable from current HTTP method: get, post, put + * + * @param string $variable + * @param int|string $filter + * @param mixed $options + * @return mixed + */ + public function request($variable, $filter, $options = null) + { + $value = $this->fromRequest($variable); + if (null !== $value) { + $value = $this->filter($value, $filter, $options); + } + + return $value; + } + + /** + * Filter value with filter_var + * + * @param mixed $value + * @param int|string $filter + * @param mixed $options + * @return mixed + */ + public function filter($value, $filter, $options = null) + { + if (!is_int($filter)) { + $filterName = strtoupper('filter_validate_' . $filter); + if (defined($filterName)) { + $filter = constant($filterName); + } else { + $filter = null; + } + } + if (null !== $filter) { + $value = filter_var($value, $filter, $options); + } else { + $value = false; + } + + return $value; + } + /**#@-*/ } diff --git a/lib/Pi/Mvc/Controller/Plugin/Resize.php b/lib/Pi/Mvc/Controller/Plugin/Resize.php deleted file mode 100644 index 8d0d700384..0000000000 --- a/lib/Pi/Mvc/Controller/Plugin/Resize.php +++ /dev/null @@ -1,277 +0,0 @@ - - * @author Herve Thouzard - * @author Jarrod Oberto - * @since 3.0 - * @package Pi\Mvc - * @version $Id$ - */ - -namespace Pi\Mvc\Controller\Plugin; - -use Pi; -use Zend\Mvc\Controller\Plugin\AbstractPlugin; - -class Resize extends AbstractPlugin -{ - private $image; - private $imageResized; - private $width; - private $height; - private $mime; - - /** - * Resize a Picture to some given dimensions (using the wideImage library) - * @param string $image Picture's name - * @param string $src_path Picture's source pach - * @param string $dst_path Picture's destination - * @param integer $width Maximum picture's width - * @param integer $height Maximum picture's height - * @param boolean $keep_original Do we have to keep the original picture ? - * @param string $option is crop, exact, portrait, landscape, auto - * @return true / false - */ - public function __invoke($file, $src_path, $dst_path, $param_width, $param_height, $keep_original = true, $option = 'auto') - { - // Set main paths - $src_path = Pi::path('upload') . '/' . $src_path; - $dst_path = Pi::path('upload') . '/' . $dst_path; - // Make dir - if (!is_dir($dst_path)) { - Pi::service('file')->mkdir($dst_path); - } - // Set image path - $src_path = $src_path . '/' . $file; - $dst_path = $dst_path . '/' . $file; - // start resize - $doresize = true; - $pictureDimensions = getimagesize($src_path); - if (is_array($pictureDimensions)) { - // Set output array - $this->width = $pictureDimensions[0]; - $this->height = $pictureDimensions[1]; - $this->mime = $pictureDimensions['mime']; - // Check image dimensions for resize - if ($this->width < $param_width && $this->height < $param_height) { - $doresize = false; - } - // Do resize or copy image - if ($doresize) { - // Will add resize codes - $this->openImage($src_path); - $this->resizeImage($param_width, $param_height); - $this->saveImage($dst_path); - } else { - Pi::service('file')->copy($src_path, $dst_path); - } - // Keep original image or not - if (!$keep_original) { - Pi::service('file')->remove($src_path); - } - // return info - return true; - } - return false; - } - - /** - * All subsequent functions written by Jarrod Oberto - * For more information please check his website : http://www.jarrodoberto.com - * source : http://net.tutsplus.com/tutorials/php/image-resizing-made-easy-with-php/ - */ - private function openImage($file) - { - // *** Get extension - $extension = strtolower(strrchr($file, '.')); - - switch ($extension) { - case '.jpg': - case '.jpeg': - $img = @imagecreatefromjpeg($file); - break; - case '.gif': - $img = @imagecreatefromgif($file); - break; - case '.png': - $img = @imagecreatefrompng($file); - break; - default: - $img = false; - break; - } - $this->image = $img; - } - - private function resizeImage($newWidth, $newHeight, $option = "auto") - { - // *** Get optimal width and height - based on $option - $optionArray = $this->getDimensions($newWidth, $newHeight, $option); - $optimalWidth = $optionArray['optimalWidth']; - $optimalHeight = $optionArray['optimalHeight']; - - // *** Resample - create image canvas of x, y size - $this->imageResized = imagecreatetruecolor($optimalWidth, $optimalHeight); - imagecopyresampled($this->imageResized, $this->image, 0, 0, 0, 0, $optimalWidth, $optimalHeight, $this->width, $this->height); - - // *** if option is 'crop', then crop too - if ($option == 'crop') { - $this->crop($optimalWidth, $optimalHeight, $newWidth, $newHeight); - } - } - - private function getDimensions($newWidth, $newHeight, $option) - { - switch ($option) { - case 'exact': - $optimalWidth = $newWidth; - $optimalHeight = $newHeight; - break; - case 'portrait': - $optimalWidth = $this->getSizeByFixedHeight($newHeight); - $optimalHeight = $newHeight; - break; - case 'landscape': - $optimalWidth = $newWidth; - $optimalHeight = $this->getSizeByFixedWidth($newWidth); - break; - case 'auto': - $optionArray = $this->getSizeByAuto($newWidth, $newHeight); - $optimalWidth = $optionArray['optimalWidth']; - $optimalHeight = $optionArray['optimalHeight']; - break; - case 'crop': - $optionArray = $this->getOptimalCrop($newWidth, $newHeight); - $optimalWidth = $optionArray['optimalWidth']; - $optimalHeight = $optionArray['optimalHeight']; - break; - } - return array('optimalWidth' => $optimalWidth, 'optimalHeight' => $optimalHeight); - } - - private function getSizeByFixedHeight($newHeight) - { - $ratio = $this->width / $this->height; - $newWidth = $newHeight * $ratio; - return $newWidth; - } - - private function getSizeByFixedWidth($newWidth) - { - $ratio = $this->height / $this->width; - $newHeight = $newWidth * $ratio; - return $newHeight; - } - - private function getSizeByAuto($newWidth, $newHeight) - { - if ($this->height < $this->width) - // *** Image to be resized is wider (landscape) - { - $optimalWidth = $newWidth; - $optimalHeight = $this->getSizeByFixedWidth($newWidth); - } elseif ($this->height > $this->width) - // *** Image to be resized is taller (portrait) - { - $optimalWidth = $this->getSizeByFixedHeight($newHeight); - $optimalHeight = $newHeight; - } else - // *** Image to be resizerd is a square - { - if ($newHeight < $newWidth) { - $optimalWidth = $newWidth; - $optimalHeight = $this->getSizeByFixedWidth($newWidth); - } else if ($newHeight > $newWidth) { - $optimalWidth = $this->getSizeByFixedHeight($newHeight); - $optimalHeight = $newHeight; - } else { - // *** Sqaure being resized to a square - $optimalWidth = $newWidth; - $optimalHeight = $newHeight; - } - } - return array('optimalWidth' => $optimalWidth, 'optimalHeight' => $optimalHeight); - } - - private function getOptimalCrop($newWidth, $newHeight) - { - $heightRatio = $this->height / $newHeight; - $widthRatio = $this->width / $newWidth; - - if ($heightRatio < $widthRatio) { - $optimalRatio = $heightRatio; - } else { - $optimalRatio = $widthRatio; - } - - $optimalHeight = $this->height / $optimalRatio; - $optimalWidth = $this->width / $optimalRatio; - - return array('optimalWidth' => $optimalWidth, 'optimalHeight' => $optimalHeight); - } - - private function crop($optimalWidth, $optimalHeight, $newWidth, $newHeight) - { - // *** Find center - this will be used for the crop - $cropStartX = ($optimalWidth / 2) - ($newWidth / 2); - $cropStartY = ($optimalHeight / 2) - ($newHeight / 2); - - $crop = $this->imageResized; - //imagedestroy($this->imageResized); - - // *** Now crop from center to exact requested size - $this->imageResized = imagecreatetruecolor($newWidth, $newHeight); - imagecopyresampled($this->imageResized, $crop, 0, 0, $cropStartX, $cropStartY, $newWidth, $newHeight, $newWidth, $newHeight); - } - - - public function saveImage($savePath, $imageQuality = "100") - { - // *** Get extension - $extension = strrchr($savePath, '.'); - $extension = strtolower($extension); - - switch ($extension) { - case '.jpg': - case '.jpeg': - if (imagetypes() & IMG_JPG) { - imagejpeg($this->imageResized, $savePath, $imageQuality); - } - break; - - case '.gif': - if (imagetypes() & IMG_GIF) { - imagegif($this->imageResized, $savePath); - } - break; - - case '.png': - // *** Scale quality from 0-100 to 0-9 - $scaleQuality = round(($imageQuality / 100) * 9); - // *** Invert quality setting as 0 is best, not 9 - $invertScaleQuality = 9 - $scaleQuality; - - if (imagetypes() & IMG_PNG) { - imagepng($this->imageResized, $savePath, $invertScaleQuality); - } - break; - - default: - // *** No extension - No save. - break; - } - - imagedestroy($this->imageResized); - } -} \ No newline at end of file diff --git a/lib/Pi/Mvc/Controller/Plugin/View.php b/lib/Pi/Mvc/Controller/Plugin/View.php index 0c3c1417a6..7e59792813 100644 --- a/lib/Pi/Mvc/Controller/Plugin/View.php +++ b/lib/Pi/Mvc/Controller/Plugin/View.php @@ -24,6 +24,61 @@ use Zend\Mvc\MvcEvent; use Zend\Mvc\InjectApplicationEventInterface; +/** + * View plugin + * + * Assign variables to view model + * + * $this->view(array('key' => 'value')); + * $this->view()->assign('key', 'value'); + * $this->view()->assign(array('key' => 'value')); + * + * + * Set page layout + * + * $this->view()->setLayout('layout-simple'); + * + * + * Set page template + * + * $this->view()->setTemplate('page-template'); + * // Disable template + * $this->view()->setTemplate(false); + * + * + * Set head title + * + * $this->view()->headTitle('Set custom title'); + * + * + * Set head keywords, default as set by overwriting + * + * $this->view()->headKeywords('keyword, keyword, keyword'[, 'set']); + * $this->view()->headKeywords('keyword, keyword, keyword', 'append'); + * $this->view()->headKeywords('keyword, keyword, keyword', 'prepend'); + * + * $this->view()->headKeywords(array('keyword', 'keyword', 'keyword')[, 'set']); + * $this->view()->headKeywords(array('keyword', 'keyword', 'keyword'), 'append'); + * $this->view()->headKeywords(array('keyword', 'keyword', 'keyword'), 'prepend'); + * + * + * Set head description, default as set by overwriting + * + * $this->view()->headKeywords('Custom description of the page.'[, 'set']); + * $this->view()->headKeywords('Custom description of the page.', 'append'); + * $this->view()->headKeywords('Custom description of the page.', 'prepend'); + * + * + * Load a view helper + * + * $helper = $this->view()->helper('helpername'); + * + * + * Call view helper methods + * + * $this->view()->css('url-to-css-resouce'); + * + */ class View extends AbstractPlugin { /** @@ -188,6 +243,51 @@ public function hasViewModel() return $this->viewModel ? true : false; } + /** + * Set head title + * + * @param string $title Head title + * @param string $setType Position, default as append + * @return View|AbstractPlugin + */ + public function headTitle($title = null, $setType = null) + { + if (func_num_args() == 0) { + return $this->helper('headTitle'); + } + $this->helper('headTitle')->__invoke($title, $setType); + return $this; + } + + /** + * Set head description + * + * @param string $description Head description + * @param string $placement Position, default as set + * @return View + */ + public function headDescription($description, $placement = null) + { + $this->helper('headMeta')->__invoke($description, 'description', 'name', array(), $placement); + return $this; + } + + /** + * Set head keywords + * + * @param string|array $keywords Head keywords + * @param string $placement Position, default as set + * @return View + */ + public function headKeywords($keywords, $placement = null) + { + if (is_array($keywords)) { + $keywords = implode(', ', $keywords); + } + $this->helper('headMeta')->__invoke($keywords, 'keywords', 'name', array(), $placement); + return $this; + } + /** * Overloading: proxy to helpers * @@ -203,11 +303,23 @@ public function hasViewModel() */ public function __call($method, $argv) { - $render = $this->getController()->getServiceLocator()->get('ViewManager')->getRenderer(); - $helper = $render->plugin($method); + $helper = $this->helper($method); if (is_callable($helper)) { return call_user_func_array($helper, $argv); } return $helper; } + + /** + * Load view helper + * + * @param string $name + * @return AbstractPlugin + */ + public function helper($name) + { + $render = $this->getController()->getServiceLocator()->get('ViewManager')->getRenderer(); + $helper = $render->plugin($name); + return $helper; + } } diff --git a/lib/Pi/Mvc/Router/Http/Standard.php b/lib/Pi/Mvc/Router/Http/Standard.php index 6836cb079d..54e5ff581a 100644 --- a/lib/Pi/Mvc/Router/Http/Standard.php +++ b/lib/Pi/Mvc/Router/Http/Standard.php @@ -166,8 +166,10 @@ protected function canonizePath(Request $request, $pathOffset = null) $pathLength = strlen($path); if ($this->prefix) { - $prefixLength = strlen($this->prefix); - if ($this->prefix != substr($path, 0, $prefixLength)) { + $prefix = rtrim($this->prefix, $this->paramDelimiter) . $this->paramDelimiter; + $path = rtrim($path, $this->paramDelimiter) . $this->paramDelimiter; + $prefixLength = strlen($prefix); + if ($prefix != substr($path, 0, $prefixLength)) { return null; } $path = substr($path, $prefixLength); diff --git a/lib/Pi/Mvc/View/Http/DefaultRenderingStrategy.php b/lib/Pi/Mvc/View/Http/DefaultRenderingStrategy.php index ad7cf9212d..3d78297177 100644 --- a/lib/Pi/Mvc/View/Http/DefaultRenderingStrategy.php +++ b/lib/Pi/Mvc/View/Http/DefaultRenderingStrategy.php @@ -21,6 +21,7 @@ namespace Pi\Mvc\View\Http; use Pi; +use Zend\EventManager\EventManagerInterface; use Zend\Mvc\View\Http\DefaultRenderingStrategy as ZendDefaultRenderingStrategy; use Zend\Stdlib\ResponseInterface as Response; use Zend\View\Model\ModelInterface as ViewModel; @@ -35,6 +36,24 @@ class DefaultRenderingStrategy extends ZendDefaultRenderingStrategy */ protected $layoutError = 'layout-error'; + /** + * Attach the aggregate to the specified event manager + * + * @param EventManagerInterface $events + * @return void + */ + public function attach(EventManagerInterface $events) + { + parent::attach($events); + + $this->listeners[] = $events->attach(MvcEvent::EVENT_ROUTE, array($this, 'initAssemble'), 10000); + + $this->listeners[] = $events->attach(MvcEvent::EVENT_RENDER, array($this, 'renderAssemble'), 10000); + $this->listeners[] = $events->attach(MvcEvent::EVENT_RENDER_ERROR, array($this, 'renderAssemble'), 10000); + + $this->listeners[] = $events->attach(MvcEvent::EVENT_FINISH, array($this, 'completeAssemble'), 10000); + } + /** * Get error layout template value * @@ -99,10 +118,6 @@ public function render(MvcEvent $e) if ($e->isError()) { $viewModel->setTemplate($this->getLayoutError()); } - - // Set up layout meta data - $viewRenderer = $e->getApplication()->getServiceManager()->get('ViewRenderer'); - $viewRenderer->meta()->assign(); } $view = $this->view; @@ -115,4 +130,74 @@ public function render(MvcEvent $e) return $response; } + + /** + * Initialize assemble with config meta + * + * @param MvcEvent $e + * @return void + */ + public function initAssemble(MvcEvent $e) + { + // Skip ajax request + $request = $e->getRequest(); + if ($request->isXmlHttpRequest()) { + return; + } + + // Get ViewRenderer + $viewRenderer = $e->getApplication()->getServiceManager()->get('ViewRenderer'); + $viewRenderer->assemble()->initStrategy(); + return; + } + + /** + * Canonize head title by appending site name and/or slogan + * + * @param MvcEvent $e + * @return void + */ + public function renderAssemble(MvcEvent $e) + { + // Skip ajax request + $request = $e->getRequest(); + if ($request->isXmlHttpRequest()) { + return; + } + + // Get ViewRenderer + $viewRenderer = $e->getApplication()->getServiceManager()->get('ViewRenderer'); + $viewRenderer->assemble()->renderStrategy(); + return; + } + + + /** + * Assemble meta contents + * + * @param MvcEvent $e + * @return void + */ + public function completeAssemble(MvcEvent $e) + { + // Set response headers for language and charset + $response = $e->getResponse(); + $response->getHeaders()->addHeaders(array( + 'content-type' => sprintf('text/html; charset=%s', Pi::config('charset')), + 'content-language' => Pi::config('locale'), + )); + + // Skip ajax request + $request = $e->getRequest(); + if ($request->isXmlHttpRequest()) { + return; + } + + // Get ViewRenderer + $viewRenderer = $e->getApplication()->getServiceManager()->get('ViewRenderer'); + $content = $response->getContent(); + $content = $viewRenderer->assemble()->completeStrategy($content); + $response->setContent($content); + return; + } } diff --git a/lib/Pi/Mvc/View/Http/ViewManager.php b/lib/Pi/Mvc/View/Http/ViewManager.php index 04ab2a3a4d..6634fd3d0a 100644 --- a/lib/Pi/Mvc/View/Http/ViewManager.php +++ b/lib/Pi/Mvc/View/Http/ViewManager.php @@ -21,9 +21,7 @@ namespace Pi\Mvc\View\Http; use Pi; - use Pi\View\Renderer\PhpRenderer as ViewPhpRenderer; -use Pi\View\Strategy\PhpRendererStrategy; use Zend\Mvc\MvcEvent; use Zend\Mvc\View\Http\ViewManager as ZendViewManager; use Pi\Mvc\View\Http\CreateViewModelListener; @@ -137,27 +135,6 @@ public function getRenderer() return $this->renderer; } - /** - * Instantiates and configures the renderer strategy for the view - * - * @return PhpRendererStrategy - */ - public function getRendererStrategy() - { - if ($this->rendererStrategy) { - return $this->rendererStrategy; - } - - $this->rendererStrategy = new PhpRendererStrategy( - $this->getRenderer() - ); - - $this->services->setService('ViewPhpRendererStrategy', $this->rendererStrategy); - $this->services->setAlias('Zend\View\Strategy\PhpRendererStrategy', 'ViewPhpRendererStrategy'); - - return $this->rendererStrategy; - } - /** * Get the layout template name * diff --git a/lib/Pi/Security/AbstractSecurity.php b/lib/Pi/Security/AbstractAdapter.php similarity index 91% rename from lib/Pi/Security/AbstractSecurity.php rename to lib/Pi/Security/AbstractAdapter.php index 7510c0c65e..b3c288bbf3 100644 --- a/lib/Pi/Security/AbstractSecurity.php +++ b/lib/Pi/Security/AbstractAdapter.php @@ -19,7 +19,7 @@ namespace Pi\Security; -abstract class AbstractSecurity +abstract class AbstractAdapter { const MESSAGE = "DEFINE SPECIFIC MESSAGE"; @@ -30,7 +30,7 @@ abstract class AbstractSecurity */ public static function check($options = null) { - throw new Exception('Access the abstract method is not allowed.'); + throw new \Exception('Access the abstract method is not allowed.'); return null; } } diff --git a/lib/Pi/Security/Agent.php b/lib/Pi/Security/Agent.php index 035bbd9100..f5bc3689a3 100644 --- a/lib/Pi/Security/Agent.php +++ b/lib/Pi/Security/Agent.php @@ -19,7 +19,7 @@ namespace Pi\Security; -class Agent extends AbstractSecurity +class Agent extends AbstractAdapter { const MESSAGE = "Access denied by HTTP_USER_AGENT check"; @@ -28,7 +28,7 @@ class Agent extends AbstractSecurity * * Policy: Returns TRUE will cause process quite and the current request will be approved; returns FALSE will cause process quit and request will be denied */ - public static function check($options = null) + public static function check($options = array()) { $key = 'HTTP_USER_AGENT'; $agent = ''; diff --git a/lib/Pi/Security/Bot.php b/lib/Pi/Security/Bot.php index 2e6601a099..4969e04f40 100644 --- a/lib/Pi/Security/Bot.php +++ b/lib/Pi/Security/Bot.php @@ -19,7 +19,7 @@ namespace Pi\Security; -class Bot extends AbstractSecurity +class Bot extends AbstractAdapter { const MESSAGE = "Access denied by bot check"; @@ -28,7 +28,7 @@ class Bot extends AbstractSecurity * * Policy: Returns TRUE will cause process quite and the current request will be approved; returns FALSE will cause process quit and request will be denied */ - public static function check($options = null) + public static function check($options = array()) { $key = 'HTTP_USER_AGENT'; $agent = ''; @@ -45,7 +45,7 @@ public static function check($options = null) return null; } // Check bad bots - $pattern = is_array($options) ? implode("|", $options) : $options; + $pattern = implode("|", $options); $status = preg_match('/' . $pattern . '/i', $agent) ? false : null; return $status; diff --git a/lib/Pi/Security/Dos.php b/lib/Pi/Security/Dos.php index a275bb17f7..7e6a73db0f 100644 --- a/lib/Pi/Security/Dos.php +++ b/lib/Pi/Security/Dos.php @@ -19,7 +19,7 @@ namespace Pi\Security; -class Dos extends AbstractSecurity +class Dos extends AbstractAdapter { const MESSAGE = "Access denied by DoS check"; @@ -28,7 +28,7 @@ class Dos extends AbstractSecurity * * Policy: Returns TRUE will cause process quite and the current request will be approved; returns FALSE will cause process quit and request will be denied */ - public static function check($options = null) + public static function check($options = array()) { $key = 'HTTP_USER_AGENT'; $agent = ''; diff --git a/lib/Pi/Security.php b/lib/Pi/Security/Security.php similarity index 53% rename from lib/Pi/Security.php rename to lib/Pi/Security/Security.php index 3c0fbfc7e7..2cad574614 100644 --- a/lib/Pi/Security.php +++ b/lib/Pi/Security/Security.php @@ -18,41 +18,21 @@ * @version $Id$ */ -namespace Pi; +namespace Pi\Security; use Pi; -use Zend\Escaper\Escaper; class Security { - static protected $escaper; - - /** - * Header outputs on deny - * - * @param string $message The message to be displayed - * @return void - */ - public static function deny($message = '') - { - if (substr(PHP_SAPI, 0, 3) == 'cgi') { - header('Status: 403 Forbidden'); - } else { - header('HTTP/1.1 403 Forbidden'); - } - exit('Access denied' . ($message ? ': ' . $message : '.')); - } - /**#@++ * Check security settings * * Policy: Returns TRUE will cause process quite and the current request will be approved; returns FALSE will cause process quit and request will be denied */ - /** * Check for IPs */ - public static function ip($options = null) + public static function ip($options = array()) { $clientIp = array(); if (!empty($_SERVER['REMOTE_ADDR'])) { @@ -96,9 +76,9 @@ public static function ip($options = null) /** * Check for super globals */ - public static function globals($options = null) + public static function globals($options = array()) { - $items = is_array($options) ? $options : explode(',', $options); + $items = $options; array_walk($items, 'trim'); $items = array_filter($items); foreach ($items as $item) { @@ -110,79 +90,16 @@ public static function globals($options = null) return null; } - /** - * Remove path prefix for security considerations - * - * @staticvar array $paths - * @param string $str - * @return string - */ - public static function sanitizePath($str) - { - static $paths; - - if (!isset($paths)) { - // Loads all path settings from host data - $paths = Pi::host()->get('path'); - $lengths = array(); - foreach ($paths as $root => $v) { - $lengths[] = strlen($v); - } - // Sort the paths by their lengths in reverse - array_multisort($lengths, SORT_NUMERIC, SORT_DESC, $paths); - } - if (DIRECTORY_SEPARATOR != '/') { - $str = str_replace(DIRECTORY_SEPARATOR, '/', $str); - } - foreach ($paths as $root => $v) { - if (empty($v) || empty($root)) { - continue; - } - $str = str_replace($v . '/', $root . '/', $str); - } - return $str; - } - - /** - * Remove DB database name and table prefix for security considerations - * - * @param string $str - * @return string - */ - public static function sanitizeDb($str) - { - $pattern = '/\b' . preg_quote(Pi::db()->getTablePrefix()) . '/i'; - $return = preg_replace($pattern, '', $str); - return $return; - } - - /** - * Get escaper, and escape HTML content if specified - * - * @param string|null $content - * @return Escaper|string - */ - public static function escape($content = null) - { - if (!static::$escaper) { - static::$escaper = new Escaper(Pi::config('charset')); - } - if (null === $content) { - return static::$escaper; - } - return static::$escaper->escapeHtml($content); - } - /** * Magic method to access custom security settings * * @param string $method The security setting to be checked * @param array $args arguments for the setting */ - public static function __callStatic($method, $args = null) + public static function __callStatic($method, $args = array()) { - $class = __NAMESPACE__ . '\\Security\\' . ucfirst($method); - if (class_exists($class) && is_subclass_of($class, __NAMESPACE__ . '\Security\\AbstractSecurity')) { + $class = __NAMESPACE__ . '\\' . ucfirst($method); + if (class_exists($class) && is_subclass_of($class, __NAMESPACE__ . '\AbstractAdapter')) { $options = $args[0]; return $class::check($options); } diff --git a/lib/Pi/Security/Xss.php b/lib/Pi/Security/Xss.php index 93fb64a29e..290e5a30b7 100644 --- a/lib/Pi/Security/Xss.php +++ b/lib/Pi/Security/Xss.php @@ -19,7 +19,7 @@ namespace Pi\Security; -class Xss extends AbstractSecurity +class Xss extends AbstractAdapter { const MESSAGE = "Access denied by XSS check"; protected static $filter = true; @@ -30,12 +30,11 @@ class Xss extends AbstractSecurity * * Policy: Returns TRUE will cause process quite and the current request will be approved; returns FALSE will cause process quit and request will be denied */ - public static function check($options = null) + public static function check($options = array()) { $filter = isset($options['filter']) ? $options['filter'] : static::$filter; static::$length = isset($options['length']) ? $options['length'] : static::$length; - //$filter = false; if (!empty($options['post']) && !empty($_POST)) { if (static::checkXssRecursive($_POST, $filter) && !$filter) { return false; diff --git a/lib/Pi/Session/SessionManager.php b/lib/Pi/Session/SessionManager.php index cede7b99de..e4f076883a 100644 --- a/lib/Pi/Session/SessionManager.php +++ b/lib/Pi/Session/SessionManager.php @@ -24,6 +24,17 @@ class SessionManager extends ZendSessionManager { + /** + * Default options when a call to {@link destroy()} is made + * - send_expire_cookie: whether or not to send a cookie expiring the current session cookie + * - clear_storage: whether or not to empty the storage object of any stored values + * @var array + */ + protected $defaultDestroyOptions = array( + 'send_expire_cookie' => true, + 'clear_storage' => true, + ); + protected $containers = array(); protected $validators = array(); @@ -56,8 +67,8 @@ public function writeClose() { // Skip storage writing if validation is failed if (!$this->isValid()) { - $this->destroy(); - exit('Exit on session violation.'); + //$this->destroy(); + return; } // Set metadata for validators diff --git a/lib/Pi/Utility/Filter.php b/lib/Pi/Utility/Filter.php new file mode 100644 index 0000000000..3ce95bdbe2 --- /dev/null +++ b/lib/Pi/Utility/Filter.php @@ -0,0 +1,239 @@ + + * @package Pi + */ + +namespace Pi\Utility +{ + use Pi; + + class Filter + { + /** + * Loads filter methods, nothing to do at this moment + */ + public static function load() + {} + + /** + * Filter value with filter_var + * + * @param mixed $value + * @param int|string $filter + * @param mixed $options + * @return mixed + */ + protected static function filterValue($value, $filter, $options = null) + { + if (!is_int($filter)) { + $filterName = strtoupper($filter); + if (defined($filterName)) { + $filter = constant($filterName); + } else { + $filter = null; + } + } + if (null !== $filter) { + $value = filter_var($value, $filter, $options); + } else { + $value = false; + } + + return $value; + } + + /** + * Filter value with filter_var + * + * @param mixed $value + * @param int|string $filter + * @param mixed $options + * @return mixed + */ + public static function filter($value, $filter, $options = null) + { + if (is_string($filter)) { + $filter = 'filter_validate_' . $filter; + } + $value = static::filterValue($value, $filter, $options); + return $value; + } + + /** + * Sanitize value with filter_var + * + * @param mixed $value + * @param int|string $filter + * @param mixed $options + * @return mixed + */ + public static function sanitize($value, $filter, $options = null) + { + if (is_string($filter)) { + if ('int' == $filter || 'float' == $filter) { + $filter = 'number_' . $filter; + } + $filter = 'filter_sanitize_' . $filter; + } + $value = static::filterValue($value, $filter, $options); + return $value; + } + + /** + * Get request container + * + * @return \Zend\Stdlib\RequestInterface + */ + protected static function getRequest() + { + $event = Pi::engine()->application()->getMvcEvent(); + return $event ? $event->getRequest() : null; + } + + /** + * Get routeMatch + * + * @return + */ + protected static function getRouteMatch() + { + $event = Pi::engine()->application()->getMvcEvent(); + return $event ? $event->getRouteMatch() : null; + } + + /** + * Retrieve a variable from query + * + * @param string $variable + * @param int|string $filter + * @param mixed $options + * @return mixed + */ + public static function fromGet($variable, $filter, $options = null) + { + $route = static::getRouteMatch(); + $value = $route ? $route->getParam($variable) : null; + + if (null === $value) { + $request = static::getRequest(); + $value = $request ? $request->getQuery($variable) : null; + } + + return static::filter($value, $filter, $options); + } + + /** + * Retrieve a variable from POST + * + * @param string $variable + * @param int|string $filter + * @param mixed $options + * @return mixed + */ + public static function fromPost($variable, $filter, $options = null) + { + $request = static::getRequest(); + $value = $request ? $request->getPost($variable) : null; + + return static::filter($value, $filter, $options); + } + } +} + +/**#@+ + * Syntactic sugar for system API + * + * Retrieve a request variable: + * + * $paramGet = _get('var', 'int'); + * $paramPost = _post('var', 'email'); + * + * + * Filter a value: + * + * $paramFiltered = _filter('1234.5', 'int'); + * $paramFiltered = _filter('+1234.5', 'float'); + * + * + * Sanitize a value: + * + * $paramSanitized = _sanitize('1234.5', 'int'); + * $paramSanitized = _sanitize('+1234.5', 'float', FILTER_FLAG_ALLOW_FRACTION); + * + */ +namespace +{ + use Pi\Utility\Filter as FilterManager; + + /**#@+ + * Retrieve request params with PHP filter_var + */ + /** + * Retrieve a variable from query + * + * @param string $variable + * @param int|string $filter + * @param mixed $options + * @return mixed + */ + function _get($variable, $filter, $options = null) + { + $value = FilterManager::fromGet($variable, $filter, $options); + return $value; + } + + /** + * Retrieve a variable from POST + * + * @param string $variable + * @param int|string $filter + * @param mixed $options + * @return mixed + */ + function _post($variable, $filter, $options = null) + { + $value = FilterManager::fromPost($variable, $filter, $options); + return $value; + } + + /** + * Filter a value with PHP filter_var + * + * @param string $variable + * @param int|string $filter + * @param mixed $options + * @return mixed + */ + function _filter($value, $filter, $options = null) + { + $value = FilterManager::filter($value, $filter, $options); + return $value; + } + + /** + * Sanitize a value with PHP filter_var + * + * @param string $variable + * @param int|string $filter + * @param mixed $options + * @return mixed + */ + function _sanitize($value, $filter, $options = null) + { + $value = FilterManager::sanitize($value, $filter, $options); + return $value; + } +} +/**#@-*/ diff --git a/lib/Pi/View/Helper/Meta.php b/lib/Pi/View/Helper/-Meta.php similarity index 99% rename from lib/Pi/View/Helper/Meta.php rename to lib/Pi/View/Helper/-Meta.php index 31dc1e37a6..10c9e82d62 100644 --- a/lib/Pi/View/Helper/Meta.php +++ b/lib/Pi/View/Helper/-Meta.php @@ -117,6 +117,7 @@ public function assign() $rootModel->setVariables($configGeneral); // Set page title + // TODO: To reset title $view->headTitle()->setSeparator(' - '); $view->headTitle()->append($configGeneral['sitename']); $view->headTitle()->append($configGeneral['slogan']); diff --git a/lib/Pi/View/Helper/AdminNav.php b/lib/Pi/View/Helper/AdminNav.php index ee722d3694..a8ff54f987 100644 --- a/lib/Pi/View/Helper/AdminNav.php +++ b/lib/Pi/View/Helper/AdminNav.php @@ -78,7 +78,7 @@ public function modes($module = null) * Check access permission to managed components */ if ('manage' == $type) { - $navConfig = Pi::service('registry')->navigation->read('system-component'); + $navConfig = Pi::service('registry')->navigation->read('system-component') ?: array(); if (!$navConfig) { continue; } @@ -217,7 +217,7 @@ public function top($module = null) $navigation = ''; // Managed components if ('manage' == $mode && 'system' == $module) { - $navConfig = Pi::service('registry')->navigation->read('system-component'); + $navConfig = Pi::service('registry')->navigation->read('system-component') ?: array(); //$currentModule = Pi::service('session')->backoffice->module; $currentModule = $_SESSION['PI_BACKOFFICE']['module']; if ($currentModule) { diff --git a/lib/Pi/View/Helper/Alert.php b/lib/Pi/View/Helper/Alert.php deleted file mode 100644 index 167dd0796b..0000000000 --- a/lib/Pi/View/Helper/Alert.php +++ /dev/null @@ -1,61 +0,0 @@ - - * @since 3.0 - * @package Pi\View - * @subpackage Helper - * @version $Id$ - */ - -namespace Pi\View\Helper; - -use Pi; -use Zend\View\Helper\AbstractHtmlElement; - -/** - * Helper for loading Alert - * - * Usage inside a phtml template: - * - * $this->alert('title', 'body'); - * $this->alert('title', 'body', 'class'); - * - */ -class Alert extends AbstractHtmlElement -{ - /** - * Make Button - * - * @param string - * @param string - * @param string - * @return Alert - */ - public function __invoke($title, $body, $class = null) - { - - if(!in_array($class, array('alert-success','alert-error','alert-info'))) { - $class = ''; - } - - return '
' . self::EOL - . '×' . self::EOL - . '

' . $title . '

' . self::EOL - . $body . self::EOL - . '
' . self::EOL - . '' . self::EOL; - } -} \ No newline at end of file diff --git a/lib/Pi/View/Helper/Assemble.php b/lib/Pi/View/Helper/Assemble.php new file mode 100644 index 0000000000..d7bd44799f --- /dev/null +++ b/lib/Pi/View/Helper/Assemble.php @@ -0,0 +1,214 @@ + + * @since 3.0 + * @package Pi\View + * @subpackage Helper + * @version $Id$ + */ + +namespace Pi\View\Helper; + +use Pi; +use Zend\View\Helper\AbstractHelper; +use Zend\View\Renderer\RendererInterface as Renderer; + +/** + * Helper for rendering assemble + * + * Usage inside a theme phtml template: + * + * $this->assemble('footScript', 4); + * + */ +class Assemble extends AbstractHelper +{ + /** + * Section labels + * + * @var array + */ + protected $sectionLabel; + + /** + * Render a section's anchor + * + * @param string $section + * @param string|int $indent + * @return string|RenderSection + */ + public function __invoke($section = null, $indent = null) + { + if (!$section) { + return $this; + } + $helper = $this->view->plugin($section); + if (null !== $indent) { + $helper->setIndent($indent); + } + $label = '<' . $section . ' id="' . md5(Pi::config('salt') . $section) . '" />'; + $this->sectionLabel[$section] = $label; + return $label; + } + + /** + * Load meta from configuration + * + * @return void + */ + public function initStrategy() + { + // Load meta config + $configMeta = Pi::service('registry')->config->read('system', 'meta'); + // Set head meta + foreach ($configMeta as $key => $value) { + if (!$value) { + continue; + } + $this->view->headMeta()->appendName($key, $value); + } + + // Load general config + $configGeneral = Pi::service('registry')->config->read('system'); + + // Set Google Analytics scripts in case available + if ($configGeneral['ga_account']) { + $this->view->footScript()->appendScript($this->view->ga($configGeneral['ga_account'])); + } + // Set foot scripts in case available + if ($configGeneral['foot_script']) { + if (false !== stripos($configGeneral['foot_script'], '' . self::EOL - . '
' . self::EOL; - return $facebook; - } -} diff --git a/lib/Pi/View/Helper/HeadLink.php b/lib/Pi/View/Helper/HeadLink.php new file mode 100644 index 0000000000..1271481888 --- /dev/null +++ b/lib/Pi/View/Helper/HeadLink.php @@ -0,0 +1,49 @@ + + * @since 3.0 + * @package Pi\View + * @subpackage Helper + * @version $Id$ + */ + +namespace Pi\View\Helper; + +use Pi; +use Zend\View\Helper\HeadLink as ZendHeadLink; +use Zend\View\Helper\Placeholder; + +/** + * Helper for setting and retrieving link element for HTML head + * + * @see ZendHeadLink for details. + */ +class HeadLink extends ZendHeadLink +{ + /** + * headLink() - View Helper Method + * + * Returns current object instance. Optionally, allows passing array of + * values to build link. + * + * @param array $attributes + * @param string $placement + * @return HeadLink + */ + public function __invoke(array $attributes = null, $placement = Placeholder\Container\AbstractContainer::APPEND) + { + parent::__invoke($attributes, strtoupper($placement)); + return $this; + } +} \ No newline at end of file diff --git a/lib/Pi/View/Helper/HeadMeta.php b/lib/Pi/View/Helper/HeadMeta.php new file mode 100644 index 0000000000..87dcd2081c --- /dev/null +++ b/lib/Pi/View/Helper/HeadMeta.php @@ -0,0 +1,106 @@ + + * @since 3.0 + * @package Pi\View + * @subpackage Helper + * @version $Id$ + */ + +namespace Pi\View\Helper; + +use Pi; +use Zend\View\Helper\HeadMeta as ZendHeadMeta; +use Zend\View\Helper\Placeholder; + +/** + * Helper for setting and building meta elements for HTML head section + * + * TODO: To reset global meta for keywords/description + * + * @see ZendHeadMeta for details. + */ +class HeadMeta extends ZendHeadMeta +{ + /** + * Retrieve object instance; optionally add meta tag + * + * @param string $content + * @param string $keyValue + * @param string $keyType + * @param array $modifiers + * @param string $placement + * @return HeadMeta + */ + public function __invoke($content = null, $keyValue = null, $keyType = 'name', $modifiers = array(), $placement = null) + { + if (null === $placement) { + $placement = Placeholder\Container\AbstractContainer::SET; + } + parent::__invoke($content, $keyValue, $keyType, $modifiers, $placement); + return $this; + } + + /** + * Append + * + * @param string $value + * @return void + */ + public function append($value) + { + if ('name' == $value->type) { + $container = $this->getContainer(); + $content = ''; + foreach ($container->getArrayCopy() as $index => $item) { + if ($item->name == $value->name) { + $content = $item->content; + $this->offsetUnset($index); + } + } + if ($content) { + $separator = ('description' == $value->name) ? ' ' : ', '; + $value->content = $content . $separator . $value->content; + } + } + + return parent::append($value); + } + + /** + * Prepend + * + * @param string $value + * @return void + */ + public function prepend($value) + { + if ('name' == $value->type) { + $container = $this->getContainer(); + $content = ''; + foreach ($container->getArrayCopy() as $index => $item) { + if ($item->name == $value->name) { + $content = $item->content; + $this->offsetUnset($index); + } + } + if ($content) { + $separator = ('description' == $value->name) ? ' ' : ', '; + $value->content = $value->content . $separator . $content; + } + } + + return parent::prepend($value); + } +} \ No newline at end of file diff --git a/lib/Pi/View/Helper/HeadScript.php b/lib/Pi/View/Helper/HeadScript.php index 65c9abee51..a5cc7635f6 100644 --- a/lib/Pi/View/Helper/HeadScript.php +++ b/lib/Pi/View/Helper/HeadScript.php @@ -26,7 +26,7 @@ /** * Helper for setting and retrieving script elements for HTML head section * - * @see HeadScript for details. + * @see ZendHeadScript for details. * A new use case with raw type content: * * * + * @since 3.0 + * @package Pi\View + * @subpackage Helper + * @version $Id$ + */ + +namespace Pi\View\Helper; + +use Pi; +use Zend\View\Helper\HeadTitle as ZendHeadTitle; +use Zend\View\Helper\Placeholder; + +/** + * Helper for setting and retrieving title element for HTML head + * + * @see ZendHeadTitle for details. + */ +class HeadTitle extends ZendHeadTitle +{ + /** + * Retrieve placeholder for title element and optionally set state + * + * @param string $title + * @param string $setType + * @return HeadTitle + */ + public function __invoke($title = null, $setType = null) + { + if (null !== $setType) { + $setType = strtoupper($setType); + } + return parent::__invoke($title, $setType); + } + + /** + * Display content with specified indentation string + * + * @param null|string|int $indent + * @return void + */ + public function render($indent = null) + { + if (null !== $indent) { + $this->setIndent($indent); + } + echo $this->toString(); + } +} \ No newline at end of file diff --git a/lib/Pi/View/Helper/Navigation.php b/lib/Pi/View/Helper/Navigation.php index c6d1a332bb..d9aa982cc2 100644 --- a/lib/Pi/View/Helper/Navigation.php +++ b/lib/Pi/View/Helper/Navigation.php @@ -89,12 +89,11 @@ public function __invoke($name = null, $options = array()) } $module = Pi::service('module')->current(); $section = isset($options['section']) ? $options['section'] : null; - $navConfig = Pi::service('registry')->navigation->read($name, $module, $section); + $navConfig = Pi::service('registry')->navigation->read($name, $module, $section) ?: array(); } else { $navConfig = $name; } - $this->setContainer($navConfig); return $this; diff --git a/lib/Pi/View/Helper/Pager.php b/lib/Pi/View/Helper/Pager.php deleted file mode 100644 index 61831bed70..0000000000 --- a/lib/Pi/View/Helper/Pager.php +++ /dev/null @@ -1,71 +0,0 @@ - - * @since 3.0 - * @package Pi\View - * @subpackage Helper - * @version $Id$ - */ - -namespace Pi\View\Helper; - -use Pi; -use Zend\View\Helper\AbstractHtmlElement; - -/** - * Helper for loading Pager - * - * Usage inside a phtml template: - * - * $this->pager(array, false); - * - */ -class Pager extends AbstractHtmlElement -{ - /** - * Make Button - * - * @param string - * @param string - * @param string - * @return Button - */ - public function __invoke($link, $align = false) - { - - if($align) { - $larr = '←'; - $rarr = '→'; - } else { - $larr = ''; - $rarr = ''; - } - - if(!empty($link['previous'])) { - $previous = '' . $larr . ' ' . __('Older') . ''; - $previous = '' . self::EOL; - } else { - $previous = ''; - } - - if(!empty($link['next'])) { - $next = '' . __('Newer') . ' ' . $rarr . ''; - $next = '' . self::EOL; - } else { - $next = ''; - } - - return '
    ' . self::EOL . $previous . $next . '
'; - } -} \ No newline at end of file diff --git a/lib/Pi/View/Helper/Plusone.php b/lib/Pi/View/Helper/Plusone.php deleted file mode 100644 index f680f75f35..0000000000 --- a/lib/Pi/View/Helper/Plusone.php +++ /dev/null @@ -1,67 +0,0 @@ - - * @since 3.0 - * @package Pi\View - * @subpackage Helper - * @version $Id$ - */ - -namespace Pi\View\Helper; - -use Pi; -use Zend\View\Helper\AbstractHtmlElement; - -/** - * Helper for loading google pliusone - * - * Usage inside a phtml template: - * - * $this->plusone(); - * $this->plusone(array()); - * - */ -class Plusone extends AbstractHtmlElement -{ - /** - * Make Plusone - * - * @param array - * @return Button - */ - public function __invoke($setting = '') - { - $attribs = array(); - if(isset($setting['data-size']) && in_array($setting['data-size'], array('small', 'medium', 'tall'))) { - $attribs['data-size'] = $setting['data-size']; - } - - if(isset($setting['data-annotation']) && in_array($setting['data-annotation'], array('inline', 'none'))) { - $attribs['data-annotation'] = $setting['data-annotation']; - } - - if(isset($setting['data-annotation'], $setting['data-width']) && $setting['data-annotation'] == 'inline' && is_numeric($setting['data-width']) ) { - $attribs['data-width'] = $setting['data-width']; - } - - return '
htmlAttribs($attribs) . '>
' . self::EOL - . ''; - } -} \ No newline at end of file diff --git a/lib/Pi/View/Helper/Twitter.php b/lib/Pi/View/Helper/Twitter.php deleted file mode 100644 index 1dd6d6dfa3..0000000000 --- a/lib/Pi/View/Helper/Twitter.php +++ /dev/null @@ -1,55 +0,0 @@ - - * @since 3.0 - * @package Pi\View - * @subpackage Helper - * @version $Id$ - */ - -namespace Pi\View\Helper; - -use Pi; -use Zend\View\Helper\AbstractHtmlElement; - -/** - * Helper for loading twitter - * - * Usage inside a phtml template: - * - * $this->twitter(); - * - */ -class Twitter extends AbstractHtmlElement -{ - /** - * Make Plusone - * - * @param array - * @return Button - */ - public function __invoke() - { - $twitter = '' . self::EOL - . '' . self::EOL; - return $twitter; - } -} \ No newline at end of file diff --git a/lib/Pi/View/Strategy/-PhpRendererStrategy.php b/lib/Pi/View/Strategy/-PhpRendererStrategy.php new file mode 100644 index 0000000000..14f2ab74c7 --- /dev/null +++ b/lib/Pi/View/Strategy/-PhpRendererStrategy.php @@ -0,0 +1,103 @@ + + * @since 3.0 + * @package Pi\View + * @version $Id$ + */ + +namespace Pi\View\Strategy; + +use Zend\View\Strategy\PhpRendererStrategy as ZendPhpRendererStrategy; +use Zend\View\ViewEvent; +use Zend\Mvc\MvcEvent; +use Zend\EventManager\EventManagerInterface; + +class PhpRendererStrategy extends ZendPhpRendererStrategy +{ + /** + * Attach the aggregate to the specified event manager + * + * @param EventManagerInterface $events + * @param int $priority + * @return void + */ + public function attach(EventManagerInterface $events, $priority = 1) + { + parent::attach($events, $priority); + //$this->listeners[] = $events->attach(ViewEvent::EVENT_RESPONSE, array($this, 'assembleMeta'), $priority); + } + + /** + * Populate the response object from the View + * + * Populates the content of the response object from the view rendering + * results. + * + * @param ViewEvent $e + * @return void + */ + public function assembleMeta(ViewEvent $e) + { + $response = $e->getResponse(); + $content = $response->getContent(); + + /**#@+ + * Generates and inserts head meta, stylesheets and scripts + */ + $pos = stripos($content, ''); + if (false === $pos) { + return; + } + $preHead = substr($content, 0, $pos); + $postHead = substr($content, $pos); + + $indent = 4; + + $headTitle = ''; + if ($this->renderer->headTitle()->count()) { + $headTitle = $this->renderer->headTitle()->toString($indent); + $headTitle .= $headTitle; + } + + $headMeta = $this->renderer->headMeta()->toString($indent); + $headMeta .= $headMeta ? PHP_EOL : ''; + + $headLink = $this->renderer->headLink()->toString($indent); + $headLink .= $headLink ? PHP_EOL : ''; + + $headStyle = $this->renderer->headStyle()->toString($indent); + $headStyle .= $headStyle ? PHP_EOL : ''; + + $headScript = $this->renderer->headScript()->toString($indent); + $headScript .= $headScript ? PHP_EOL : ''; + + $head = $headTitle . $headMeta . $headLink . $headStyle . $headScript; + $content = $preHead . ($head ? PHP_EOL . $head . PHP_EOL : '') . $postHead; + /**#@-*/ + + /**@+ + * Generates and inserts foot scripts + */ + $foot = $this->renderer->footScript()->toString($indent); + if ($foot && $pos = strripos($content, '')) { + $preFoot = substr($content, 0, $pos); + $postFoot = substr($content, $pos); + $content = $preFoot . PHP_EOL . $foot . PHP_EOL . PHP_EOL . $postFoot; + } + /**#@-*/ + + $response->setContent($content); + } +} diff --git a/lib/Pi/View/Strategy/PhpRendererStrategy.php b/lib/Pi/View/Strategy/PhpRendererStrategy.php deleted file mode 100644 index 63b68a7ba6..0000000000 --- a/lib/Pi/View/Strategy/PhpRendererStrategy.php +++ /dev/null @@ -1,94 +0,0 @@ - - * @since 3.0 - * @package Pi\View - * @version $Id$ - */ - -namespace Pi\View\Strategy; - -use Zend\View\Strategy\PhpRendererStrategy as ZendPhpRendererStrategy; -use Zend\View\ViewEvent; - -class PhpRendererStrategy extends ZendPhpRendererStrategy -{ - /** - * Populate the response object from the View - * - * Populates the content of the response object from the view rendering - * results. - * - * @param ViewEvent $e - * @return void - */ - public function injectResponse(ViewEvent $e) - { - $renderer = $e->getRenderer(); - if ($renderer !== $this->renderer) { - return; - } - - $result = $e->getResult(); - $response = $e->getResponse(); - - // Set content - // If content is empty, check common placeholders to determine if they are - // populated, and set the content from them. - if (empty($result)) { - $placeholders = $renderer->plugin('placeholder'); - $registry = $placeholders->getRegistry(); - foreach ($this->contentPlaceholders as $placeholder) { - if ($registry->containerExists($placeholder)) { - $result = (string) $registry->getContainer($placeholder); - break; - } - } - } - - $result = $this->assembleMeta($result); - - $response->setContent($result); - } - - public function assembleMeta($content) - { - $pos = stripos($content, ''); - if (false === $pos) { - return $content; - } - - $preHead = substr($content, 0, $pos); - $postHead = substr($content, $pos); - $head = $this->renderer->headMeta() . PHP_EOL - . $this->renderer->headLink() . PHP_EOL - . $this->renderer->headScript(); - $content = $preHead . PHP_EOL - . $head . PHP_EOL . PHP_EOL - . $postHead; - - $foot = $this->renderer->footScript()->toString(); - if ($foot && $pos = strripos($content, '')) { - $preFoot = substr($content, 0, $pos); - $postFoot = substr($content, $pos); - $head = $this->renderer->headMeta() . PHP_EOL - . $this->renderer->headLink() . PHP_EOL - . $this->renderer->headScript(); - $content = $preFoot . PHP_EOL - . $foot . PHP_EOL . PHP_EOL - . $postFoot; - } - return $content; - } -} diff --git a/lib/Zend/Cache/Storage/Adapter/AbstractAdapter.php b/lib/Zend/Cache/Storage/Adapter/AbstractAdapter.php index 0892d9eb0a..3c2ea41d00 100644 --- a/lib/Zend/Cache/Storage/Adapter/AbstractAdapter.php +++ b/lib/Zend/Cache/Storage/Adapter/AbstractAdapter.php @@ -188,7 +188,7 @@ public function getCaching() public function getEventManager() { if ($this->events === null) { - $this->events = new EventManager(array(__CLASS__, get_called_class())); + $this->events = new EventManager(array(__CLASS__, get_class($this))); } return $this->events; } diff --git a/lib/Zend/Cache/Storage/Adapter/FilesystemIterator.php b/lib/Zend/Cache/Storage/Adapter/FilesystemIterator.php index ede9db20d6..800e038ada 100644 --- a/lib/Zend/Cache/Storage/Adapter/FilesystemIterator.php +++ b/lib/Zend/Cache/Storage/Adapter/FilesystemIterator.php @@ -16,9 +16,9 @@ class FilesystemIterator implements IteratorInterface { /** - * The apc storage instance + * The Filesystem storage instance * - * @var Apc + * @var Filesystem */ protected $storage; @@ -89,7 +89,7 @@ public function getMode() * Set iterator mode * * @param int $mode - * @return ApcIterator Fluent interface + * @return FilesystemIterator Fluent interface */ public function setMode($mode) { @@ -164,10 +164,17 @@ public function valid() /** * Rewind the Iterator to the first element. * - * @return void + * @return bool false if the operation failed. */ public function rewind() { - return $this->globIterator->rewind(); + try { + return $this->globIterator->rewind(); + } catch (\LogicException $e) { + // @link https://bugs.php.net/bug.php?id=55701 + // GlobIterator throws LogicException with message + // 'The parent constructor was not called: the object is in an invalid state' + return false; + } } } diff --git a/lib/Zend/Console/Adapter/AbstractAdapter.php b/lib/Zend/Console/Adapter/AbstractAdapter.php index 8d33fb403d..e982b63853 100644 --- a/lib/Zend/Console/Adapter/AbstractAdapter.php +++ b/lib/Zend/Console/Adapter/AbstractAdapter.php @@ -11,6 +11,7 @@ use Zend\Console\Charset; use Zend\Console\Exception; +use Zend\Stdlib\StringUtils; /** * Common console adapter codebase @@ -73,8 +74,6 @@ public function writeText($text, $color = null, $bgColor = null) /** * Write a single line of text to console and advance cursor to the next line. - * If the text is longer than console width it will be truncated. - * * * @param string $text * @param null|int $color @@ -82,25 +81,7 @@ public function writeText($text, $color = null, $bgColor = null) */ public function writeLine($text = "", $color = null, $bgColor = null) { - $width = $this->getStringWidth($text); - - // Remove newline characters from the end of string - $text = trim($text, "\r\n"); - - // Replace newline characters with spaces - $text = str_replace("\n", " ", $text); - - // Trim the line if it's too long and output text - $consoleWidth = $this->getWidth(); - if ($width > $consoleWidth) { - $text = $this->stringTrim($text, $consoleWidth); - $this->write($text, $color, $bgColor); - } elseif ($width == $consoleWidth) { - $this->write($text, $color, $bgColor); - } else { - $this->write($text, $color, $bgColor); - $this->write("\n"); - } + $this->write($text . PHP_EOL, $color, $bgColor); } /** @@ -228,7 +209,7 @@ public function writeBox( } } elseif ($fillStyle) { - $fillChar = $this->stringTrim($fillStyle, 1); + $fillChar = StringUtils::getWrapper()->substr($fillStyle, 0, 1); } else { $fillChar = ' '; } @@ -487,56 +468,6 @@ public function clearScreen() return $this->clear(); } - /** - * Helper function that return string length as rendered in console. - * - * @static - * @param $string - * @return int - */ - protected function getStringWidth($string) - { - $width = strlen($string); - - if (!$this->isUtf8()) { - return $width; - } - - if (static::$hasMBString === null) { - static::$hasMBString = extension_loaded( 'mbstring' ); - } - - $width = (static::$hasMBString) - ? mb_strlen($string, 'UTF-8' ) - : strlen(utf8_decode($string)); - - return $width; - } - - /** - * Trim a string in an encoding-safe way - * - * @param mixed $string - * @param mixed $length - * @return int - */ - protected function stringTrim($string, $length) - { - if ($this->isUtf8()) { - if (static::$hasMBString === null) { - static::$hasMBString = extension_loaded('mbstring'); - } - - if (static::$hasMBString) { - return mb_strlen($string, 'UTF-8'); - } - - return strlen(utf8_decode($string)); - } - - return strlen($string); - } - /** * Read a single line from the console input * diff --git a/lib/Zend/Console/Adapter/Posix.php b/lib/Zend/Console/Adapter/Posix.php index 3044a63dca..7e5c5059e0 100644 --- a/lib/Zend/Console/Adapter/Posix.php +++ b/lib/Zend/Console/Adapter/Posix.php @@ -92,6 +92,24 @@ class Posix extends AbstractAdapter */ protected $lastTTYMode = null; + /** + * Write a single line of text to console and advance cursor to the next line. + * + * This override works around a bug in some terminals that cause the background color + * to fill the next line after EOL. To remedy this, we are sending the colored string with + * appropriate color reset sequences before sending EOL character. + * + * @link https://github.com/zendframework/zf2/issues/4167 + * @param string $text + * @param null|int $color + * @param null|int $bgColor + */ + public function writeLine($text = "", $color = null, $bgColor = null) + { + $this->write($text, $color, $bgColor); + $this->write(PHP_EOL); + } + /** * Determine and return current console width. * diff --git a/lib/Zend/Db/Adapter/AdapterAwareTrait.php b/lib/Zend/Db/Adapter/AdapterAwareTrait.php index 24e9f0af91..b0d9c497b3 100644 --- a/lib/Zend/Db/Adapter/AdapterAwareTrait.php +++ b/lib/Zend/Db/Adapter/AdapterAwareTrait.php @@ -11,9 +11,6 @@ use Zend\Db\Adapter\Adapter; -/** - * @packcage Zend_Db - */ trait AdapterAwareTrait { /** diff --git a/lib/Zend/Db/Adapter/Driver/Mysqli/Connection.php b/lib/Zend/Db/Adapter/Driver/Mysqli/Connection.php index e4fe97f520..c8525ff640 100644 --- a/lib/Zend/Db/Adapter/Driver/Mysqli/Connection.php +++ b/lib/Zend/Db/Adapter/Driver/Mysqli/Connection.php @@ -267,8 +267,8 @@ public function commit() } $this->resource->commit(); - $this->inTransaction = false; + $this->resource->autocommit(true); } /** @@ -288,6 +288,7 @@ public function rollback() } $this->resource->rollback(); + $this->resource->autocommit(true); return $this; } diff --git a/lib/Zend/Db/Adapter/Driver/Oci8/Oci8.php b/lib/Zend/Db/Adapter/Driver/Oci8/Oci8.php index e4c8318f07..5e9996dad1 100644 --- a/lib/Zend/Db/Adapter/Driver/Oci8/Oci8.php +++ b/lib/Zend/Db/Adapter/Driver/Oci8/Oci8.php @@ -148,11 +148,7 @@ public function getResultPrototype() */ public function getDatabasePlatformName($nameFormat = self::NAME_FORMAT_CAMELCASE) { - if ($nameFormat == self::NAME_FORMAT_CAMELCASE) { - return 'Oracle'; - } else { - return 'Oracle'; - } + return 'Oracle'; } /** diff --git a/lib/Zend/Db/Adapter/Driver/Pdo/Connection.php b/lib/Zend/Db/Adapter/Driver/Pdo/Connection.php index 5be339d5f6..03cbe3e868 100644 --- a/lib/Zend/Db/Adapter/Driver/Pdo/Connection.php +++ b/lib/Zend/Db/Adapter/Driver/Pdo/Connection.php @@ -186,6 +186,9 @@ public function setResource(\PDO $resource) */ public function getResource() { + if (!$this->isConnected()) { + $this->connect(); + } return $this->resource; } diff --git a/lib/Zend/Db/Adapter/Driver/Pgsql/Connection.php b/lib/Zend/Db/Adapter/Driver/Pgsql/Connection.php index feac1c666b..98dab06eb6 100644 --- a/lib/Zend/Db/Adapter/Driver/Pgsql/Connection.php +++ b/lib/Zend/Db/Adapter/Driver/Pgsql/Connection.php @@ -137,6 +137,9 @@ public function getCurrentSchema() */ public function getResource() { + if (!$this->isConnected()) { + $this->connect(); + } return $this->resource; } @@ -176,7 +179,13 @@ public function connect() $connection = array_filter($connection); // remove nulls $connection = http_build_query($connection, null, ' '); // @link http://php.net/pg_connect + set_error_handler(function ($number, $string) { + throw new Exception\RuntimeException( + __METHOD__ . ': Unable to connect to database', null, new Exception\ErrorException($string, $number) + ); + }); $this->resource = pg_connect($connection); + restore_error_handler(); if ($this->resource === false) { throw new Exception\RuntimeException(sprintf( diff --git a/lib/Zend/Db/Adapter/Driver/Sqlsrv/Connection.php b/lib/Zend/Db/Adapter/Driver/Sqlsrv/Connection.php index 7b785d9ebf..2de4727304 100644 --- a/lib/Zend/Db/Adapter/Driver/Sqlsrv/Connection.php +++ b/lib/Zend/Db/Adapter/Driver/Sqlsrv/Connection.php @@ -147,6 +147,9 @@ public function setResource($resource) */ public function getResource() { + if (!$this->isConnected()) { + $this->connect(); + } return $this->resource; } diff --git a/lib/Zend/Db/Adapter/Platform/Mysql.php b/lib/Zend/Db/Adapter/Platform/Mysql.php index b4b6e5568f..85c3c0b334 100644 --- a/lib/Zend/Db/Adapter/Platform/Mysql.php +++ b/lib/Zend/Db/Adapter/Platform/Mysql.php @@ -9,6 +9,7 @@ namespace Zend\Db\Adapter\Platform; +use Zend\Db\Adapter\Driver\DriverInterface; use Zend\Db\Adapter\Driver\Mysqli; use Zend\Db\Adapter\Driver\Pdo; use Zend\Db\Adapter\Exception; @@ -35,14 +36,7 @@ public function setDriver($driver) // handle Zend_Db drivers if ($driver instanceof Mysqli\Mysqli || ($driver instanceof Pdo\Pdo && $driver->getDatabasePlatformName() == 'Mysql') - ) { - /** @var $driver \Zend\Db\Adapter\Driver\DriverInterface */ - $this->resource = $driver->getConnection()->getResource(); - return $this; - } - - // handle - if ($driver instanceof \mysqli + || ($driver instanceof \mysqli) || ($driver instanceof \PDO && $driver->getAttribute(\PDO::ATTR_DRIVER_NAME) == 'mysql') ) { $this->resource = $driver; @@ -116,6 +110,9 @@ public function getQuoteValueSymbol() */ public function quoteValue($value) { + if ($this->resource instanceof DriverInterface) { + $this->resource = $this->resource->getConnection()->getResource(); + } if ($this->resource instanceof \mysqli) { return '\'' . $this->resource->real_escape_string($value) . '\''; } @@ -139,6 +136,9 @@ public function quoteValue($value) */ public function quoteTrustedValue($value) { + if ($this->resource instanceof DriverInterface) { + $this->resource = $this->resource->getConnection()->getResource(); + } if ($this->resource instanceof \mysqli) { return '\'' . $this->resource->real_escape_string($value) . '\''; } diff --git a/lib/Zend/Db/Adapter/Platform/Postgresql.php b/lib/Zend/Db/Adapter/Platform/Postgresql.php index 77de31500c..6e1bc09d89 100644 --- a/lib/Zend/Db/Adapter/Platform/Postgresql.php +++ b/lib/Zend/Db/Adapter/Platform/Postgresql.php @@ -9,6 +9,7 @@ namespace Zend\Db\Adapter\Platform; +use Zend\Db\Adapter\Driver\DriverInterface; use Zend\Db\Adapter\Driver\Pgsql; use Zend\Db\Adapter\Driver\Pdo; use Zend\Db\Adapter\Exception; @@ -34,12 +35,7 @@ public function setDriver($driver) { if ($driver instanceof Pgsql\Pgsql || ($driver instanceof Pdo\Pdo && $driver->getDatabasePlatformName() == 'Postgresql') - ) { - $this->resource = $driver->getConnection()->getResource(); - return $this; - } - - if ((is_resource($driver) && (in_array(get_resource_type($driver), array('pgsql link', 'pgsql link persistent')))) + || (is_resource($driver) && (in_array(get_resource_type($driver), array('pgsql link', 'pgsql link persistent')))) || ($driver instanceof \PDO && $driver->getAttribute(\PDO::ATTR_DRIVER_NAME) == 'pgsql') ) { $this->resource = $driver; @@ -113,6 +109,9 @@ public function getQuoteValueSymbol() */ public function quoteValue($value) { + if ($this->resource instanceof DriverInterface) { + $this->resource = $this->resource->getConnection()->getResource(); + } if (is_resource($this->resource)) { return '\'' . pg_escape_string($this->resource, $value) . '\''; } @@ -136,6 +135,9 @@ public function quoteValue($value) */ public function quoteTrustedValue($value) { + if ($this->resource instanceof DriverInterface) { + $this->resource = $this->resource->getConnection()->getResource(); + } if (is_resource($this->resource)) { return '\'' . pg_escape_string($this->resource, $value) . '\''; } diff --git a/lib/Zend/Db/Adapter/Platform/SqlServer.php b/lib/Zend/Db/Adapter/Platform/SqlServer.php index 7924be70c5..56e9cc54ff 100644 --- a/lib/Zend/Db/Adapter/Platform/SqlServer.php +++ b/lib/Zend/Db/Adapter/Platform/SqlServer.php @@ -9,7 +9,7 @@ namespace Zend\Db\Adapter\Platform; -use Zend\Db\Adapter\Driver\Sqlsrv; +use Zend\Db\Adapter\Driver\DriverInterface; use Zend\Db\Adapter\Driver\Pdo; use Zend\Db\Adapter\Exception; @@ -34,14 +34,9 @@ public function __construct($driver = null) public function setDriver($driver) { // handle Zend_Db drivers - if ($driver instanceof Pdo\Pdo && $driver->getDatabasePlatformName() == 'Sqlsrv') { - /** @var $driver \Zend\Db\Adapter\Driver\DriverInterface */ - $this->resource = $driver->getConnection()->getResource(); - return $this; - } - - // handle - if (($driver instanceof \PDO && $driver->getAttribute(\PDO::ATTR_DRIVER_NAME) == 'sqlsrv')) { + if (($driver instanceof Pdo\Pdo && $driver->getDatabasePlatformName() == 'Sqlsrv') + || (($driver instanceof \PDO && $driver->getAttribute(\PDO::ATTR_DRIVER_NAME) == 'sqlsrv')) + ) { $this->resource = $driver; return $this; } @@ -112,6 +107,9 @@ public function getQuoteValueSymbol() */ public function quoteValue($value) { + if ($this->resource instanceof DriverInterface) { + $this->resource = $this->resource->getConnection()->getResource(); + } if ($this->resource instanceof \PDO) { return $this->resource->quote($value); } @@ -132,6 +130,9 @@ public function quoteValue($value) */ public function quoteTrustedValue($value) { + if ($this->resource instanceof DriverInterface) { + $this->resource = $this->resource->getConnection()->getResource(); + } if ($this->resource instanceof \PDO) { return $this->resource->quote($value); } diff --git a/lib/Zend/Db/Adapter/Platform/Sqlite.php b/lib/Zend/Db/Adapter/Platform/Sqlite.php index aa0a65427a..f4dc769709 100644 --- a/lib/Zend/Db/Adapter/Platform/Sqlite.php +++ b/lib/Zend/Db/Adapter/Platform/Sqlite.php @@ -9,6 +9,7 @@ namespace Zend\Db\Adapter\Platform; +use Zend\Db\Adapter\Driver\DriverInterface; use Zend\Db\Adapter\Driver\Pdo; use Zend\Db\Adapter\Exception; @@ -32,16 +33,13 @@ public function __construct($driver = null) */ public function setDriver($driver) { - if ($driver instanceof \PDO && $driver->getAttribute(\PDO::ATTR_DRIVER_NAME) == 'sqlite') { + if (($driver instanceof \PDO && $driver->getAttribute(\PDO::ATTR_DRIVER_NAME) == 'sqlite') + || ($driver instanceof Pdo\Pdo && $driver->getDatabasePlatformName() == 'Sqlite') + ) { $this->resource = $driver; return $this; } - if ($driver instanceof Pdo\Pdo && $driver->getDatabasePlatformName() == 'Sqlite') { - $this->resource = $driver->getConnection()->getResource(); - return $this; - } - throw new Exception\InvalidArgumentException('$driver must be a Sqlite PDO Zend\Db\Adapter\Driver, Sqlite PDO instance'); } @@ -109,6 +107,9 @@ public function getQuoteValueSymbol() */ public function quoteValue($value) { + if ($this->resource instanceof DriverInterface) { + $this->resource = $this->resource->getConnection()->getResource(); + } if ($this->resource instanceof \PDO) { return $this->resource->quote($value); } @@ -129,6 +130,9 @@ public function quoteValue($value) */ public function quoteTrustedValue($value) { + if ($this->resource instanceof DriverInterface) { + $this->resource = $this->resource->getConnection()->getResource(); + } if ($this->resource instanceof \PDO) { return $this->resource->quote($value); } diff --git a/lib/Zend/Db/Metadata/Source/AbstractSource.php b/lib/Zend/Db/Metadata/Source/AbstractSource.php index 2b37c95fb7..9e6c614b7f 100644 --- a/lib/Zend/Db/Metadata/Source/AbstractSource.php +++ b/lib/Zend/Db/Metadata/Source/AbstractSource.php @@ -380,7 +380,7 @@ public function getConstraintKeys($constraint, $table, $schema = null) $schema = $this->defaultSchema; } - $this->loadConstraintData($table, $schema); + $this->loadConstraintReferences($table, $schema); // organize references first $references = array(); @@ -390,6 +390,8 @@ public function getConstraintKeys($constraint, $table, $schema = null) } } + $this->loadConstraintDataKeys($schema); + $keys = array(); foreach ($this->data['constraint_keys'][$schema] as $constraintKeyInfo) { if ($constraintKeyInfo['table_name'] == $table && $constraintKeyInfo['constraint_name'] === $constraint) { @@ -504,10 +506,18 @@ protected function prepareDataHierarchy($type) } } + /** + * Load schema data + */ protected function loadSchemaData() { } + /** + * Load table name data + * + * @param string $schema + */ protected function loadTableNameData($schema) { if (isset($this->data['table_names'][$schema])) { @@ -517,6 +527,12 @@ protected function loadTableNameData($schema) $this->prepareDataHierarchy('table_names', $schema); } + /** + * Load column data + * + * @param string $table + * @param string $schema + */ protected function loadColumnData($table, $schema) { if (isset($this->data['columns'][$schema][$table])) { @@ -526,6 +542,12 @@ protected function loadColumnData($table, $schema) $this->prepareDataHierarchy('columns', $schema, $table); } + /** + * Load constraint data + * + * @param string $table + * @param string $schema + */ protected function loadConstraintData($table, $schema) { if (isset($this->data['constraints'][$schema])) { @@ -535,6 +557,40 @@ protected function loadConstraintData($table, $schema) $this->prepareDataHierarchy('constraints', $schema); } + /** + * Load constraint data keys + * + * @param string $schema + */ + protected function loadConstraintDataKeys($schema) + { + if (isset($this->data['constraint_keys'][$schema])) { + return; + } + + $this->prepareDataHierarchy('constraint_keys', $schema); + } + + /** + * Load constraint references + * + * @param string $table + * @param string $schema + */ + protected function loadConstraintReferences($table, $schema) + { + if (isset($this->data['constraint_references'][$schema])) { + return; + } + + $this->prepareDataHierarchy('constraint_references', $schema); + } + + /** + * Load trigger data + * + * @param string $schema + */ protected function loadTriggerData($schema) { if (isset($this->data['triggers'][$schema])) { diff --git a/lib/Zend/Db/Metadata/Source/MysqlMetadata.php b/lib/Zend/Db/Metadata/Source/MysqlMetadata.php index 76f0cdd14a..de5f366e31 100644 --- a/lib/Zend/Db/Metadata/Source/MysqlMetadata.php +++ b/lib/Zend/Db/Metadata/Source/MysqlMetadata.php @@ -25,7 +25,7 @@ protected function loadSchemaData() $sql = 'SELECT ' . $p->quoteIdentifier('SCHEMA_NAME') . ' FROM ' . $p->quoteIdentifierChain(array('INFORMATION_SCHEMA', 'SCHEMATA')) . ' WHERE ' . $p->quoteIdentifier('SCHEMA_NAME') - . ' != ' . $p->quoteValue('INFORMATION_SCHEMA'); + . ' != \'INFORMATION_SCHEMA\''; $results = $this->adapter->query($sql, Adapter::QUERY_MODE_EXECUTE); @@ -66,14 +66,14 @@ protected function loadTableNameData($schema) . ' = ' . $p->quoteIdentifierChain(array('V','TABLE_NAME')) . ' WHERE ' . $p->quoteIdentifierChain(array('T','TABLE_TYPE')) - . ' IN (' . $p->quoteValueList(array('BASE TABLE', 'VIEW')) . ')'; + . ' IN (\'BASE TABLE\', \'VIEW\')'; if ($schema != self::DEFAULT_SCHEMA) { $sql .= ' AND ' . $p->quoteIdentifierChain(array('T','TABLE_SCHEMA')) - . ' = ' . $p->quoteValue($schema); + . ' = ' . $p->quoteTrustedValue($schema); } else { $sql .= ' AND ' . $p->quoteIdentifierChain(array('T','TABLE_SCHEMA')) - . ' != ' . $p->quoteValue('INFORMATION_SCHEMA'); + . ' != \'INFORMATION_SCHEMA\''; } $results = $this->adapter->query($sql, Adapter::QUERY_MODE_EXECUTE); @@ -122,16 +122,16 @@ protected function loadColumnData($table, $schema) . ' AND ' . $p->quoteIdentifierChain(array('T','TABLE_NAME')) . ' = ' . $p->quoteIdentifierChain(array('C','TABLE_NAME')) . ' WHERE ' . $p->quoteIdentifierChain(array('T','TABLE_TYPE')) - . ' IN (' . $p->quoteValueList(array('BASE TABLE', 'VIEW')) . ')' + . ' IN (\'BASE TABLE\', \'VIEW\')' . ' AND ' . $p->quoteIdentifierChain(array('T','TABLE_NAME')) - . ' = ' . $p->quoteValue($table); + . ' = ' . $p->quoteTrustedValue($table); if ($schema != self::DEFAULT_SCHEMA) { $sql .= ' AND ' . $p->quoteIdentifierChain(array('T','TABLE_SCHEMA')) - . ' = ' . $p->quoteValue($schema); + . ' = ' . $p->quoteTrustedValue($schema); } else { $sql .= ' AND ' . $p->quoteIdentifierChain(array('T','TABLE_SCHEMA')) - . ' != ' . $p->quoteValue('INFORMATION_SCHEMA'); + . ' != \'INFORMATION_SCHEMA\''; } $results = $this->adapter->query($sql, Adapter::QUERY_MODE_EXECUTE); @@ -216,16 +216,16 @@ protected function loadConstraintData($table, $schema) . ' = ' . $p->quoteIdentifierChain(array('RC','CONSTRAINT_NAME')) . ' WHERE ' . $p->quoteIdentifierChain(array('T','TABLE_NAME')) - . ' = ' . $p->quoteValue($table) + . ' = ' . $p->quoteTrustedValue($table) . ' AND ' . $p->quoteIdentifierChain(array('T','TABLE_TYPE')) - . ' IN (' . $p->quoteValueList(array('BASE TABLE', 'VIEW')) . ')'; + . ' IN (\'BASE TABLE\', \'VIEW\')'; if ($schema != self::DEFAULT_SCHEMA) { $sql .= ' AND ' . $p->quoteIdentifierChain(array('T','TABLE_SCHEMA')) - . ' = ' . $p->quoteValue($schema); + . ' = ' . $p->quoteTrustedValue($schema); } else { $sql .= ' AND ' . $p->quoteIdentifierChain(array('T','TABLE_SCHEMA')) - . ' != ' . $p->quoteValue('INFORMATION_SCHEMA'); + . ' != \'INFORMATION_SCHEMA\''; } $sql .= ' ORDER BY CASE ' . $p->quoteIdentifierChain(array('TC','CONSTRAINT_TYPE')) @@ -302,14 +302,14 @@ protected function loadConstraintDataNames($schema) . ' AND ' . $p->quoteIdentifierChain(array('T','TABLE_NAME')) . ' = ' . $p->quoteIdentifierChain(array('TC','TABLE_NAME')) . ' WHERE ' . $p->quoteIdentifierChain(array('T','TABLE_TYPE')) - . ' IN (' . $p->quoteValueList(array('BASE TABLE', 'VIEW')) . ')'; + . ' IN (\'BASE TABLE\', \'VIEW\')'; if ($schema != self::DEFAULT_SCHEMA) { $sql .= ' AND ' . $p->quoteIdentifierChain(array('T','TABLE_SCHEMA')) - . ' = ' . $p->quoteValue($schema); + . ' = ' . $p->quoteTrustedValue($schema); } else { $sql .= ' AND ' . $p->quoteIdentifierChain(array('T','TABLE_SCHEMA')) - . ' != ' . $p->quoteValue('INFORMATION_SCHEMA'); + . ' != \'INFORMATION_SCHEMA\''; } $results = $this->adapter->query($sql, Adapter::QUERY_MODE_EXECUTE); @@ -353,14 +353,14 @@ protected function loadConstraintDataKeys($schema) . ' = ' . $p->quoteIdentifierChain(array('KCU','TABLE_NAME')) . ' WHERE ' . $p->quoteIdentifierChain(array('T','TABLE_TYPE')) - . ' IN (' . $p->quoteValueList(array('BASE TABLE', 'VIEW')) . ')'; + . ' IN (\'BASE TABLE\', \'VIEW\')'; if ($schema != self::DEFAULT_SCHEMA) { $sql .= ' AND ' . $p->quoteIdentifierChain(array('T','TABLE_SCHEMA')) - . ' = ' . $p->quoteValue($schema); + . ' = ' . $p->quoteTrustedValue($schema); } else { $sql .= ' AND ' . $p->quoteIdentifierChain(array('T','TABLE_SCHEMA')) - . ' != ' . $p->quoteValue('INFORMATION_SCHEMA'); + . ' != \'INFORMATION_SCHEMA\''; } $results = $this->adapter->query($sql, Adapter::QUERY_MODE_EXECUTE); @@ -415,14 +415,14 @@ protected function loadConstraintReferences($schema) . ' = ' . $p->quoteIdentifierChain(array('KCU','CONSTRAINT_NAME')) . 'WHERE ' . $p->quoteIdentifierChain(array('T','TABLE_TYPE')) - . ' IN (' . $p->quoteValueList(array('BASE TABLE', 'VIEW')) . ')'; + . ' IN (\'BASE TABLE\', \'VIEW\')'; if ($schema != self::DEFAULT_SCHEMA) { $sql .= ' AND ' . $p->quoteIdentifierChain(array('T','TABLE_SCHEMA')) - . ' = ' . $p->quoteValue($schema); + . ' = ' . $p->quoteTrustedValue($schema); } else { $sql .= ' AND ' . $p->quoteIdentifierChain(array('T','TABLE_SCHEMA')) - . ' != ' . $p->quoteValue('INFORMATION_SCHEMA'); + . ' != \'INFORMATION_SCHEMA\''; } $results = $this->adapter->query($sql, Adapter::QUERY_MODE_EXECUTE); @@ -475,10 +475,10 @@ protected function loadTriggerData($schema) if ($schema != self::DEFAULT_SCHEMA) { $sql .= $p->quoteIdentifier('TRIGGER_SCHEMA') - . ' = ' . $p->quoteValue($schema); + . ' = ' . $p->quoteTrustedValue($schema); } else { $sql .= $p->quoteIdentifier('TRIGGER_SCHEMA') - . ' != ' . $p->quoteValue('INFORMATION_SCHEMA'); + . ' != \'INFORMATION_SCHEMA\''; } $results = $this->adapter->query($sql, Adapter::QUERY_MODE_EXECUTE); diff --git a/lib/Zend/Db/Metadata/Source/PostgresqlMetadata.php b/lib/Zend/Db/Metadata/Source/PostgresqlMetadata.php index b7b583adef..b52b39048c 100644 --- a/lib/Zend/Db/Metadata/Source/PostgresqlMetadata.php +++ b/lib/Zend/Db/Metadata/Source/PostgresqlMetadata.php @@ -26,7 +26,7 @@ protected function loadSchemaData() $sql = 'SELECT ' . $p->quoteIdentifier('schema_name') . ' FROM ' . $p->quoteIdentifierChain(array('information_schema', 'schemata')) . ' WHERE ' . $p->quoteIdentifier('schema_name') - . ' != ' . $p->quoteValue('information_schema') + . ' != \'information_schema\'' . ' AND ' . $p->quoteIdentifier('schema_name') . " NOT LIKE 'pg_%'"; $results = $this->adapter->query($sql, Adapter::QUERY_MODE_EXECUTE); @@ -68,14 +68,14 @@ protected function loadTableNameData($schema) . ' = ' . $p->quoteIdentifierChain(array('v','table_name')) . ' WHERE ' . $p->quoteIdentifierChain(array('t','table_type')) - . ' IN (' . $p->quoteValueList(array('BASE TABLE', 'VIEW')) . ')'; + . ' IN (\'BASE TABLE\', \'VIEW\')'; if ($schema != self::DEFAULT_SCHEMA) { $sql .= ' AND ' . $p->quoteIdentifierChain(array('t','table_schema')) - . ' = ' . $p->quoteValue($schema); + . ' = ' . $p->quoteTrustedValue($schema); } else { $sql .= ' AND ' . $p->quoteIdentifierChain(array('t','table_schema')) - . ' != ' . $p->quoteValue('information_schema'); + . ' != \'information_schema\''; } $results = $this->adapter->query($sql, Adapter::QUERY_MODE_EXECUTE); @@ -122,13 +122,13 @@ protected function loadColumnData($table, $schema) . ' FROM ' . $platform->quoteIdentifier('information_schema') . $platform->getIdentifierSeparator() . $platform->quoteIdentifier('columns') . ' WHERE ' . $platform->quoteIdentifier('table_schema') - . ' != ' . $platform->quoteValue('information') + . ' != \'information\'' . ' AND ' . $platform->quoteIdentifier('table_name') - . ' = ' . $platform->quoteValue($table); + . ' = ' . $platform->quoteTrustedValue($table); if ($schema != '__DEFAULT_SCHEMA__') { $sql .= ' AND ' . $platform->quoteIdentifier('table_schema') - . ' = ' . $platform->quoteValue($schema); + . ' = ' . $platform->quoteTrustedValue($schema); } $results = $this->adapter->query($sql, Adapter::QUERY_MODE_EXECUTE); @@ -221,16 +221,16 @@ protected function loadConstraintData($table, $schema) . ' = ' . $p->quoteIdentifierChain(array('kcu2','ordinal_position')) . ' WHERE ' . $p->quoteIdentifierChain(array('t','table_name')) - . ' = ' . $p->quoteValue($table) + . ' = ' . $p->quoteTrustedValue($table) . ' AND ' . $p->quoteIdentifierChain(array('t','table_type')) - . ' IN (' . $p->quoteValueList(array('BASE TABLE', 'VIEW')) . ')'; + . ' IN (\'BASE TABLE\', \'VIEW\')'; if ($schema != self::DEFAULT_SCHEMA) { $sql .= ' AND ' . $p->quoteIdentifierChain(array('t','table_schema')) - . ' = ' . $p->quoteValue($schema); + . ' = ' . $p->quoteTrustedValue($schema); } else { $sql .= ' AND ' . $p->quoteIdentifierChain(array('t','table_schema')) - . ' != ' . $p->quoteValue('information_schema'); + . ' != \'information_schema\''; } $sql .= ' ORDER BY CASE ' . $p->quoteIdentifierChain(array('tc','constraint_type')) @@ -322,10 +322,10 @@ protected function loadTriggerData($schema) if ($schema != self::DEFAULT_SCHEMA) { $sql .= $p->quoteIdentifier('trigger_schema') - . ' = ' . $p->quoteValue($schema); + . ' = ' . $p->quoteTrustedValue($schema); } else { $sql .= $p->quoteIdentifier('trigger_schema') - . ' != ' . $p->quoteValue('information_schema'); + . ' != \'information_schema\''; } $results = $this->adapter->query($sql, Adapter::QUERY_MODE_EXECUTE); diff --git a/lib/Zend/Db/Metadata/Source/SqlServerMetadata.php b/lib/Zend/Db/Metadata/Source/SqlServerMetadata.php index a24287bd26..c890d8f9db 100644 --- a/lib/Zend/Db/Metadata/Source/SqlServerMetadata.php +++ b/lib/Zend/Db/Metadata/Source/SqlServerMetadata.php @@ -27,7 +27,7 @@ protected function loadSchemaData() $sql = 'SELECT ' . $p->quoteIdentifier('SCHEMA_NAME') . ' FROM ' . $p->quoteIdentifierChain(array('INFORMATION_SCHEMA', 'SCHEMATA')) . ' WHERE ' . $p->quoteIdentifier('SCHEMA_NAME') - . ' != ' . $p->quoteValue('INFORMATION_SCHEMA'); + . ' != \'INFORMATION_SCHEMA\''; $results = $this->adapter->query($sql, Adapter::QUERY_MODE_EXECUTE); @@ -68,14 +68,14 @@ protected function loadTableNameData($schema) . ' = ' . $p->quoteIdentifierChain(array('V','TABLE_NAME')) . ' WHERE ' . $p->quoteIdentifierChain(array('T','TABLE_TYPE')) - . ' IN (' . $p->quoteValueList(array('BASE TABLE', 'VIEW')) . ')'; + . ' IN (\'BASE TABLE\', \'VIEW\')'; if ($schema != self::DEFAULT_SCHEMA) { $sql .= ' AND ' . $p->quoteIdentifierChain(array('T','TABLE_SCHEMA')) - . ' = ' . $p->quoteValue($schema); + . ' = ' . $p->quoteTrustedValue($schema); } else { $sql .= ' AND ' . $p->quoteIdentifierChain(array('T','TABLE_SCHEMA')) - . ' != ' . $p->quoteValue('INFORMATION_SCHEMA'); + . ' != \'INFORMATION_SCHEMA\''; } $results = $this->adapter->query($sql, Adapter::QUERY_MODE_EXECUTE); @@ -123,16 +123,16 @@ protected function loadColumnData($table, $schema) . ' AND ' . $p->quoteIdentifierChain(array('T','TABLE_NAME')) . ' = ' . $p->quoteIdentifierChain(array('C','TABLE_NAME')) . ' WHERE ' . $p->quoteIdentifierChain(array('T','TABLE_TYPE')) - . ' IN (' . $p->quoteValueList(array('BASE TABLE', 'VIEW')) . ')' + . ' IN (\'BASE TABLE\', \'VIEW\')' . ' AND ' . $p->quoteIdentifierChain(array('T','TABLE_NAME')) - . ' = ' . $p->quoteValue($table); + . ' = ' . $p->quoteTrustedValue($table); if ($schema != self::DEFAULT_SCHEMA) { $sql .= ' AND ' . $p->quoteIdentifierChain(array('T','TABLE_SCHEMA')) - . ' = ' . $p->quoteValue($schema); + . ' = ' . $p->quoteTrustedValue($schema); } else { $sql .= ' AND ' . $p->quoteIdentifierChain(array('T','TABLE_SCHEMA')) - . ' != ' . $p->quoteValue('INFORMATION_SCHEMA'); + . ' != \'INFORMATION_SCHEMA\''; } $results = $this->adapter->query($sql, Adapter::QUERY_MODE_EXECUTE); @@ -225,16 +225,16 @@ protected function loadConstraintData($table, $schema) . ' = ' . $p->quoteIdentifierChain(array('KCU2','ORDINAL_POSITION')) . ' WHERE ' . $p->quoteIdentifierChain(array('T','TABLE_NAME')) - . ' = ' . $p->quoteValue($table) + . ' = ' . $p->quoteTrustedValue($table) . ' AND ' . $p->quoteIdentifierChain(array('T','TABLE_TYPE')) - . ' IN (' . $p->quoteValueList(array('BASE TABLE', 'VIEW')) . ')'; + . ' IN (\'BASE TABLE\', \'VIEW\')'; if ($schema != self::DEFAULT_SCHEMA) { $sql .= ' AND ' . $p->quoteIdentifierChain(array('T','TABLE_SCHEMA')) - . ' = ' . $p->quoteValue($schema); + . ' = ' . $p->quoteTrustedValue($schema); } else { $sql .= ' AND ' . $p->quoteIdentifierChain(array('T','TABLE_SCHEMA')) - . ' != ' . $p->quoteValue('INFORMATION_SCHEMA'); + . ' != \'INFORMATION_SCHEMA\''; } $sql .= ' ORDER BY CASE ' . $p->quoteIdentifierChain(array('TC','CONSTRAINT_TYPE')) @@ -321,10 +321,10 @@ protected function loadTriggerData($schema) if ($schema != self::DEFAULT_SCHEMA) { $sql .= $p->quoteIdentifier('TRIGGER_SCHEMA') - . ' = ' . $p->quoteValue($schema); + . ' = ' . $p->quoteTrustedValue($schema); } else { $sql .= $p->quoteIdentifier('TRIGGER_SCHEMA') - . ' != ' . $p->quoteValue('INFORMATION_SCHEMA'); + . ' != \'INFORMATION_SCHEMA\''; } $results = $this->adapter->query($sql, Adapter::QUERY_MODE_EXECUTE); diff --git a/lib/Zend/Db/Metadata/Source/SqliteMetadata.php b/lib/Zend/Db/Metadata/Source/SqliteMetadata.php index 0a47ec125a..aa7e5e0d51 100644 --- a/lib/Zend/Db/Metadata/Source/SqliteMetadata.php +++ b/lib/Zend/Db/Metadata/Source/SqliteMetadata.php @@ -246,7 +246,7 @@ protected function fetchPragma($name, $value = null, $schema = null) $sql .= $name; if (null !== $value) { - $sql .= '(' . $p->quoteValue($value) . ')'; + $sql .= '(' . $p->quoteTrustedValue($value) . ')'; } $results = $this->adapter->query($sql, Adapter::QUERY_MODE_EXECUTE); diff --git a/lib/Zend/Db/RowGateway/Feature/AbstractFeature.php b/lib/Zend/Db/RowGateway/Feature/AbstractFeature.php index 9ab091448a..0bb91a6663 100644 --- a/lib/Zend/Db/RowGateway/Feature/AbstractFeature.php +++ b/lib/Zend/Db/RowGateway/Feature/AbstractFeature.php @@ -30,7 +30,7 @@ abstract class AbstractFeature extends AbstractRowGateway */ public function getName() { - return get_called_class(); + return get_class($this); } /** diff --git a/lib/Zend/Db/Sql/Platform/Oracle/SelectDecorator.php b/lib/Zend/Db/Sql/Platform/Oracle/SelectDecorator.php index e941fab843..ba2c5700f8 100644 --- a/lib/Zend/Db/Sql/Platform/Oracle/SelectDecorator.php +++ b/lib/Zend/Db/Sql/Platform/Oracle/SelectDecorator.php @@ -34,6 +34,14 @@ public function setSubject($select) $this->select = $select; } + /** + * @see \Zend\Db\Sql\Select::renderTable + */ + protected function renderTable($table, $alias = null) + { + return $table . ' ' . $alias; + } + /** * @param AdapterInterface $adapter * @param StatementContainerInterface $statementContainer diff --git a/lib/Zend/Db/Sql/Select.php b/lib/Zend/Db/Sql/Select.php index be614c7774..47885e187f 100644 --- a/lib/Zend/Db/Sql/Select.php +++ b/lib/Zend/Db/Sql/Select.php @@ -560,6 +560,31 @@ public function isTableReadOnly() return $this->tableReadOnly; } + /** + * Render table with alias in from/join parts + * + * @todo move TableIdentifier concatination here + * @param string $table + * @param string $alias + * @return string + */ + protected function renderTable($table, $alias = null) + { + $sql = $table; + if ($alias) { + $sql .= ' AS ' . $alias; + } + return $sql; + } + + /** + * Process the select part + * + * @param PlatformInterface $platform + * @param DriverInterface $driver + * @param ParameterContainer $parameterContainer + * @return null|array + */ protected function processSelect(PlatformInterface $platform, DriverInterface $driver = null, ParameterContainer $parameterContainer = null) { $expr = 1; @@ -593,7 +618,7 @@ protected function processSelect(PlatformInterface $platform, DriverInterface $d if ($alias) { $fromTable = $platform->quoteIdentifier($alias); - $table .= ' AS ' . $fromTable; + $table = $this->renderTable($table, $fromTable); } else { $fromTable = $table; } diff --git a/lib/Zend/Db/TableGateway/Feature/AbstractFeature.php b/lib/Zend/Db/TableGateway/Feature/AbstractFeature.php index d22a7fb103..4d9503e503 100644 --- a/lib/Zend/Db/TableGateway/Feature/AbstractFeature.php +++ b/lib/Zend/Db/TableGateway/Feature/AbstractFeature.php @@ -24,7 +24,7 @@ abstract class AbstractFeature extends AbstractTableGateway public function getName() { - return get_called_class(); + return get_class($this); } public function setTableGateway(AbstractTableGateway $tableGateway) diff --git a/lib/Zend/Db/TableGateway/Feature/SequenceFeature.php b/lib/Zend/Db/TableGateway/Feature/SequenceFeature.php index da4b310dbf..1122ccfe02 100644 --- a/lib/Zend/Db/TableGateway/Feature/SequenceFeature.php +++ b/lib/Zend/Db/TableGateway/Feature/SequenceFeature.php @@ -41,7 +41,9 @@ public function __construct($primaryKeyField, $sequenceName) $this->sequenceName = $sequenceName; } - + /** + * @param Insert $insert + */ public function preInsert(Insert $insert) { $columns = $insert->getRawState('columns'); @@ -53,20 +55,19 @@ public function preInsert(Insert $insert) } $this->sequenceValue = $this->nextSequenceId(); - if ($this->sequenceValue === null) + if ($this->sequenceValue === null) { return $insert; + } - array_push($columns, $this->primaryKeyField); - array_push($values, $this->sequenceValue); - $insert->columns($columns); - $insert->values($values); + $insert->values(array($this->primaryKeyField => $this->sequenceValue), Insert::VALUES_MERGE); return $insert; } public function postInsert(StatementInterface $statement, ResultInterface $result) { - if ($this->sequenceValue !== null) + if ($this->sequenceValue !== null) { $this->tableGateway->lastInsertValue = $this->sequenceValue; + } } /** @@ -78,7 +79,6 @@ public function nextSequenceId() $platform = $this->tableGateway->adapter->getPlatform(); $platformName = $platform->getName(); - $sql = ''; switch ($platformName) { case 'Oracle': $sql = 'SELECT ' . $platform->quoteIdentifier($this->sequenceName) . '.NEXTVAL FROM dual'; @@ -93,7 +93,7 @@ public function nextSequenceId() $statement = $this->tableGateway->adapter->createStatement(); $statement->prepare($sql); $result = $statement->execute(); - $sequence = $result->getResource()->fetch(\PDO::FETCH_ASSOC); + $sequence = $result->current(); unset($statement, $result); return $sequence['nextval']; } @@ -107,7 +107,6 @@ public function lastSequenceId() $platform = $this->tableGateway->adapter->getPlatform(); $platformName = $platform->getName(); - $sql = ''; switch ($platformName) { case 'Oracle': $sql = 'SELECT ' . $platform->quoteIdentifier($this->sequenceName) . '.CURRVAL FROM dual'; @@ -122,7 +121,7 @@ public function lastSequenceId() $statement = $this->tableGateway->adapter->createStatement(); $statement->prepare($sql); $result = $statement->execute(); - $sequence = $result->getResource()->fetch(\PDO::FETCH_ASSOC); + $sequence = $result->current(); unset($statement, $result); return $sequence['currval']; } diff --git a/lib/Zend/Escaper/Escaper.php b/lib/Zend/Escaper/Escaper.php index d67db32cd9..91a5140480 100644 --- a/lib/Zend/Escaper/Escaper.php +++ b/lib/Zend/Escaper/Escaper.php @@ -103,14 +103,14 @@ public function __construct($encoding = null) $encoding = (string) $encoding; if ($encoding === '') { throw new Exception\InvalidArgumentException( - get_called_class() . ' constructor parameter does not allow a blank value' + get_class($this) . ' constructor parameter does not allow a blank value' ); } $encoding = strtolower($encoding); if (!in_array($encoding, $this->supportedEncodings)) { throw new Exception\InvalidArgumentException( - 'Value of \'' . $encoding . '\' passed to ' . get_called_class() + 'Value of \'' . $encoding . '\' passed to ' . get_class($this) . ' constructor parameter is invalid. Provide an encoding supported by htmlspecialchars()' ); } @@ -376,7 +376,7 @@ protected function convertEncoding($string, $to, $from) $result = mb_convert_encoding($string, $to, $from); } else { throw new Exception\RuntimeException( - get_called_class() + get_class($this) . ' requires either the iconv or mbstring extension to be installed' . ' when escaping for non UTF-8 strings.' ); diff --git a/lib/Zend/EventManager/EventManager.php b/lib/Zend/EventManager/EventManager.php index f5d1597b7f..3f4c58fc7b 100644 --- a/lib/Zend/EventManager/EventManager.php +++ b/lib/Zend/EventManager/EventManager.php @@ -157,7 +157,7 @@ public function setIdentifiers($identifiers) public function addIdentifiers($identifiers) { if (is_array($identifiers) || $identifiers instanceof Traversable) { - $this->identifiers = array_unique($this->identifiers + (array) $identifiers); + $this->identifiers = array_unique(array_merge($this->identifiers, (array) $identifiers)); } elseif ($identifiers !== null) { $this->identifiers = array_unique(array_merge($this->identifiers, array($identifiers))); } @@ -201,6 +201,9 @@ public function trigger($event, $target = null, $argv = array(), $callback = nul throw new Exception\InvalidCallbackException('Invalid callback provided'); } + // Initial value of stop propagation flag should be false + $e->stopPropagation(false); + return $this->triggerListeners($event, $e, $callback); } @@ -243,6 +246,9 @@ public function triggerUntil($event, $target, $argv = null, $callback = null) throw new Exception\InvalidCallbackException('Invalid callback provided'); } + // Initial value of stop propagation flag should be false + $e->stopPropagation(false); + return $this->triggerListeners($event, $e, $callback); } @@ -455,9 +461,15 @@ protected function triggerListeners($event, EventInterface $e, $callback = null) } foreach ($listeners as $listener) { + $listenerCallback = $listener->getCallback(); + if (!$listenerCallback) { + $this->detach($listener); + continue; + } + // Trigger the listener's callback, and push its result onto the // response collection - $responses->push(call_user_func($listener->getCallback(), $e)); + $responses->push(call_user_func($listenerCallback, $e)); // If the event was asked to stop propagating, do so if ($e->propagationIsStopped()) { diff --git a/lib/Zend/EventManager/ProvidesEvents.php b/lib/Zend/EventManager/ProvidesEvents.php index 560e97a733..ea46333a1f 100644 --- a/lib/Zend/EventManager/ProvidesEvents.php +++ b/lib/Zend/EventManager/ProvidesEvents.php @@ -29,7 +29,7 @@ trait ProvidesEvents */ public function setEventManager(EventManagerInterface $events) { - $identifiers = array(__CLASS__, get_called_class()); + $identifiers = array(__CLASS__, get_class($this)); if (isset($this->eventIdentifier)) { if ((is_string($this->eventIdentifier)) || (is_array($this->eventIdentifier)) diff --git a/lib/Zend/Feed/PubSubHubbub/AbstractCallback.php b/lib/Zend/Feed/PubSubHubbub/AbstractCallback.php index f54f0f48fd..cc408e56a6 100644 --- a/lib/Zend/Feed/PubSubHubbub/AbstractCallback.php +++ b/lib/Zend/Feed/PubSubHubbub/AbstractCallback.php @@ -199,7 +199,9 @@ public function getSubscriberCount() protected function _detectCallbackUrl() { $callbackUrl = ''; - if (isset($_SERVER['HTTP_X_REWRITE_URL'])) { + if (isset($_SERVER['HTTP_X_ORIGINAL_URL'])) { + $callbackUrl = $_SERVER['HTTP_X_ORIGINAL_URL']; + } elseif (isset($_SERVER['HTTP_X_REWRITE_URL'])) { $callbackUrl = $_SERVER['HTTP_X_REWRITE_URL']; } elseif (isset($_SERVER['REQUEST_URI'])) { $callbackUrl = $_SERVER['REQUEST_URI']; diff --git a/lib/Zend/Feed/PubSubHubbub/Model/AbstractModel.php b/lib/Zend/Feed/PubSubHubbub/Model/AbstractModel.php index 3862a4c302..023fe8ed67 100644 --- a/lib/Zend/Feed/PubSubHubbub/Model/AbstractModel.php +++ b/lib/Zend/Feed/PubSubHubbub/Model/AbstractModel.php @@ -29,7 +29,7 @@ class AbstractModel public function __construct(TableGatewayInterface $tableGateway = null) { if ($tableGateway === null) { - $parts = explode('\\', get_called_class()); + $parts = explode('\\', get_class($this)); $table = strtolower(array_pop($parts)); $this->db = new TableGateway($table, null); } else { diff --git a/lib/Zend/Feed/Writer/Renderer/AbstractRenderer.php b/lib/Zend/Feed/Writer/Renderer/AbstractRenderer.php index 199ad597ba..c630fdf2fa 100644 --- a/lib/Zend/Feed/Writer/Renderer/AbstractRenderer.php +++ b/lib/Zend/Feed/Writer/Renderer/AbstractRenderer.php @@ -218,7 +218,7 @@ protected function _loadExtensions() Writer\Writer::registerCoreExtensions(); $manager = Writer\Writer::getExtensionManager(); $all = Writer\Writer::getExtensions(); - if (stripos(get_called_class(), 'entry')) { + if (stripos(get_class($this), 'entry')) { $exts = $all['entryRenderer']; } else { $exts = $all['feedRenderer']; diff --git a/lib/Zend/File/Transfer/Adapter/AbstractAdapter.php b/lib/Zend/File/Transfer/Adapter/AbstractAdapter.php index 002e958d23..53bfa0dfc4 100644 --- a/lib/Zend/File/Transfer/Adapter/AbstractAdapter.php +++ b/lib/Zend/File/Transfer/Adapter/AbstractAdapter.php @@ -1224,16 +1224,15 @@ protected function detectMimeType($value) } if (class_exists('finfo', false)) { - $const = defined('FILEINFO_MIME_TYPE') ? FILEINFO_MIME_TYPE : FILEINFO_MIME; if (!empty($value['options']['magicFile'])) { ErrorHandler::start(); - $mime = finfo_open($const, $value['options']['magicFile']); + $mime = finfo_open(FILEINFO_MIME_TYPE, $value['options']['magicFile']); ErrorHandler::stop(); } if (empty($mime)) { ErrorHandler::start(); - $mime = finfo_open($const); + $mime = finfo_open(FILEINFO_MIME_TYPE); ErrorHandler::stop(); } diff --git a/lib/Zend/Filter/FilterChain.php b/lib/Zend/Filter/FilterChain.php index 15189e1a32..25576d1a1b 100644 --- a/lib/Zend/Filter/FilterChain.php +++ b/lib/Zend/Filter/FilterChain.php @@ -184,8 +184,8 @@ public function attachByName($name, $options = array(), $priority = self::DEFAUL */ public function merge(FilterChain $filterChain) { - foreach ($filterChain->filters as $filter) { - $this->attach($filter); + foreach ($filterChain->filters->toArray(PriorityQueue::EXTR_BOTH) as $item) { + $this->attach($item['data'], $item['priority']); } return $this; diff --git a/lib/Zend/Filter/PregReplace.php b/lib/Zend/Filter/PregReplace.php index 2c595d6fe3..2ae2a31d7b 100644 --- a/lib/Zend/Filter/PregReplace.php +++ b/lib/Zend/Filter/PregReplace.php @@ -132,7 +132,7 @@ public function filter($value) if ($this->options['pattern'] === null) { throw new Exception\RuntimeException(sprintf( 'Filter %s does not have a valid pattern set', - get_called_class() + get_class($this) )); } diff --git a/lib/Zend/Form/Element/Collection.php b/lib/Zend/Form/Element/Collection.php index 12306208ae..1bf2043173 100644 --- a/lib/Zend/Form/Element/Collection.php +++ b/lib/Zend/Form/Element/Collection.php @@ -68,6 +68,13 @@ class Collection extends Fieldset implements FieldsetPrepareAwareInterface */ protected $templatePlaceholder = self::DEFAULT_TEMPLATE_PLACEHOLDER; + /** + * Whether or not to create new objects during modify + * + * @var bool + */ + protected $createNewObjects = false; + /** * Element used as a template * @@ -115,6 +122,10 @@ public function setOptions($options) $this->setTemplatePlaceholder($options['template_placeholder']); } + if (isset($options['create_new_objects'])) { + $this->setCreateNewObjects($options['create_new_objects']); + } + return $this; } @@ -233,6 +244,10 @@ public function populateValues($data) ) ); } + + if (! $this->createNewObjects()) { + $this->replaceTemplateObjects(); + } } /** @@ -417,6 +432,24 @@ public function getTemplatePlaceholder() return $this->templatePlaceholder; } + /** + * @param bool $createNewObjects + * @return Collection + */ + public function setCreateNewObjects($createNewObjects) + { + $this->createNewObjects = (bool) $createNewObjects; + return $this; + } + + /** + * @return bool + */ + public function createNewObjects() + { + return $this->createNewObjects; + } + /** * Get a template element used for rendering purposes only * @@ -477,7 +510,7 @@ public function extract() $targetElement = clone $this->targetElement; $targetElement->object = $value; $values[$key] = $targetElement->extract(); - if ($this->has($key)) { + if (! $this->createNewObjects() && $this->has($key)) { $fieldset = $this->get($key); if ($fieldset instanceof Fieldset && $fieldset->allowObjectBinding($value)) { $fieldset->setObject($value); @@ -536,4 +569,26 @@ protected function createTemplateElement() return $elementOrFieldset; } + + /** + * Replaces the default template object of a sub element with the corresponding + * real entity so that all properties are preserved. + * + * @return void + */ + protected function replaceTemplateObjects() + { + $fieldsets = $this->getFieldsets(); + + if (!count($fieldsets) || !$this->object) { + return; + } + + foreach ($fieldsets as $fieldset) { + $i = $fieldset->getName(); + if (isset($this->object[$i])) { + $fieldset->setObject($this->object[$i]); + } + } + } } diff --git a/lib/Zend/Form/Factory.php b/lib/Zend/Form/Factory.php index d9f47e0f3e..d3487a81f4 100644 --- a/lib/Zend/Form/Factory.php +++ b/lib/Zend/Form/Factory.php @@ -413,7 +413,7 @@ protected function prepareAndInjectObject($objectName, FieldsetInterface $fields */ protected function prepareAndInjectHydrator($hydratorOrName, FieldsetInterface $fieldset, $method) { - if (is_object($hydratorOrName) && $hydratorOrName instanceof Hydrator\HydratorInterface) { + if ($hydratorOrName instanceof Hydrator\HydratorInterface) { $fieldset->setHydrator($hydratorOrName); return; } diff --git a/lib/Zend/Form/Form.php b/lib/Zend/Form/Form.php index 4f6a7b6c19..4b97f09813 100644 --- a/lib/Zend/Form/Form.php +++ b/lib/Zend/Form/Form.php @@ -272,7 +272,9 @@ public function setHydrator(HydratorInterface $hydrator) public function bindValues(array $values = array()) { if (!is_object($this->object)) { - return; + if ( $this->baseFieldset === null || $this->baseFieldset->allowValueBinding() == false ) { + return; + } } if (!$this->hasValidated() && !empty($values)) { $this->setData($values); @@ -343,9 +345,9 @@ public function setBindOnValidate($bindOnValidateFlag) throw new Exception\InvalidArgumentException(sprintf( '%s expects the flag to be one of %s::%s or %s::%s', __METHOD__, - get_called_class(), + get_class($this), 'BIND_ON_VALIDATE', - get_called_class(), + get_class($this), 'BIND_MANUAL' )); } diff --git a/lib/Zend/Form/View/Helper/FormDateTimeSelect.php b/lib/Zend/Form/View/Helper/FormDateTimeSelect.php index 0815caf701..b766ccbf40 100644 --- a/lib/Zend/Form/View/Helper/FormDateTimeSelect.php +++ b/lib/Zend/Form/View/Helper/FormDateTimeSelect.php @@ -51,8 +51,9 @@ public function render(ElementInterface $element) )); } + $shouldRenderDelimiters = $element->shouldRenderDelimiters(); $selectHelper = $this->getSelectElementHelper(); - $pattern = $this->parsePattern($element->shouldRenderDelimiters()); + $pattern = $this->parsePattern($shouldRenderDelimiters); $daysOptions = $this->getDaysOptions($pattern['day']); $monthsOptions = $this->getMonthsOptions($pattern['month']); @@ -78,16 +79,19 @@ public function render(ElementInterface $element) } $data = array(); - $data[$pattern['day']] = $selectHelper->render($dayElement); - $data[$pattern['month']] = $selectHelper->render($monthElement); - $data[$pattern['year']] = $selectHelper->render($yearElement); - $data[$pattern['hour']] = $selectHelper->render($hourElement); - $data[$pattern['minute']] = $selectHelper->render($minuteElement); + $data[$pattern['day']] = $selectHelper->render($dayElement); + $data[$pattern['month']] = $selectHelper->render($monthElement); + $data[$pattern['year']] = $selectHelper->render($yearElement); + $data[$pattern['hour']] = $selectHelper->render($hourElement); + $data[$pattern['minute']] = $selectHelper->render($minuteElement); if ($element->shouldShowSeconds()) { $data[$pattern['second']] = $selectHelper->render($secondElement); } else { unset($pattern['second']); + if ($shouldRenderDelimiters) { + unset($pattern[4]); + } } $markup = ''; @@ -99,6 +103,7 @@ public function render(ElementInterface $element) $markup .= $data[$value]; } } + $markup = trim($markup); return $markup; } @@ -200,6 +205,9 @@ protected function parsePattern($renderDelimiters = true) $result['minute'] = $value; } elseif (stripos($value, "'") === false && strpos($value, 's') !== false) { $result['second'] = $value; + } elseif (stripos($value, "'") === false && stripos($value, 'a') !== false) { + // ignore ante/post meridiem marker + continue; } elseif ($renderDelimiters) { $result[] = str_replace("'", '', $value); } diff --git a/lib/Zend/Form/View/Helper/FormMultiCheckbox.php b/lib/Zend/Form/View/Helper/FormMultiCheckbox.php index f41b3f30e7..e6ad8ee74c 100644 --- a/lib/Zend/Form/View/Helper/FormMultiCheckbox.php +++ b/lib/Zend/Form/View/Helper/FormMultiCheckbox.php @@ -257,10 +257,10 @@ protected function renderOptions(MultiCheckboxElement $element, array $options, $value = ''; $label = ''; - $selected = false; - $disabled = false; $inputAttributes = $attributes; $labelAttributes = $globalLabelAttributes; + $selected = isset($inputAttributes['selected']) && $inputAttributes['type'] != 'radio' && $inputAttributes['selected'] != false ? true : false; + $disabled = isset($inputAttributes['disabled']) && $inputAttributes['disabled'] != false ? true : false; if (is_scalar($optionSpec)) { $optionSpec = array( diff --git a/lib/Zend/Form/View/Helper/FormRow.php b/lib/Zend/Form/View/Helper/FormRow.php index 830737fb9d..43c787713f 100644 --- a/lib/Zend/Form/View/Helper/FormRow.php +++ b/lib/Zend/Form/View/Helper/FormRow.php @@ -162,6 +162,8 @@ public function __invoke(ElementInterface $element = null, $labelPosition = null if ($labelPosition !== null) { $this->setLabelPosition($labelPosition); + } else { + $this->setLabelPosition(self::LABEL_PREPEND); } if ($renderErrors !== null){ diff --git a/lib/Zend/Http/Client/Adapter/Curl.php b/lib/Zend/Http/Client/Adapter/Curl.php index d5becf8e08..2f0af52746 100644 --- a/lib/Zend/Http/Client/Adapter/Curl.php +++ b/lib/Zend/Http/Client/Adapter/Curl.php @@ -134,6 +134,9 @@ public function setOptions($options = array()) $this->setCurlOption(CURLOPT_PROXYPORT, $v); break; default: + if (is_array($v) && isset($this->config[$option]) && is_array($this->config[$option])) { + $v = ArrayUtils::merge($this->config[$option], $v); + } $this->config[$option] = $v; break; } diff --git a/lib/Zend/Http/Headers.php b/lib/Zend/Http/Headers.php index 38e543aba0..6843fe12a9 100644 --- a/lib/Zend/Http/Headers.php +++ b/lib/Zend/Http/Headers.php @@ -286,7 +286,7 @@ public function has($name) } /** - * Advance the pointer for this object as an interator + * Advance the pointer for this object as an iterator * * @return void */ diff --git a/lib/Zend/Http/PhpEnvironment/Request.php b/lib/Zend/Http/PhpEnvironment/Request.php index 38ee9a63c3..eefcaeea88 100644 --- a/lib/Zend/Http/PhpEnvironment/Request.php +++ b/lib/Zend/Http/PhpEnvironment/Request.php @@ -459,7 +459,6 @@ protected function detectRequestUri() * Uses a variety of criteria in order to detect the base URL of the request * (i.e., anything additional to the document root). * - * The base URL includes the schema, host, and port, in addition to the path. * * @return string */ diff --git a/lib/Zend/Http/Response.php b/lib/Zend/Http/Response.php index 8293042d7c..dc5d08885f 100644 --- a/lib/Zend/Http/Response.php +++ b/lib/Zend/Http/Response.php @@ -239,7 +239,7 @@ public function getCookie() */ public function setStatusCode($code) { - $const = get_called_class() . '::STATUS_CODE_' . $code; + $const = get_class($this) . '::STATUS_CODE_' . $code; if (!is_numeric($code) || !defined($const)) { $code = is_scalar($code) ? $code : gettype($code); throw new Exception\InvalidArgumentException(sprintf( diff --git a/lib/Zend/Http/Response/Stream.php b/lib/Zend/Http/Response/Stream.php index 990cadb22e..94c61e46cd 100644 --- a/lib/Zend/Http/Response/Stream.php +++ b/lib/Zend/Http/Response/Stream.php @@ -26,7 +26,7 @@ class Stream extends Response protected $contentLength = null; /** - * The portion of the body that has alredy been streamed + * The portion of the body that has already been streamed * * @var int */ diff --git a/lib/Zend/I18n/Exception/ExtensionNotLoadedException.php b/lib/Zend/I18n/Exception/ExtensionNotLoadedException.php new file mode 100644 index 0000000000..39bb5a9050 --- /dev/null +++ b/lib/Zend/I18n/Exception/ExtensionNotLoadedException.php @@ -0,0 +1,16 @@ +setOptions($allowWhiteSpaceOrOptions); diff --git a/lib/Zend/I18n/Filter/NumberFormat.php b/lib/Zend/I18n/Filter/NumberFormat.php index 21a82ddd0c..7c62679076 100644 --- a/lib/Zend/I18n/Filter/NumberFormat.php +++ b/lib/Zend/I18n/Filter/NumberFormat.php @@ -37,6 +37,7 @@ public function __construct( $style = NumberFormatter::DEFAULT_STYLE, $type = NumberFormatter::TYPE_DOUBLE) { + parent::__construct(); if ($localeOrOptions !== null) { if ($localeOrOptions instanceof Traversable) { $localeOrOptions = iterator_to_array($localeOrOptions); diff --git a/lib/Zend/I18n/Translator/Plural/Rule.php b/lib/Zend/I18n/Translator/Plural/Rule.php index 21b816e731..ffe3a66d79 100644 --- a/lib/Zend/I18n/Translator/Plural/Rule.php +++ b/lib/Zend/I18n/Translator/Plural/Rule.php @@ -71,6 +71,16 @@ public function evaluate($number) return $result; } + /** + * Get number of possible plural forms. + * + * @return integer + */ + public function getNumPlurals() + { + return $this->numPlurals; + } + /** * Evaluate a part of an ast. * diff --git a/lib/Zend/I18n/Translator/TextDomain.php b/lib/Zend/I18n/Translator/TextDomain.php index 47c710c208..e33b707979 100644 --- a/lib/Zend/I18n/Translator/TextDomain.php +++ b/lib/Zend/I18n/Translator/TextDomain.php @@ -10,6 +10,7 @@ namespace Zend\I18n\Translator; use ArrayObject; +use Zend\I18n\Exception; use Zend\I18n\Translator\Plural\Rule as PluralRule; /** @@ -46,9 +47,36 @@ public function setPluralRule(PluralRule $rule) public function getPluralRule() { if ($this->pluralRule === null) { - $this->setPluralRule(PluralRule::fromString('nplurals=2; plural=n==1')); + $this->setPluralRule(PluralRule::fromString('nplurals=2; plural=n != 1;')); } return $this->pluralRule; } + + /** + * Merge another text domain with the current one. + * + * The plural rule of both text domains must be compatible for a successful + * merge. We are only validating the number of plural forms though, as the + * same rule could be made up with different expression. + * + * @param TextDomain $textDomain + * @return TextDomain + * @throws Exception\RuntimeException + */ + public function merge(TextDomain $textDomain) + { + if ($this->getPluralRule()->getNumPlurals() !== $textDomain->getPluralRule()->getNumPlurals()) { + throw new Exception\RuntimeException('Plural rule of merging text domain is not compatible with the current one'); + } + + $this->exchangeArray( + array_replace( + $this->getArrayCopy(), + $textDomain->getArrayCopy() + ) + ); + + return $this; + } } diff --git a/lib/Zend/I18n/Translator/Translator.php b/lib/Zend/I18n/Translator/Translator.php index cfb22c9504..7623c27388 100644 --- a/lib/Zend/I18n/Translator/Translator.php +++ b/lib/Zend/I18n/Translator/Translator.php @@ -217,10 +217,17 @@ public function setLocale($locale) * Get the default locale. * * @return string + * @throws Exception\ExtensionNotLoadedException if ext/intl is not present and no locale set */ public function getLocale() { if ($this->locale === null) { + if (!extension_loaded('intl')) { + throw new Exception\ExtensionNotLoadedException(sprintf( + '%s component requires the intl PHP extension', + __NAMESPACE__ + )); + } $this->locale = Locale::getDefault(); } @@ -347,9 +354,9 @@ public function translatePlural( $locale = null ) { $locale = $locale ?: $this->getLocale(); - $translation = $this->getTranslatedMessage($singular, $locale, $textDomain, true); + $translation = $this->getTranslatedMessage($singular, $locale, $textDomain); - if ($translation === null || $translation['message'] === '') { + if ($translation === null || $translation === '') { if (null !== ($fallbackLocale = $this->getFallbackLocale()) && $locale !== $fallbackLocale ) { @@ -365,31 +372,31 @@ public function translatePlural( return ($number == 1 ? $singular : $plural); } - $index = $translation['plural_rule']->evaluate($number); + $index = $this->messages[$textDomain][$locale] + ->getPluralRule() + ->evaluate($number); - if (!isset($translation['message'][$index])) { + if (!isset($translation[$index])) { throw new Exception\OutOfBoundsException(sprintf( 'Provided index %d does not exist in plural array', $index )); } - return $translation['message'][$index]; + return $translation[$index]; } /** * Get a translated message. * - * @param string $message - * @param string $locale - * @param string $textDomain - * @param boolean $returnPluralRule + * @param string $message + * @param string $locale + * @param string $textDomain * @return string|null */ protected function getTranslatedMessage( $message, $locale = null, - $textDomain = 'default', - $returnPluralRule = false + $textDomain = 'default' ) { if ($message === '') { return ''; @@ -399,28 +406,8 @@ protected function getTranslatedMessage( $this->loadMessages($textDomain, $locale); } - if (is_array($this->messages[$textDomain][$locale])) { - foreach ($this->messages[$textDomain][$locale] as $textDomain) { - if (isset($textDomain[$message])) { - if ($returnPluralRule) { - return array( - 'message' => $textDomain[$message], - 'plural_rule' => $textDomain->getPluralRule() - ); - } else { - return $textDomain[$message]; - } - } - } - } elseif (isset($this->messages[$textDomain][$locale][$message])) { - if ($returnPluralRule) { - return array( - 'message' => $this->messages[$textDomain][$locale][$message], - 'plural_rule' => $this->messages[$textDomain][$locale]->getPluralRule() - ); - } else { - return $this->messages[$textDomain][$locale][$message]; - } + if (isset($this->messages[$textDomain][$locale][$message])) { + return $this->messages[$textDomain][$locale][$message]; } return null; @@ -525,13 +512,14 @@ protected function loadMessages($textDomain, $locale) } } - $messagesLoaded = ( - $this->loadMessagesFromRemote($textDomain, $locale) - || $this->loadMessagesFromPatterns($textDomain, $locale) - || $this->loadMessagesFromFiles($textDomain, $locale) - ); + $messagesLoaded = false; + $messagesLoaded |= $this->loadMessagesFromRemote($textDomain, $locale); + $messagesLoaded |= $this->loadMessagesFromPatterns($textDomain, $locale); + $messagesLoaded |= $this->loadMessagesFromFiles($textDomain, $locale); - if ($messagesLoaded && $cache !== null) { + if (!$messagesLoaded) { + $this->messages[$textDomain][$locale] = null; + } elseif ($cache !== null) { $cache->setItem($cacheId, $this->messages[$textDomain][$locale]); } } @@ -557,13 +545,7 @@ protected function loadMessagesFromRemote($textDomain, $locale) } if (isset($this->messages[$textDomain][$locale])) { - if (!is_array($this->messages[$textDomain][$locale])) { - $this->messages[$textDomain][$locale] = array( - $this->messages[$textDomain][$locale] - ); - } - - $this->messages[$textDomain][$locale][] = $loader->load($locale, $textDomain); + $this->messages[$textDomain][$locale]->merge($loader->load($locale, $textDomain)); } else { $this->messages[$textDomain][$locale] = $loader->load($locale, $textDomain); } @@ -599,13 +581,7 @@ protected function loadMessagesFromPatterns($textDomain, $locale) } if (isset($this->messages[$textDomain][$locale])) { - if (!is_array($this->messages[$textDomain][$locale])) { - $this->messages[$textDomain][$locale] = array( - $this->messages[$textDomain][$locale] - ); - } - - $this->messages[$textDomain][$locale][] = $loader->load($locale, $filename); + $this->messages[$textDomain][$locale]->merge($loader->load($locale, $filename)); } else { $this->messages[$textDomain][$locale] = $loader->load($locale, $filename); } @@ -643,13 +619,7 @@ protected function loadMessagesFromFiles($textDomain, $locale) } if (isset($this->messages[$textDomain][$locale])) { - if (!is_array($this->messages[$textDomain][$locale])) { - $this->messages[$textDomain][$locale] = array( - $this->messages[$textDomain][$locale] - ); - } - - $this->messages[$textDomain][$locale][] = $loader->load($locale, $file['filename']); + $this->messages[$textDomain][$locale]->merge($loader->load($locale, $file['filename'])); } else { $this->messages[$textDomain][$locale] = $loader->load($locale, $file['filename']); } diff --git a/lib/Zend/I18n/Validator/Float.php b/lib/Zend/I18n/Validator/Float.php index b1ae9131f1..dd1d4cd841 100644 --- a/lib/Zend/I18n/Validator/Float.php +++ b/lib/Zend/I18n/Validator/Float.php @@ -12,6 +12,7 @@ use Locale; use NumberFormatter; use Traversable; +use Zend\I18n\Exception as I18nException; use Zend\Stdlib\ArrayUtils; use Zend\Validator\AbstractValidator; use Zend\Validator\Exception; @@ -40,9 +41,17 @@ class Float extends AbstractValidator * Constructor for the integer validator * * @param array|Traversable $options + * @throws Exception\ExtensionNotLoadedException if ext/intl is not present */ public function __construct($options = array()) { + if (!extension_loaded('intl')) { + throw new I18nException\ExtensionNotLoadedException(sprintf( + '%s component requires the intl PHP extension', + __NAMESPACE__ + )); + } + if ($options instanceof Traversable) { $options = ArrayUtils::iteratorToArray($options); } diff --git a/lib/Zend/I18n/Validator/Int.php b/lib/Zend/I18n/Validator/Int.php index 968c881a2b..5ea1cf4a55 100644 --- a/lib/Zend/I18n/Validator/Int.php +++ b/lib/Zend/I18n/Validator/Int.php @@ -12,6 +12,7 @@ use Locale; use NumberFormatter; use Traversable; +use Zend\I18n\Exception as I18nException; use Zend\Stdlib\ArrayUtils; use Zend\Validator\AbstractValidator; use Zend\Validator\Exception; @@ -40,9 +41,17 @@ class Int extends AbstractValidator * Constructor for the integer validator * * @param array|Traversable $options + * @throws Exception\ExtensionNotLoadedException if ext/intl is not present */ public function __construct($options = array()) { + if (!extension_loaded('intl')) { + throw new I18nException\ExtensionNotLoadedException(sprintf( + '%s component requires the intl PHP extension', + __NAMESPACE__ + )); + } + if ($options instanceof Traversable) { $options = ArrayUtils::iteratorToArray($options); } diff --git a/lib/Zend/I18n/Validator/PostCode.php b/lib/Zend/I18n/Validator/PostCode.php index 36d777d3ca..4ad577e6b2 100644 --- a/lib/Zend/I18n/Validator/PostCode.php +++ b/lib/Zend/I18n/Validator/PostCode.php @@ -11,6 +11,7 @@ use Locale; use Traversable; +use Zend\I18n\Exception as I18nException; use Zend\Stdlib\ArrayUtils; use Zend\Validator\AbstractValidator; use Zend\Validator\Callback; @@ -226,9 +227,17 @@ class PostCode extends AbstractValidator * Accepts a string locale and/or "format". * * @param array|Traversable $options + * @throws Exception\ExtensionNotLoadedException if ext/intl is not present */ public function __construct($options = array()) { + if (!extension_loaded('intl')) { + throw new I18nException\ExtensionNotLoadedException(sprintf( + '%s component requires the intl PHP extension', + __NAMESPACE__ + )); + } + if ($options instanceof Traversable) { $options = ArrayUtils::iteratorToArray($options); } diff --git a/lib/Zend/I18n/View/Helper/AbstractTranslatorHelper.php b/lib/Zend/I18n/View/Helper/AbstractTranslatorHelper.php index 1a5bfd27d9..ec6faef15b 100644 --- a/lib/Zend/I18n/View/Helper/AbstractTranslatorHelper.php +++ b/lib/Zend/I18n/View/Helper/AbstractTranslatorHelper.php @@ -9,6 +9,7 @@ namespace Zend\I18n\View\Helper; +use Zend\I18n\Exception; use Zend\I18n\Translator\Translator; use Zend\I18n\Translator\TranslatorAwareInterface; use Zend\View\Helper\AbstractHelper; @@ -30,6 +31,26 @@ abstract class AbstractTranslatorHelper extends AbstractHelper implements */ protected $translatorTextDomain = 'default'; + /** + * @throws Exception\ExtensionsNotLoadedException if ext/intl is not present + */ + public function __construct() + { + /**#@+ + * Remove unnecessary dependency on Intl extension introduced in commit #751ce1895bd8b3fcbb28253a3a308842345318f4 + * Modified by Taiwen Jiang + */ + /* + if (!extension_loaded('intl')) { + throw new Exception\ExtensionNotLoadedException(sprintf( + '%s component requires the intl PHP extension', + __NAMESPACE__ + )); + } + */ + /**#@-*/ + } + /** * Whether translator should be used * diff --git a/lib/Zend/I18n/View/Helper/CurrencyFormat.php b/lib/Zend/I18n/View/Helper/CurrencyFormat.php index eee0a4dff9..255bbaf3c8 100644 --- a/lib/Zend/I18n/View/Helper/CurrencyFormat.php +++ b/lib/Zend/I18n/View/Helper/CurrencyFormat.php @@ -11,6 +11,7 @@ use Locale; use NumberFormatter; +use Zend\I18n\Exception; use Zend\View\Helper\AbstractHelper; /** @@ -46,6 +47,19 @@ class CurrencyFormat extends AbstractHelper */ protected $formatters = array(); + /** + * @throws Exception\ExtensionNotLoadedException if ext/intl is not present + */ + public function __construct() + { + if (!extension_loaded('intl')) { + throw new Exception\ExtensionNotLoadedException(sprintf( + '%s component requires the intl PHP extension', + __NAMESPACE__ + )); + } + } + /** * The 3-letter ISO 4217 currency code indicating the currency to use. * diff --git a/lib/Zend/I18n/View/Helper/DateFormat.php b/lib/Zend/I18n/View/Helper/DateFormat.php index 9ebb9ef39d..04caf02ccb 100644 --- a/lib/Zend/I18n/View/Helper/DateFormat.php +++ b/lib/Zend/I18n/View/Helper/DateFormat.php @@ -41,6 +41,19 @@ class DateFormat extends AbstractHelper */ protected $formatters = array(); + /** + * @throws Exception\ExtensionNotLoadedException if ext/intl is not present + */ + public function __construct() + { + if (!extension_loaded('intl')) { + throw new Exception\ExtensionNotLoadedException(sprintf( + '%s component requires the intl PHP extension', + __NAMESPACE__ + )); + } + } + /** * Set timezone to use instead of the default. * diff --git a/lib/Zend/I18n/View/Helper/NumberFormat.php b/lib/Zend/I18n/View/Helper/NumberFormat.php index 63b152995f..9658d5f244 100644 --- a/lib/Zend/I18n/View/Helper/NumberFormat.php +++ b/lib/Zend/I18n/View/Helper/NumberFormat.php @@ -11,6 +11,7 @@ use Locale; use NumberFormatter; +use Zend\I18n\Exception; use Zend\View\Helper\AbstractHelper; /** @@ -46,6 +47,19 @@ class NumberFormat extends AbstractHelper */ protected $formatters = array(); + /** + * @throws Exception\ExtensionNotLoadedException if ext/intl is not present + */ + public function __construct() + { + if (!extension_loaded('intl')) { + throw new Exception\ExtensionNotLoadedException(sprintf( + '%s component requires the intl PHP extension', + __NAMESPACE__ + )); + } + } + /** * Set format style to use instead of the default. * diff --git a/lib/Zend/I18n/View/Helper/Plural.php b/lib/Zend/I18n/View/Helper/Plural.php index a6fa185a72..4d567dba56 100644 --- a/lib/Zend/I18n/View/Helper/Plural.php +++ b/lib/Zend/I18n/View/Helper/Plural.php @@ -34,6 +34,19 @@ class Plural extends AbstractHelper */ protected $rule; + /** + * @throws Exception\ExtensionNotLoadedException if ext/intl is not present + */ + public function __construct() + { + if (!extension_loaded('intl')) { + throw new Exception\ExtensionNotLoadedException(sprintf( + '%s component requires the intl PHP extension', + __NAMESPACE__ + )); + } + } + /** * Set the plural rule to use * diff --git a/lib/Zend/I18n/composer.json b/lib/Zend/I18n/composer.json index cebe6537cd..87200f9989 100644 --- a/lib/Zend/I18n/composer.json +++ b/lib/Zend/I18n/composer.json @@ -14,10 +14,10 @@ "target-dir": "Zend/I18n", "require": { "php": ">=5.3.3", - "ext-intl": "*", "zendframework/zend-stdlib": "self.version" }, "suggest": { + "ext-intl": "Required for most features of Zend\\I18n; included in default builds of PHP", "zendframework/zend-filter": "You should install this package to use the provided filters", "zendframework/zend-validator": "You should install this package to use the provided validators", "zendframework/zend-view": "You should install this package to use the provided view helpers" diff --git a/lib/Zend/I18n/diff.txt b/lib/Zend/I18n/diff.txt new file mode 100644 index 0000000000..55ecbecba7 --- /dev/null +++ b/lib/Zend/I18n/diff.txt @@ -0,0 +1,2 @@ + +View/Helper/AbstractTranslatorHelper.php \ No newline at end of file diff --git a/lib/Zend/InputFilter/BaseInputFilter.php b/lib/Zend/InputFilter/BaseInputFilter.php index 319a9bc281..47560e4cb8 100644 --- a/lib/Zend/InputFilter/BaseInputFilter.php +++ b/lib/Zend/InputFilter/BaseInputFilter.php @@ -171,7 +171,10 @@ public function isValid() ) { if ($input instanceof InputInterface) { // - test if input is required - if (!$input->isRequired()) { + if (!$input->isRequired() + // "Not required" should not apply to empty strings (#3983) + && !(array_key_exists($name, $this->data) && is_string($this->data[$name])) + ) { $this->validInputs[$name] = $input; continue; } @@ -182,7 +185,7 @@ public function isValid() } } // make sure we have a value (empty) for validation - $this->data[$name] = ''; + $this->data[$name] = null; } if ($input instanceof InputFilterInterface) { diff --git a/lib/Zend/InputFilter/Factory.php b/lib/Zend/InputFilter/Factory.php index 31db2a7460..dddc6f5750 100644 --- a/lib/Zend/InputFilter/Factory.php +++ b/lib/Zend/InputFilter/Factory.php @@ -153,6 +153,9 @@ public function createInput($inputSpecification) $input->setRequired(!$value); } break; + case 'error_message': + $input->setErrorMessage($value); + break; case 'fallback_value': $input->setFallbackValue($value); break; @@ -264,11 +267,12 @@ protected function populateFilters(FilterChain $chain, $filters) ); } $name = $filter['name']; + $priority = isset($filter['priority']) ? $filter['priority'] : FilterChain::DEFAULT_PRIORITY; $options = array(); if (isset($filter['options'])) { $options = $filter['options']; } - $chain->attachByName($name, $options); + $chain->attachByName($name, $options, $priority); continue; } diff --git a/lib/Zend/Json/Decoder.php b/lib/Zend/Json/Decoder.php index af8b67e227..7783d8f7d2 100644 --- a/lib/Zend/Json/Decoder.php +++ b/lib/Zend/Json/Decoder.php @@ -80,7 +80,7 @@ class Decoder * * @param string $source String source to decode * @param int $decodeType How objects should be decoded -- see - * {@link Zend_Json::TYPE_ARRAY} and {@link Zend_Json::TYPE_OBJECT} for + * {@link Zend\Json\Json::TYPE_ARRAY} and {@link Zend\Json\Json::TYPE_OBJECT} for * valid values * @throws InvalidArgumentException * @return void @@ -120,15 +120,15 @@ protected function __construct($source, $decodeType) * - array of one or more of the above types * * By default, decoded objects will be returned as associative arrays; to - * return a stdClass object instead, pass {@link Zend_Json::TYPE_OBJECT} to + * return a stdClass object instead, pass {@link Zend\Json\Json::TYPE_OBJECT} to * the $objectDecodeType parameter. * * @static * @access public * @param string $source String to be decoded * @param int $objectDecodeType How objects should be decoded; should be - * either or {@link Zend_Json::TYPE_ARRAY} or - * {@link Zend_Json::TYPE_OBJECT}; defaults to TYPE_ARRAY + * either or {@link Zend\Json\Json::TYPE_ARRAY} or + * {@link Zend\Json\Json::TYPE_OBJECT}; defaults to TYPE_ARRAY * @return mixed */ public static function decode($source, $objectDecodeType = Json::TYPE_OBJECT) @@ -166,7 +166,7 @@ protected function _decodeValue() * Decodes an object of the form: * { "attribute: value, "attribute2" : value,...} * - * If Zend_Json_Encoder was used to encode the original object then + * If Zend\Json\Encoder was used to encode the original object then * a special attribute called __className which specifies a class * name that should wrap the data contained within the encoded source. * diff --git a/lib/Zend/Json/Expr.php b/lib/Zend/Json/Expr.php index 77377cfc16..0cd75a6091 100644 --- a/lib/Zend/Json/Expr.php +++ b/lib/Zend/Json/Expr.php @@ -10,10 +10,10 @@ namespace Zend\Json; /** - * Class for Zend_Json encode method. + * Class for Zend\Json\Json encode method. * * This class simply holds a string with a native Javascript Expression, - * so objects | arrays to be encoded with Zend_Json can contain native + * so objects | arrays to be encoded with Zend\Json\Json can contain native * Javascript Expressions. * * Example: @@ -21,14 +21,14 @@ * $foo = array( * 'integer' =>9, * 'string' =>'test string', - * 'function' => Zend_Json_Expr( - * 'function() { window.alert("javascript function encoded by Zend_Json") }' + * 'function' => Zend\Json\Expr( + * 'function() { window.alert("javascript function encoded by Zend\Json\Json") }' * ), * ); * - * Zend_Json::encode($foo, false, array('enableJsonExprFinder' => true)); + * Zend\Json\Json::encode($foo, false, array('enableJsonExprFinder' => true)); * // it will returns json encoded string: - * // {"integer":9,"string":"test string","function":function() {window.alert("javascript function encoded by Zend_Json")}} + * // {"integer":9,"string":"test string","function":function() {window.alert("javascript function encoded by Zend\Json\Json")}} *
*/ class Expr diff --git a/lib/Zend/Json/Json.php b/lib/Zend/Json/Json.php index db5c602e30..68a125f546 100644 --- a/lib/Zend/Json/Json.php +++ b/lib/Zend/Json/Json.php @@ -46,7 +46,7 @@ class Json * * @param string $encodedValue Encoded in JSON format * @param int $objectDecodeType Optional; flag indicating how to decode - * objects. See {@link Zend_Json_Decoder::decode()} for details. + * objects. See {@link Zend\Json\Decoder::decode()} for details. * @return mixed * @throws RuntimeException */ @@ -85,10 +85,10 @@ public static function decode($encodedValue, $objectDecodeType = self::TYPE_OBJE * * NOTE: Only public variables will be encoded * - * NOTE: Encoding native javascript expressions are possible using Zend_Json_Expr. + * NOTE: Encoding native javascript expressions are possible using Zend\Json\Expr. * You can enable this by setting $options['enableJsonExprFinder'] = true * - * @see Zend_Json_Expr + * @see Zend\Json\Expr * * @param mixed $valueToEncode * @param bool $cycleCheck Optional; whether or not to check for object recursion; off by default @@ -105,7 +105,7 @@ public static function encode($valueToEncode, $cycleCheck = false, $options = ar } } - // Pre-encoding look for Zend_Json_Expr objects and replacing by tmp ids + // Pre-encoding look for Zend\Json\Expr objects and replacing by tmp ids $javascriptExpressions = array(); if (isset($options['enableJsonExprFinder']) && ($options['enableJsonExprFinder'] == true) @@ -123,7 +123,7 @@ public static function encode($valueToEncode, $cycleCheck = false, $options = ar $encodedResult = Encoder::encode($valueToEncode, $cycleCheck, $options); } - //only do post-processing to revert back the Zend_Json_Expr if any. + //only do post-processing to revert back the Zend\Json\Expr if any. if (count($javascriptExpressions) > 0) { $count = count($javascriptExpressions); for ($i = 0; $i < $count; $i++) { @@ -143,9 +143,9 @@ public static function encode($valueToEncode, $cycleCheck = false, $options = ar } /** - * Check & Replace Zend_Json_Expr for tmp ids in the valueToEncode + * Check & Replace Zend\Json\Expr for tmp ids in the valueToEncode * - * Check if the value is a Zend_Json_Expr, and if replace its value + * Check if the value is a Zend\Json\Expr, and if replace its value * with a magic key and save the javascript expression in an array. * * NOTE this method is recursive. @@ -186,9 +186,9 @@ protected static function _recursiveJsonExprFinder( * Return the value of an XML attribute text or the text between * the XML tags * - * In order to allow Zend_Json_Expr from xml, we check if the node - * matches the pattern that try to detect if it is a new Zend_Json_Expr - * if it matches, we return a new Zend_Json_Expr instead of a text node + * In order to allow Zend\Json\Expr from xml, we check if the node + * matches the pattern that try to detect if it is a new Zend\Json\Expr + * if it matches, we return a new Zend\Json\Expr instead of a text node * * @param SimpleXMLElement $simpleXmlElementObject * @return Expr|string @@ -298,7 +298,7 @@ protected static function _processXml($simpleXmlElementObject, $ignoreXmlAttribu * calling a recursive (protected static) function in this class. Then, it * converts that PHP array into JSON by calling the "encode" static function. * - * NOTE: Encoding native javascript expressions via Zend_Json_Expr is not possible. + * NOTE: Encoding native javascript expressions via Zend\Json\Expr is not possible. * * @static * @access public @@ -323,7 +323,7 @@ public static function fromXml($xmlStringContents, $ignoreXmlAttributes = true) // Call the recursive function to convert the XML into a PHP array. $resultArray = static::_processXml($simpleXmlElementObject, $ignoreXmlAttributes); - // Convert the PHP array to JSON using Zend_Json encode method. + // Convert the PHP array to JSON using Zend\Json\Json encode method. // It is just that simple. $jsonStringOutput = static::encode($resultArray); return($jsonStringOutput); diff --git a/lib/Zend/Json/Server/Cache.php b/lib/Zend/Json/Server/Cache.php index af968e1341..1f2e0e4882 100644 --- a/lib/Zend/Json/Server/Cache.php +++ b/lib/Zend/Json/Server/Cache.php @@ -13,7 +13,7 @@ use Zend\Stdlib\ErrorHandler; /** - * Zend_Json_Server_Cache: cache Zend_Json_Server server definition and SMD + * Zend\Json\Server\Cache: cache Zend\Json\Server\Server server definition and SMD */ class Cache extends ServerCache { diff --git a/lib/Zend/Json/Server/Exception/HttpException.php b/lib/Zend/Json/Server/Exception/HttpException.php index c7d111fc1c..2e301ba2d3 100644 --- a/lib/Zend/Json/Server/Exception/HttpException.php +++ b/lib/Zend/Json/Server/Exception/HttpException.php @@ -10,7 +10,7 @@ namespace Zend\Json\Server\Exception; /** - * Thrown by Zend_Json_Server_Client when an HTTP error occurs during an + * Thrown by Zend\Json\Server\Client when an HTTP error occurs during an * JSON-RPC method call. */ class HttpException extends RuntimeException diff --git a/lib/Zend/Json/Server/Server.php b/lib/Zend/Json/Server/Server.php index 5993e229ef..85cf3278f5 100644 --- a/lib/Zend/Json/Server/Server.php +++ b/lib/Zend/Json/Server/Server.php @@ -497,7 +497,7 @@ protected function _handle() } $params = $request->getParams(); - $invocable = $this->table->getMethod($method); + $invokable = $this->table->getMethod($method); $serviceMap = $this->getServiceMap(); $service = $serviceMap->getService($method); $serviceParams = $service->getParams(); @@ -509,7 +509,7 @@ protected function _handle() //Make sure named parameters are passed in correct order if (is_string( key( $params ) )) { - $callback = $invocable->getCallback(); + $callback = $invokable->getCallback(); if ('function' == $callback->getType()) { $reflection = new ReflectionFunction( $callback->getFunction() ); } else { @@ -534,7 +534,7 @@ protected function _handle() } try { - $result = $this->_dispatch($invocable, $params); + $result = $this->_dispatch($invokable, $params); } catch (\Exception $e) { return $this->fault($e->getMessage(), $e->getCode(), $e); } diff --git a/lib/Zend/Loader/AutoloaderFactory.php b/lib/Zend/Loader/AutoloaderFactory.php index d9d71a1587..27ab200f3c 100644 --- a/lib/Zend/Loader/AutoloaderFactory.php +++ b/lib/Zend/Loader/AutoloaderFactory.php @@ -12,8 +12,6 @@ use ReflectionClass; use Traversable; -require_once __DIR__ . '/SplAutoloader.php'; - if (class_exists('Zend\Loader\AutoloaderFactory')) { return; } diff --git a/lib/Zend/Mail/Header/GenericHeader.php b/lib/Zend/Mail/Header/GenericHeader.php index 67834e932f..cc48385a67 100644 --- a/lib/Zend/Mail/Header/GenericHeader.php +++ b/lib/Zend/Mail/Header/GenericHeader.php @@ -76,9 +76,9 @@ public function setFieldName($fieldName) $fieldName = str_replace(' ', '-', ucwords(str_replace(array('_', '-'), ' ', $fieldName))); // Validate what we have - if (!preg_match('/^[a-z][a-z0-9-]*$/i', $fieldName)) { + if (!preg_match('/^[\x21-\x39\x3B-\x7E]*$/i', $fieldName)) { throw new Exception\InvalidArgumentException( - 'Header name must start with a letter, and consist of only letters, numbers and dashes.' + 'Header name must be composed of printable US-ASCII characters, except colon.' ); } diff --git a/lib/Zend/Mail/Headers.php b/lib/Zend/Mail/Headers.php index d62c754442..8e644edd62 100644 --- a/lib/Zend/Mail/Headers.php +++ b/lib/Zend/Mail/Headers.php @@ -70,7 +70,7 @@ public static function fromString($string, $EOL = self::EOL) // iterate the header lines, some might be continuations foreach (explode($EOL, $string) as $line) { // check if a header name is present - if (preg_match('/^(?P[^()><@,;:\"\\/\[\]?=}{ \t]+):.*$/', $line, $matches)) { + if (preg_match('/^(?P[\x21-\x39\x3B-\x7E]+):.*$/', $line, $matches)) { if ($currentLine) { // a header name was present, then store the current complete line $headers->addHeaderLine($currentLine); diff --git a/lib/Zend/Math/composer.json b/lib/Zend/Math/composer.json index 495b59fe57..9b2896060c 100644 --- a/lib/Zend/Math/composer.json +++ b/lib/Zend/Math/composer.json @@ -17,7 +17,7 @@ }, "suggest": { "ircmaxell/random-lib": "Fallback random byte generator for Zend\\Math\\Rand if OpenSSL/Mcrypt extensions are unavailable" - } + }, "extra": { "branch-alias": { "dev-master": "2.1-dev", diff --git a/lib/Zend/ModuleManager/ModuleManager.php b/lib/Zend/ModuleManager/ModuleManager.php index 92d0cb90cb..6f68f5e146 100644 --- a/lib/Zend/ModuleManager/ModuleManager.php +++ b/lib/Zend/ModuleManager/ModuleManager.php @@ -245,7 +245,7 @@ public function setEventManager(EventManagerInterface $events) { $events->setIdentifiers(array( __CLASS__, - get_called_class(), + get_class($this), 'module_manager', )); $this->events = $events; diff --git a/lib/Zend/Mvc/Application.php b/lib/Zend/Mvc/Application.php index 7d42a84961..80cdf3d3d0 100644 --- a/lib/Zend/Mvc/Application.php +++ b/lib/Zend/Mvc/Application.php @@ -193,7 +193,7 @@ public function setEventManager(EventManagerInterface $eventManager) { $eventManager->setIdentifiers(array( __CLASS__, - get_called_class(), + get_class($this), )); $this->events = $eventManager; return $this; diff --git a/lib/Zend/Mvc/Controller/AbstractController.php b/lib/Zend/Mvc/Controller/AbstractController.php index a8275b5a13..aa4902c103 100644 --- a/lib/Zend/Mvc/Controller/AbstractController.php +++ b/lib/Zend/Mvc/Controller/AbstractController.php @@ -29,8 +29,8 @@ * Convenience methods for pre-built plugins (@see __call): * * @method \Zend\View\Model\ModelInterface acceptableViewModelSelector(array $matchAgainst = null, bool $returnDefault = true, \Zend\Http\Header\Accept\FieldValuePart\AbstractFieldValuePart $resultReference = null) - * @method boolean|array|\Zend\Http\Response fileprg(\Zend\Form\Form $form, $redirect = null, $redirectToUrl = false) - * @method boolean|array|\Zend\Http\Response filePostRedirectGet(\Zend\Form\Form $form, $redirect = null, $redirectToUrl = false) + * @method bool|array|\Zend\Http\Response fileprg(\Zend\Form\Form $form, $redirect = null, $redirectToUrl = false) + * @method bool|array|\Zend\Http\Response filePostRedirectGet(\Zend\Form\Form $form, $redirect = null, $redirectToUrl = false) * @method \Zend\Mvc\Controller\Plugin\FlashMessenger flashMessenger() * @method \Zend\Mvc\Controller\Plugin\Forward forward() * @method mixed|null identity() @@ -162,9 +162,9 @@ public function setEventManager(EventManagerInterface $events) $events->setIdentifiers(array( 'Zend\Stdlib\DispatchableInterface', __CLASS__, - get_called_class(), + get_class($this), $this->eventIdentifier, - substr(get_called_class(), 0, strpos(get_called_class(), '\\')) + substr(get_class($this), 0, strpos(get_class($this), '\\')) )); $this->events = $events; $this->attachDefaultListeners(); diff --git a/lib/Zend/Mvc/Controller/AbstractRestfulController.php b/lib/Zend/Mvc/Controller/AbstractRestfulController.php index dfffcfeb17..75ee82440a 100644 --- a/lib/Zend/Mvc/Controller/AbstractRestfulController.php +++ b/lib/Zend/Mvc/Controller/AbstractRestfulController.php @@ -361,7 +361,7 @@ public function processPostData(Request $request) * * @param Request $request * @param string|null $contentType - * @return boolean + * @return bool */ public function requestHasContentType(Request $request, $contentType = '') { @@ -431,7 +431,7 @@ public function addHttpMethodHandler($method, /* Callable */ $handler) * Retrieve the identifier, if any * * Attempts to see if an identifier was passed in either the URI or the - * query string, returning if if found. Otherwise, returns a boolean false. + * query string, returning it if found. Otherwise, returns a boolean false. * * @param \Zend\Mvc\Router\RouteMatch $routeMatch * @param Request $request diff --git a/lib/Zend/Mvc/Controller/ControllerManager.php b/lib/Zend/Mvc/Controller/ControllerManager.php index 563551b8e6..3e1d1e6248 100644 --- a/lib/Zend/Mvc/Controller/ControllerManager.php +++ b/lib/Zend/Mvc/Controller/ControllerManager.php @@ -108,7 +108,20 @@ public function validatePlugin($plugin) } /** - * Override: do not use peering service manager to retrieve controller + * Override: do not use peering service managers + * + * @param string|array $name + * @param bool $checkAbstractFactories + * @param bool $usePeeringServiceManagers + * @return bool + */ + public function has($name, $checkAbstractFactories = true, $usePeeringServiceManagers = false) + { + return parent::has($name, $checkAbstractFactories, $usePeeringServiceManagers); + } + + /** + * Override: do not use peering service managers * * @param string $name * @param array $options diff --git a/lib/Zend/Mvc/Controller/Plugin/FilePostRedirectGet.php b/lib/Zend/Mvc/Controller/Plugin/FilePostRedirectGet.php index 521c22538e..10ea5f1233 100644 --- a/lib/Zend/Mvc/Controller/Plugin/FilePostRedirectGet.php +++ b/lib/Zend/Mvc/Controller/Plugin/FilePostRedirectGet.php @@ -39,8 +39,8 @@ class FilePostRedirectGet extends AbstractPlugin /** * @param FormInterface $form * @param string $redirect Route or URL string (default: current route) - * @param boolean $redirectToUrl Use $redirect as a URL string (default: false) - * @return boolean|array|Response + * @param bool $redirectToUrl Use $redirect as a URL string (default: false) + * @return bool|array|Response */ public function __invoke(FormInterface $form, $redirect = null, $redirectToUrl = false) { @@ -55,7 +55,7 @@ public function __invoke(FormInterface $form, $redirect = null, $redirectToUrl = /** * @param FormInterface $form * @param string $redirect Route or URL string (default: current route) - * @param boolean $redirectToUrl Use $redirect as a URL string (default: false) + * @param bool $redirectToUrl Use $redirect as a URL string (default: false) * @return Response */ protected function handlePostRequest(FormInterface $form, $redirect, $redirectToUrl) @@ -109,7 +109,7 @@ function($input, $value) { /** * @param FormInterface $form - * @return boolean|array + * @return bool|array */ protected function handleGetRequest(FormInterface $form) { @@ -288,7 +288,7 @@ function($input, $value) { * TODO: Good candidate for traits method in PHP 5.4 with PostRedirectGet plugin * * @param string $redirect - * @param boolean $redirectToUrl + * @param bool $redirectToUrl * @return Response * @throws \Zend\Mvc\Exception\RuntimeException */ diff --git a/lib/Zend/Mvc/Controller/Plugin/FlashMessenger.php b/lib/Zend/Mvc/Controller/Plugin/FlashMessenger.php index 85bbd820f2..c1058813e8 100644 --- a/lib/Zend/Mvc/Controller/Plugin/FlashMessenger.php +++ b/lib/Zend/Mvc/Controller/Plugin/FlashMessenger.php @@ -235,7 +235,7 @@ public function hasMessages() /** * Whether "info" namespace has messages * - * @return boolean + * @return bool */ public function hasInfoMessages() { @@ -250,7 +250,7 @@ public function hasInfoMessages() /** * Whether "success" namespace has messages * - * @return boolean + * @return bool */ public function hasSuccessMessages() { @@ -265,7 +265,7 @@ public function hasSuccessMessages() /** * Whether "error" namespace has messages * - * @return boolean + * @return bool */ public function hasErrorMessages() { @@ -356,7 +356,7 @@ public function clearMessages() * Clear all messages from specific namespace * * @param string $namespaceToClear - * @return boolean True if messages were cleared, false if none existed + * @return bool True if messages were cleared, false if none existed */ public function clearMessagesFromNamespace($namespaceToClear) { @@ -371,7 +371,7 @@ public function clearMessagesFromNamespace($namespaceToClear) /** * Clear all messages from the container * - * @return boolean True if messages were cleared, false if none existed + * @return bool True if messages were cleared, false if none existed */ public function clearMessagesFromContainer() { @@ -403,7 +403,7 @@ public function hasCurrentMessages() * Check to see if messages have been added to "info" * namespace within this request * - * @return boolean + * @return bool */ public function hasCurrentInfoMessages() { @@ -419,7 +419,7 @@ public function hasCurrentInfoMessages() * Check to see if messages have been added to "success" * namespace within this request * - * @return boolean + * @return bool */ public function hasCurrentSuccessMessages() { @@ -435,7 +435,7 @@ public function hasCurrentSuccessMessages() * Check to see if messages have been added to "error" * namespace within this request * - * @return boolean + * @return bool */ public function hasCurrentErrorMessages() { @@ -533,7 +533,7 @@ public function getCurrentMessagesFromNamespace($namespaceToGet) /** * Clear messages from the current request and current namespace * - * @return bool + * @return bool True if current messages were cleared, false if none existed. */ public function clearCurrentMessages() { @@ -552,7 +552,7 @@ public function clearCurrentMessages() * Clear messages from the current namespace * * @param string $namespaceToClear - * @return boolean + * @return bool True if current messages were cleared from the given namespace, false if none existed. */ public function clearCurrentMessagesFromNamespace($namespaceToClear) { @@ -567,7 +567,7 @@ public function clearCurrentMessagesFromNamespace($namespaceToClear) /** * Clear messages from the container * - * @return boolean + * @return bool True if current messages were cleared from the container, false if none existed. */ public function clearCurrentMessagesFromContainer() { diff --git a/lib/Zend/Mvc/Controller/Plugin/PostRedirectGet.php b/lib/Zend/Mvc/Controller/Plugin/PostRedirectGet.php index ce038a4753..9d178fe55c 100644 --- a/lib/Zend/Mvc/Controller/Plugin/PostRedirectGet.php +++ b/lib/Zend/Mvc/Controller/Plugin/PostRedirectGet.php @@ -38,7 +38,7 @@ class PostRedirectGet extends AbstractPlugin * boolean false. * * @param null|string $redirect - * @param bool $redirectToUrl + * @param bool $redirectToUrl * @return \Zend\Http\Response|array|\Traversable|false */ public function __invoke($redirect = null, $redirectToUrl = false) @@ -87,7 +87,7 @@ public function setSessionContainer(Container $container) * TODO: Good candidate for traits method in PHP 5.4 with FilePostRedirectGet plugin * * @param string $redirect - * @param boolean $redirectToUrl + * @param bool $redirectToUrl * @return \Zend\Http\Response * @throws \Zend\Mvc\Exception\RuntimeException */ diff --git a/lib/Zend/Mvc/Controller/Plugin/Redirect.php b/lib/Zend/Mvc/Controller/Plugin/Redirect.php index 044d83c239..885bac4b00 100644 --- a/lib/Zend/Mvc/Controller/Plugin/Redirect.php +++ b/lib/Zend/Mvc/Controller/Plugin/Redirect.php @@ -68,7 +68,7 @@ public function toUrl($url) /** * Refresh to current route * - * @return string + * @return Response */ public function refresh() { diff --git a/lib/Zend/Mvc/Router/Console/Simple.php b/lib/Zend/Mvc/Router/Console/Simple.php index efa7e3867c..597bfb671e 100644 --- a/lib/Zend/Mvc/Router/Console/Simple.php +++ b/lib/Zend/Mvc/Router/Console/Simple.php @@ -203,7 +203,7 @@ protected function parseRouteDefinition($def) * --param= * --param=whatever */ - if (preg_match('/\G--(?[a-zA-Z0-9][a-zA-Z0-9\_\-]+)(?=\S*?)?(?: +|$)/s', $def, $m, 0, $pos)) { + if (preg_match('/\G--(?P[a-zA-Z0-9][a-zA-Z0-9\_\-]+)(?P=\S*?)?(?: +|$)/s', $def, $m, 0, $pos)) { $item = array( 'name' => $m['name'], 'short' => false, @@ -218,7 +218,7 @@ protected function parseRouteDefinition($def) * [--param] */ elseif (preg_match( - '/\G\[ *?--(?[a-zA-Z0-9][a-zA-Z0-9\_\-]+) *?\](?: +|$)/s', $def, $m, 0, $pos + '/\G\[ *?--(?P[a-zA-Z0-9][a-zA-Z0-9\_\-]+) *?\](?: +|$)/s', $def, $m, 0, $pos )) { $item = array( 'name' => $m['name'], @@ -235,7 +235,7 @@ protected function parseRouteDefinition($def) * [--param=whatever] */ elseif (preg_match( - '/\G\[ *?--(?[a-zA-Z0-9][a-zA-Z0-9\_\-]+)(?=\S*?)? *?\](?: +|$)/s', $def, $m, 0, $pos + '/\G\[ *?--(?P[a-zA-Z0-9][a-zA-Z0-9\_\-]+)(?P=\S*?)? *?\](?: +|$)/s', $def, $m, 0, $pos )) { $item = array( 'name' => $m['name'], @@ -253,7 +253,7 @@ protected function parseRouteDefinition($def) * -a=s * -a=w */ - elseif (preg_match('/\G-(?[a-zA-Z0-9])(?:=(?[ns]))?(?: +|$)/s', $def, $m, 0, $pos)) { + elseif (preg_match('/\G-(?P[a-zA-Z0-9])(?:=(?P[ns]))?(?: +|$)/s', $def, $m, 0, $pos)) { $item = array( 'name' => $m['name'], 'short' => true, @@ -269,7 +269,7 @@ protected function parseRouteDefinition($def) * [-a=n] * [-a=s] */ - elseif (preg_match('/\G\[ *?-(?[a-zA-Z0-9])(?:=(?[ns]))? *?\](?: +|$)/s', $def, $m, 0, $pos)) { + elseif (preg_match('/\G\[ *?-(?P[a-zA-Z0-9])(?:=(?P[ns]))? *?\](?: +|$)/s', $def, $m, 0, $pos)) { $item = array( 'name' => $m['name'], 'short' => true, @@ -287,17 +287,17 @@ protected function parseRouteDefinition($def) elseif (preg_match('/ \G \[ - (? + (?P (?: \ *? - (?[a-z0-9][a-zA-Z0-9_]*?) + (?P[a-z0-9][a-zA-Z0-9_\-]*?) \ *? (?:\||(?=\])) \ *? )+ ) \] - (?:\:(?[a-zA-Z0-9]+))? + (?:\:(?P[a-zA-Z0-9]+))? (?:\ +|$) /sx', $def, $m, 0, $pos ) @@ -327,17 +327,17 @@ protected function parseRouteDefinition($def) elseif (preg_match('/ \G \( - (? + (?P (?: \ *? - (?[a-z0-9][a-zA-Z0-9_]+) + (?P[a-z0-9][a-zA-Z0-9_\-]+) \ *? (?:\||(?=\))) \ *? )+ ) \) - (?:\:(?[a-zA-Z0-9]+))? + (?:\:(?P[a-zA-Z0-9]+))? (?:\ +|$) /sx', $def, $m, 0, $pos )) { @@ -365,17 +365,17 @@ protected function parseRouteDefinition($def) elseif (preg_match('/ \G \( - (? + (?P (?: \ *? - \-+(?[a-zA-Z0-9][a-zA-Z0-9_\-]*?) + \-+(?P[a-zA-Z0-9][a-zA-Z0-9_\-]*?) \ *? (?:\||(?=\))) \ *? )+ ) \) - (?:\:(?[a-zA-Z0-9]+))? + (?:\:(?P[a-zA-Z0-9]+))? (?:\ +|$) /sx', $def, $m, 0, $pos )) { @@ -408,17 +408,17 @@ protected function parseRouteDefinition($def) elseif (preg_match('/ \G \[ - (? + (?P (?: \ *? - \-+(?[a-zA-Z0-9][a-zA-Z0-9_\-]*?) + \-+(?P[a-zA-Z0-9][a-zA-Z0-9_\-]*?) \ *? (?:\||(?=\])) \ *? )+ ) \] - (?:\:(?[a-zA-Z0-9]+))? + (?:\:(?P[a-zA-Z0-9]+))? (?:\ +|$) /sx', $def, $m, 0, $pos )) { @@ -447,7 +447,7 @@ protected function parseRouteDefinition($def) * Optional literal param, i.e. * [something] */ - elseif (preg_match('/\G\[ *?(?[a-z0-9][a-zA-Z0-9\_]*?) *?\](?: +|$)/s', $def, $m, 0, $pos)) { + elseif (preg_match('/\G\[ *?(?P[a-z0-9][a-zA-Z0-9\_\-]*?) *?\](?: +|$)/s', $def, $m, 0, $pos)) { $item = array( 'name' => $m['name'], 'literal' => true, @@ -460,7 +460,7 @@ protected function parseRouteDefinition($def) * Optional value param, i.e. * [SOMETHING] */ - elseif (preg_match('/\G\[(?[A-Z0-9\_]+)\](?: +|$)/s', $def, $m, 0, $pos)) { + elseif (preg_match('/\G\[(?P[a-z0-9][a-zA-Z0-9\_\-]*?)\](?: +|$)/s', $def, $m, 0, $pos)) { $item = array( 'name' => strtolower( $m['name'] ), 'literal' => false, @@ -473,7 +473,7 @@ protected function parseRouteDefinition($def) * Optional value param, syntax 2, i.e. * [] */ - elseif (preg_match('/\G\[ *\<(?[a-zA-Z0-9\_]+)\> *\](?: +|$)/s', $def, $m, 0, $pos)) { + elseif (preg_match('/\G\[ *\<(?P[a-z0-9][a-zA-Z0-9\_\-]*?)\> *\](?: +|$)/s', $def, $m, 0, $pos)) { $item = array( 'name' => strtolower( $m['name'] ), 'literal' => false, @@ -486,7 +486,7 @@ protected function parseRouteDefinition($def) * Mandatory value param, i.e. * */ - elseif (preg_match('/\G\< *(?[a-zA-Z0-9\_]+) *\>(?: +|$)/s', $def, $m, 0, $pos)) { + elseif (preg_match('/\G\< *(?P[a-z0-9][a-zA-Z0-9\_\-]*?) *\>(?: +|$)/s', $def, $m, 0, $pos)) { $item = array( 'name' => $m['name'], 'literal' => false, @@ -499,7 +499,7 @@ protected function parseRouteDefinition($def) * Mandatory value param, i.e. * SOMETHING */ - elseif (preg_match('/\G(?[A-Z0-9\_]*?)(?: +|$)/s', $def, $m, 0, $pos)) { + elseif (preg_match('/\G(?P[A-Z][a-zA-Z0-9\_\-]*?)(?: +|$)/s', $def, $m, 0, $pos)) { $item = array( 'name' => strtolower( $m['name'] ), 'literal' => false, @@ -512,7 +512,7 @@ protected function parseRouteDefinition($def) * Mandatory literal param, i.e. * something */ - elseif (preg_match('/\G(?[a-z0-9][a-zA-Z0-9\_]*?)(?: +|$)/s', $def, $m, 0, $pos)) { + elseif (preg_match('/\G(?P[a-z0-9][a-zA-Z0-9\_\-]*?)(?: +|$)/s', $def, $m, 0, $pos)) { $item = array( 'name' => $m['name'], 'literal' => true, @@ -573,11 +573,11 @@ public function match(Request $request, $pathOffset = null) */ if (isset($part['alternatives'])) { // an alternative of flags - $regex = '/^\-+(?'; + $regex = '/^\-+(?P'; $regex .= join('|', $part['alternatives']); if ($part['hasValue']) { - $regex .= ')(?:\=(?.*?)$)?$/'; + $regex .= ')(?:\=(?P.*?)$)?$/'; } else { $regex .= ')$/i'; } @@ -586,14 +586,14 @@ public function match(Request $request, $pathOffset = null) if ($part['short'] === true) { // short variant if ($part['hasValue']) { - $regex = '/^\-' . $part['name'] . '(?:\=(?.*?)$)?$/i'; + $regex = '/^\-' . $part['name'] . '(?:\=(?P.*?)$)?$/i'; } else { $regex = '/^\-' . $part['name'] . '$/i'; } } elseif ($part['short'] === false) { // long variant if ($part['hasValue']) { - $regex = '/^\-{2,}' . $part['name'] . '(?:\=(?.*?)$)?$/i'; + $regex = '/^\-{2,}' . $part['name'] . '(?:\=(?P.*?)$)?$/i'; } else { $regex = '/^\-{2,}' . $part['name'] . '$/i'; } @@ -692,17 +692,17 @@ public function match(Request $request, $pathOffset = null) if (isset($part['alternatives'])) { if ($part['hasValue']) { foreach ($part['alternatives'] as $alt) { - if ($alt == $matchedName) { + if ($alt === $matchedName && !isset($matches[$alt])) { $matches[$alt] = $value; - } else { + } elseif (!isset($matches[$alt])) { $matches[$alt] = null; } } } else { foreach ($part['alternatives'] as $alt) { - if ($alt == $matchedName) { + if ($alt === $matchedName && !isset($matches[$alt])) { $matches[$alt] = true; - } else { + } elseif (!isset($matches[$alt])) { $matches[$alt] = false; } } @@ -797,7 +797,7 @@ public function match(Request $request, $pathOffset = null) return null; // there are extraneous params that were not consumed } - return new RouteMatch(array_merge($this->defaults, $matches)); + return new RouteMatch(array_replace($matches, $this->defaults)); } /** diff --git a/lib/Zend/Mvc/Router/Http/Part.php b/lib/Zend/Mvc/Router/Http/Part.php index 1f66a83f58..dea1fb3324 100644 --- a/lib/Zend/Mvc/Router/Http/Part.php +++ b/lib/Zend/Mvc/Router/Http/Part.php @@ -166,7 +166,7 @@ public function match(Request $request, $pathOffset = null) */ public function assemble(array $params = array(), array $options = array()) { - if ($this->childRoutes !== null) { + if ($this->childRoutes !== null) { $this->addRoutes($this->childRoutes); $this->childRoutes = null; } diff --git a/lib/Zend/Mvc/Router/Http/TreeRouteStack.php b/lib/Zend/Mvc/Router/Http/TreeRouteStack.php index 7496176d6d..5eaec557a7 100644 --- a/lib/Zend/Mvc/Router/Http/TreeRouteStack.php +++ b/lib/Zend/Mvc/Router/Http/TreeRouteStack.php @@ -188,6 +188,9 @@ public function assemble(array $params = array(), array $options = array()) } if (isset($names[1])) { + if (!$route instanceof TreeRouteStack) { + throw new Exception\RuntimeException(sprintf('Route with name "%s" does not have child routes', $names[0])); + } $options['name'] = $names[1]; } else { unset($options['name']); diff --git a/lib/Zend/Mvc/Router/SimpleRouteStack.php b/lib/Zend/Mvc/Router/SimpleRouteStack.php index 08625c81fb..8b6861b8ad 100644 --- a/lib/Zend/Mvc/Router/SimpleRouteStack.php +++ b/lib/Zend/Mvc/Router/SimpleRouteStack.php @@ -205,8 +205,8 @@ public function getRoutes() /** * Check if a route with a specific name exists * - * @param string $name - * @return boolean true if route exists + * @param string $name + * @return bool true if route exists */ public function hasRoute($name) { diff --git a/lib/Zend/Mvc/SendResponseListener.php b/lib/Zend/Mvc/SendResponseListener.php index e91476e872..3d577cc66c 100644 --- a/lib/Zend/Mvc/SendResponseListener.php +++ b/lib/Zend/Mvc/SendResponseListener.php @@ -50,7 +50,7 @@ public function setEventManager(EventManagerInterface $eventManager) { $eventManager->setIdentifiers(array( __CLASS__, - get_called_class(), + get_class($this), )); $this->eventManager = $eventManager; $this->attachDefaultListeners(); diff --git a/lib/Zend/Mvc/Service/ConsoleAdapterFactory.php b/lib/Zend/Mvc/Service/ConsoleAdapterFactory.php index 8d5fd7f8f3..57834defb5 100644 --- a/lib/Zend/Mvc/Service/ConsoleAdapterFactory.php +++ b/lib/Zend/Mvc/Service/ConsoleAdapterFactory.php @@ -29,7 +29,7 @@ class ConsoleAdapterFactory implements FactoryInterface * 'charset' => 'MyConsoleCharset', // always use this console charset * ), * 'service_manager' => array( - * 'invocables' => array( + * 'invokables' => array( * 'MyConsoleAdapter' => 'Zend\Console\Adapter\Windows', * 'MyConsoleCharset' => 'Zend\Console\Charset\DESCG', * ) diff --git a/lib/Zend/Mvc/Service/DiAbstractServiceFactoryFactory.php b/lib/Zend/Mvc/Service/DiAbstractServiceFactoryFactory.php index 1af683f33d..b10813cacd 100644 --- a/lib/Zend/Mvc/Service/DiAbstractServiceFactoryFactory.php +++ b/lib/Zend/Mvc/Service/DiAbstractServiceFactoryFactory.php @@ -17,10 +17,10 @@ class DiAbstractServiceFactoryFactory implements FactoryInterface { /** - * Class responsible for instantiating a DiStrictAbstractServiceFactory + * Class responsible for instantiating a DiAbstractServiceFactory * * @param ServiceLocatorInterface $serviceLocator - * @return DiStrictAbstractServiceFactory + * @return DiAbstractServiceFactory */ public function createService(ServiceLocatorInterface $serviceLocator) { diff --git a/lib/Zend/Mvc/View/Console/RouteNotFoundStrategy.php b/lib/Zend/Mvc/View/Console/RouteNotFoundStrategy.php index 58cf48f2ed..fc100fe234 100644 --- a/lib/Zend/Mvc/View/Console/RouteNotFoundStrategy.php +++ b/lib/Zend/Mvc/View/Console/RouteNotFoundStrategy.php @@ -221,7 +221,14 @@ protected function getConsoleBanner(ConsoleAdapter $console, ModuleManagerInterf continue; // this module does not provide a banner } - $banners[] = $module->getConsoleBanner($console); + // Don't render empty completely empty lines + $banner = $module->getConsoleBanner($console); + if ($banner == '') { + continue; + } + + // We colorize each banners in blue for visual emphasis + $banners[] = $console->colorize($banner, ColorInterface::BLUE); } } @@ -267,13 +274,24 @@ protected function getConsoleUsage( continue; // this module does not provide usage info } + // We prepend the usage by the module name (printed in red), so that each module is + // clearly visible by the user + $moduleName = sprintf("%s\n%s\n%s\n", + str_repeat('-', $console->getWidth()), + $name, + str_repeat('-', $console->getWidth()) + ); + + $moduleName = $console->colorize($moduleName, ColorInterface::RED); + $usage = $module->getConsoleUsage($console); // Normalize what we got from the module or discard - if (is_array($usage)) { + if (is_array($usage) && !empty($usage)) { + array_unshift($usage, $moduleName); $usageInfo[$name] = $usage; - } elseif (is_string($usage)) { - $usageInfo[$name] = array($usage); + } elseif (is_string($usage) && ($usage != '')) { + $usageInfo[$name] = array($moduleName, $usage); } } } diff --git a/lib/Zend/Mvc/composer.json b/lib/Zend/Mvc/composer.json index 0020728a7e..05b078e377 100644 --- a/lib/Zend/Mvc/composer.json +++ b/lib/Zend/Mvc/composer.json @@ -14,6 +14,7 @@ "target-dir": "Zend/Mvc", "require": { "php": ">=5.3.3", + "zendframework/zend-config": "self.version", "zendframework/zend-console": "self.version", "zendframework/zend-di": "self.version", "zendframework/zend-eventmanager": "self.version", diff --git a/lib/Zend/Navigation/AbstractContainer.php b/lib/Zend/Navigation/AbstractContainer.php index cfde1f8019..56a250eaad 100644 --- a/lib/Zend/Navigation/AbstractContainer.php +++ b/lib/Zend/Navigation/AbstractContainer.php @@ -353,7 +353,7 @@ public function __call($method, $arguments) if (!$result) { throw new Exception\BadMethodCallException(sprintf( 'Bad method call: Unknown method %s::%s', - get_called_class(), + get_class($this), $method ), 0, $error); } diff --git a/lib/Zend/Navigation/Page/AbstractPage.php b/lib/Zend/Navigation/Page/AbstractPage.php index be77ffb236..51b4919c0e 100644 --- a/lib/Zend/Navigation/Page/AbstractPage.php +++ b/lib/Zend/Navigation/Page/AbstractPage.php @@ -1151,7 +1151,7 @@ public function toArray() 'privilege' => $this->getPrivilege(), 'active' => $this->isActive(), 'visible' => $this->isVisible(), - 'type' => get_called_class(), + 'type' => get_class($this), 'pages' => parent::toArray(), )); } diff --git a/lib/Zend/Navigation/Page/Mvc.php b/lib/Zend/Navigation/Page/Mvc.php index 5bc0d880fc..114fbbb932 100644 --- a/lib/Zend/Navigation/Page/Mvc.php +++ b/lib/Zend/Navigation/Page/Mvc.php @@ -34,6 +34,13 @@ class Mvc extends AbstractPage */ protected $controller; + /** + * URL query part to use when assembling URL + * + * @var array|string + */ + protected $query; + /** * Params to use when assembling URL * @@ -68,6 +75,13 @@ class Mvc extends AbstractPage */ protected $routeMatch; + /** + * If true and set routeMatch than getHref will use routeMatch params + * to assemble uri + * @var bool + */ + protected $useRouteMatch = false; + /** * Router for assembling URLs * @@ -244,7 +258,23 @@ public function getHref() ); } - $params = $this->getParams(); + if ($this->useRouteMatch()) { + $rmParams = $this->getRouteMatch()->getParams(); + + if (isset($rmParams[ModuleRouteListener::ORIGINAL_CONTROLLER])) { + $rmParams['controller'] = $rmParams[ModuleRouteListener::ORIGINAL_CONTROLLER]; + unset($rmParams[ModuleRouteListener::ORIGINAL_CONTROLLER]); + } + + if (isset($rmParams[ModuleRouteListener::MODULE_NAMESPACE])) { + unset($rmParams[ModuleRouteListener::MODULE_NAMESPACE]); + } + + $params = array_merge($rmParams, $this->getParams()); + } else { + $params = $this->getParams(); + } + /**#@+ * Added by Taiwen Jiang @@ -262,29 +292,35 @@ public function getHref() $params['action'] = $param; } + switch (true) { + case ($this->getRoute() !== null): + $name = $this->getRoute(); + break; + case ($this->getRouteMatch() !== null): + $name = $this->getRouteMatch()->getMatchedRouteName(); + break; + default: + throw new Exception\DomainException('No route name could be found'); + } + + $options = array('name' => $name); + + // Add the fragment identifier if it is set + $fragment = $this->getFragment(); + if (null !== $fragment) { + $options['fragment'] = $fragment; + } + + if (null !== ($query = $this->getQuery())) { + $options['query'] = $query; + } + + /**#@+ * Modified by Taiwen Jiang */ try { - switch (true) { - case ($this->getRoute() !== null): - $name = $this->getRoute(); - break; - case ($this->getRouteMatch() !== null): - $name = $this->getRouteMatch()->getMatchedRouteName(); - break; - default: - throw new Exception\DomainException('No route name could be found'); - } - - $options = array('name' => $name); - $url = $router->assemble($params, $options); - - // Add the fragment identifier if it is set - $fragment = $this->getFragment(); - if (null !== $fragment) { - $url .= '#' . $fragment; - } + $url = $router->assemble($params, $options); } catch (\Exception $e) { $url = ''; trigger_error($e->getMessage(), E_USER_WARNING); @@ -400,6 +436,32 @@ public function getModule() } /**#@-*/ + /** + * Sets URL query part to use when assembling URL + * + * @see getHref() + * @param array|string|null $query URL query part + * @return self fluent interface, returns self + */ + public function setQuery($query) + { + $this->query = $query; + $this->hrefCache = null; + return $this; + } + + /** + * Returns URL query part to use when assembling URL + * + * @see getHref() + * + * @return array|string|null URL query part (as an array or string) or null + */ + public function getQuery() + { + return $this->query; + } + /** * Sets params to use when assembling URL * @@ -494,6 +556,30 @@ public function setRouteMatch(RouteMatch $matches) return $this; } + /** + * Get the useRouteMatch flag + * + * @return bool + */ + public function useRouteMatch() + { + return $this->useRouteMatch; + } + + /** + * Set whether the page should use route match params for assembling link uri + * + * @see getHref() + * @param bool $useRouteMatch [optional] + * @return Mvc + */ + public function setUseRouteMatch($useRouteMatch = true) + { + $this->useRouteMatch = (bool) $useRouteMatch; + $this->hrefCache = null; + return $this; + } + /** * Get the router. * @@ -586,6 +672,8 @@ public function toArray() 'controller' => $this->getController(), 'params' => $this->getParams(), 'route' => $this->getRoute(), + 'router' => $this->getRouter(), + 'route_match' => $this->getRouteMatch(), /**#@+ * Added by Taiwen Jiang */ diff --git a/lib/Zend/Navigation/Service/AbstractNavigationFactory.php b/lib/Zend/Navigation/Service/AbstractNavigationFactory.php index 89368e8814..f5af421edc 100644 --- a/lib/Zend/Navigation/Service/AbstractNavigationFactory.php +++ b/lib/Zend/Navigation/Service/AbstractNavigationFactory.php @@ -63,16 +63,26 @@ protected function getPages(ServiceLocatorInterface $serviceLocator) )); } - $application = $serviceLocator->get('Application'); - $routeMatch = $application->getMvcEvent()->getRouteMatch(); - $router = $application->getMvcEvent()->getRouter(); $pages = $this->getPagesFromConfig($configuration['navigation'][$this->getName()]); - - $this->pages = $this->injectComponents($pages, $routeMatch, $router); + $this->pages = $this->preparePages($serviceLocator, $pages); } return $this->pages; } + /** + * @param ServiceLocatorInterface $serviceLocator + * @param array|\Zend\Config\Config $pages + * @throws \Zend\Navigation\Exception\InvalidArgumentException + */ + protected function preparePages(ServiceLocatorInterface $serviceLocator, $pages) + { + $application = $serviceLocator->get('Application'); + $routeMatch = $application->getMvcEvent()->getRouteMatch(); + $router = $application->getMvcEvent()->getRouter(); + + return $this->injectComponents($pages, $routeMatch, $router); + } + /** * @param string|\Zend\Config\Config|array $config * @return array|null|\Zend\Config\Config diff --git a/lib/Zend/Navigation/Service/ConstructedNavigationFactory.php b/lib/Zend/Navigation/Service/ConstructedNavigationFactory.php index bbf75fa5ab..373c5887b1 100644 --- a/lib/Zend/Navigation/Service/ConstructedNavigationFactory.php +++ b/lib/Zend/Navigation/Service/ConstructedNavigationFactory.php @@ -16,12 +16,17 @@ */ class ConstructedNavigationFactory extends AbstractNavigationFactory { + /** + * @var string|\Zend\Config\Config|array + */ + protected $config; + /** * @param string|\Zend\Config\Config|array $config */ public function __construct($config) { - $this->pages = $this->getPagesFromConfig($config); + $this->config = $config; } /** @@ -30,6 +35,9 @@ public function __construct($config) */ public function getPages(ServiceLocatorInterface $serviceLocator) { + if (null === $this->pages) { + $this->pages = $this->preparePages($serviceLocator, $this->getPagesFromConfig($this->config)); + } return $this->pages; } diff --git a/lib/Zend/Paginator/Adapter/DbSelect.php b/lib/Zend/Paginator/Adapter/DbSelect.php index 3919de15a9..05c66336c3 100644 --- a/lib/Zend/Paginator/Adapter/DbSelect.php +++ b/lib/Zend/Paginator/Adapter/DbSelect.php @@ -115,7 +115,7 @@ public function count() foreach ($joins as $join) { $select->join($join['name'], $join['on'], array(), $join['type']); } - + $select->columns(array('c' => new Expression('COUNT(1)'))); $statement = $this->sql->prepareStatementForSqlObject($select); diff --git a/lib/Zend/Permissions/Acl/Acl.php b/lib/Zend/Permissions/Acl/Acl.php index e12a363cc8..5774d21ed6 100644 --- a/lib/Zend/Permissions/Acl/Acl.php +++ b/lib/Zend/Permissions/Acl/Acl.php @@ -556,6 +556,10 @@ public function setRule($operation, $type, $roles = null, $resources = null, if (!is_array($resources)) { if (null === $resources && count($this->resources) > 0) { $resources = array_keys($this->resources); + // Passing a null resource; make sure "global" permission is also set! + if (!in_array(null, $resources)) { + array_unshift($resources, null); + } } else { $resources = array($resources); } diff --git a/lib/Zend/Permissions/Acl/Role/Registry.php b/lib/Zend/Permissions/Acl/Role/Registry.php index 0ea49d0f9f..9cbb847434 100644 --- a/lib/Zend/Permissions/Acl/Role/Registry.php +++ b/lib/Zend/Permissions/Acl/Role/Registry.php @@ -9,6 +9,7 @@ namespace Zend\Permissions\Acl\Role; +use Traversable; use Zend\Permissions\Acl\Exception; class Registry @@ -34,8 +35,8 @@ class Registry * will have the least priority, and the last parent added will have the * highest priority. * - * @param RoleInterface $role - * @param RoleInterface|string|array $parents + * @param RoleInterface $role + * @param RoleInterface|string|array|Traversable $parents * @throws Exception\InvalidArgumentException * @return Registry Provides a fluent interface */ @@ -53,7 +54,7 @@ public function add(RoleInterface $role, $parents = null) $roleParents = array(); if (null !== $parents) { - if (!is_array($parents)) { + if (!is_array($parents) && !$parents instanceof Traversable) { $parents = array($parents); } foreach ($parents as $parent) { diff --git a/lib/Zend/Permissions/Rbac/AbstractIterator.php b/lib/Zend/Permissions/Rbac/AbstractIterator.php index 43e38c37a9..df9c8f86c6 100644 --- a/lib/Zend/Permissions/Rbac/AbstractIterator.php +++ b/lib/Zend/Permissions/Rbac/AbstractIterator.php @@ -80,7 +80,11 @@ public function rewind() */ public function hasChildren() { - return count($this->children) > 0; + if ($this->valid() && ($this->current() instanceof RecursiveIterator)) { + return true; + } + + return false; } /** diff --git a/lib/Zend/Permissions/Rbac/Rbac.php b/lib/Zend/Permissions/Rbac/Rbac.php index fd3c67d16e..91880b7eeb 100644 --- a/lib/Zend/Permissions/Rbac/Rbac.php +++ b/lib/Zend/Permissions/Rbac/Rbac.php @@ -45,7 +45,7 @@ public function getCreateMissingRoles() * * @param string|RoleInterface $child * @param array|RoleInterface|null $parents - * @return RoleInterface + * @return self * @throws Exception\InvalidArgumentException */ public function addRole($child, $parents = null) diff --git a/lib/Zend/Serializer/Adapter/PythonPickle.php b/lib/Zend/Serializer/Adapter/PythonPickle.php index 201ea39dee..4cd157ee29 100644 --- a/lib/Zend/Serializer/Adapter/PythonPickle.php +++ b/lib/Zend/Serializer/Adapter/PythonPickle.php @@ -234,7 +234,7 @@ protected function write($value) throw new Exception\RuntimeException(sprintf( 'PHP-Type "%s" can not be serialized by %s', gettype($value), - get_called_class() + get_class($this) )); } } diff --git a/lib/Zend/ServiceManager/ServiceManager.php b/lib/Zend/ServiceManager/ServiceManager.php index 4b503e21e2..2a76ba5fad 100644 --- a/lib/Zend/ServiceManager/ServiceManager.php +++ b/lib/Zend/ServiceManager/ServiceManager.php @@ -53,6 +53,16 @@ class ServiceManager implements ServiceLocatorInterface */ protected $pendingAbstractFactoryRequests = array(); + /** + * @var string + */ + protected $lastAbstractFactoryUsed = null; + + /** + * @var string + */ + protected $lastCanonicalNameUsed = null; + /** * @var array */ @@ -148,7 +158,7 @@ public function setShareByDefault($shareByDefault) if ($this->allowOverride === false) { throw new Exception\RuntimeException(sprintf( '%s: cannot alter default shared service setting; container is marked immutable (allow_override is false)', - __METHOD__ + get_class($this) . '::' . __FUNCTION__ )); } $this->shareByDefault = (bool) $shareByDefault; @@ -362,7 +372,7 @@ public function setService($name, $service) if ($this->allowOverride === false) { throw new Exception\InvalidServiceNameException(sprintf( '%s: A service by the name "%s" or alias already exists and cannot be overridden, please use an alternate name.', - __METHOD__, + get_class($this) . '::' . __FUNCTION__, $name )); } @@ -391,7 +401,7 @@ public function setShared($name, $isShared) ) { throw new Exception\ServiceNotFoundException(sprintf( '%s: A service by the name "%s" was not found and could not be marked as shared', - __METHOD__, + get_class($this) . '::' . __FUNCTION__, $name )); } @@ -455,7 +465,7 @@ public function get($name, $usePeeringServiceManagers = true) throw new Exception\ServiceNotFoundException(sprintf( '%s was unable to fetch or create an instance for %s', - __METHOD__, + get_class($this) . '::' . __FUNCTION__, $name )); } @@ -608,7 +618,18 @@ public function canCreateFromAbstractFactory($cName, $rName) return false; } + $objectHash = spl_object_hash($abstractFactory); + + if ($this->lastAbstractFactoryUsed === $objectHash && $this->lastCanonicalNameUsed === $cName) { + $this->lastAbstractFactoryUsed = $this->lastCanonicalNameUsed = null; + return false; + } + + $this->lastAbstractFactoryUsed = $objectHash; + $this->lastCanonicalNameUsed = $cName; + if ($abstractFactory->canCreateServiceWithName($this, $cName, $rName)) { + $this->lastAbstractFactoryUsed = $this->lastCanonicalNameUsed = null; return true; } } @@ -838,7 +859,7 @@ protected function createFromInvokable($canonicalName, $requestedName) if (!class_exists($invokable)) { throw new Exception\ServiceNotFoundException(sprintf( '%s: failed retrieving "%s%s" via invokable class "%s"; class does not exist', - __METHOD__, + get_class($this) . '::' . __FUNCTION__, $canonicalName, ($requestedName ? '(alias: ' . $requestedName . ')' : ''), $invokable diff --git a/lib/Zend/Session/Config/StandardConfig.php b/lib/Zend/Session/Config/StandardConfig.php index af8f22f526..9424a8b2c7 100644 --- a/lib/Zend/Session/Config/StandardConfig.php +++ b/lib/Zend/Session/Config/StandardConfig.php @@ -803,7 +803,7 @@ public function __call($method, $args) throw new Exception\BadMethodCallException(sprintf( 'Method "%s" does not exist in %s', $method, - get_called_class() + get_class($this) )); } } diff --git a/lib/Zend/Stdlib/AbstractOptions.php b/lib/Zend/Stdlib/AbstractOptions.php index 8099c75ff9..0e68c29e11 100644 --- a/lib/Zend/Stdlib/AbstractOptions.php +++ b/lib/Zend/Stdlib/AbstractOptions.php @@ -22,6 +22,8 @@ abstract class AbstractOptions implements ParameterObjectInterface protected $__strictMode__ = true; /** + * Constructor + * * @param array|Traversable|null $options */ public function __construct($options = null) @@ -32,22 +34,29 @@ public function __construct($options = null) } /** - * @param array|Traversable $options + * Set one or more configuration properties + * + * @param array|Traversable|AbstractOptions $options * @throws Exception\InvalidArgumentException * @return AbstractOptions Provides fluent interface */ public function setFromArray($options) { + if ($options instanceof self) { + $options = $options->toArray(); + } + if (!is_array($options) && !$options instanceof Traversable) { throw new Exception\InvalidArgumentException(sprintf( - 'Parameter provided to %s must be an array or Traversable', - __METHOD__ + 'Parameter provided to %s must be an %s, %s or %s', + __METHOD__, 'array', 'Traversable', 'Zend\Stdlib\AbstractOptions' )); } foreach ($options as $key => $value) { $this->__set($key, $value); } + return $this; } @@ -72,6 +81,8 @@ public function toArray() } /** + * Set a configuration property + * * @see ParameterObject::__set() * @param string $key * @param mixed $value @@ -94,6 +105,8 @@ public function __set($key, $value) } /** + * Get a configuration property + * * @see ParameterObject::__get() * @param string $key * @throws Exception\BadMethodCallException @@ -114,6 +127,7 @@ public function __get($key) } /** + * Test if a configuration property is null * @see ParameterObject::__isset() * @param string $key * @return bool @@ -124,6 +138,8 @@ public function __isset($key) } /** + * Set a configuration property to NULL + * * @see ParameterObject::__unset() * @param string $key * @throws Exception\InvalidArgumentException diff --git a/lib/Zend/Stdlib/Hydrator/ArraySerializable.php b/lib/Zend/Stdlib/Hydrator/ArraySerializable.php index 09dfebba1c..d9631122e1 100644 --- a/lib/Zend/Stdlib/Hydrator/ArraySerializable.php +++ b/lib/Zend/Stdlib/Hydrator/ArraySerializable.php @@ -31,15 +31,16 @@ public function extract($object) )); } - $self = $this; $data = $object->getArrayCopy(); - array_walk($data, function (&$value, $name) use ($self, &$data) { - if (!$self->getFilter()->filter($name)) { + + foreach ($data as $name => $value) { + if (!$this->getFilter()->filter($name)) { unset($data[$name]); - } else { - $value = $self->extractValue($name, $value); + continue; } - }); + + $data[$name] = $this->extractValue($name, $value); + } return $data; } diff --git a/lib/Zend/Stdlib/Hydrator/ClassMethods.php b/lib/Zend/Stdlib/Hydrator/ClassMethods.php index 679df32c81..5ad76c0a73 100644 --- a/lib/Zend/Stdlib/Hydrator/ClassMethods.php +++ b/lib/Zend/Stdlib/Hydrator/ClassMethods.php @@ -177,7 +177,7 @@ public function hydrate(array $data, $object) if ($this->underscoreSeparatedKeys) { $method = preg_replace_callback('/(_[a-z])/', $transform, $method); } - if (method_exists($object, $method)) { + if (is_callable(array($object, $method))) { $value = $this->hydrateValue($property, $value); $object->$method($value); diff --git a/lib/Zend/Stdlib/Hydrator/ObjectProperty.php b/lib/Zend/Stdlib/Hydrator/ObjectProperty.php index e212dc79a1..52178a1b3b 100644 --- a/lib/Zend/Stdlib/Hydrator/ObjectProperty.php +++ b/lib/Zend/Stdlib/Hydrator/ObjectProperty.php @@ -30,15 +30,19 @@ public function extract($object) )); } - $self = $this; $data = get_object_vars($object); - array_walk($data, function (&$value, $name) use ($self, &$data) { - if (!$self->getFilter()->filter($name)) { + + $filter = $this->getFilter(); + foreach ($data as $name => $value) { + // Filter keys, removing any we don't want + if (!$filter->filter($name)) { unset($data[$name]); - } else { - $value = $self->extractValue($name, $value); + continue; } - }); + // Extract data + $data[$name] = $this->extractValue($name, $value); + } + return $data; } diff --git a/lib/Zend/Stdlib/PriorityQueue.php b/lib/Zend/Stdlib/PriorityQueue.php index 5c0c13db93..bf6a624ac8 100644 --- a/lib/Zend/Stdlib/PriorityQueue.php +++ b/lib/Zend/Stdlib/PriorityQueue.php @@ -98,9 +98,12 @@ public function remove($datum) if ($found) { unset($this->items[$key]); $this->queue = null; - $queue = $this->getQueue(); - foreach ($this->items as $item) { - $queue->insert($item['data'], $item['priority']); + + if (!$this->isEmpty()) { + $queue = $this->getQueue(); + foreach ($this->items as $item) { + $queue->insert($item['data'], $item['priority']); + } } return true; } diff --git a/lib/Zend/Uri/Uri.php b/lib/Zend/Uri/Uri.php index 8800bf01e4..5b092244e5 100644 --- a/lib/Zend/Uri/Uri.php +++ b/lib/Zend/Uri/Uri.php @@ -677,7 +677,7 @@ public function setScheme($scheme) throw new Exception\InvalidUriPartException(sprintf( 'Scheme "%s" is not valid or is not accepted by %s', $scheme, - get_called_class() + get_class($this) ), Exception\InvalidUriPartException::INVALID_SCHEME); } @@ -726,7 +726,7 @@ public function setHost($host) throw new Exception\InvalidUriPartException(sprintf( 'Host "%s" is not valid or is not accepted by %s', $host, - get_called_class() + get_class($this) ), Exception\InvalidUriPartException::INVALID_HOSTNAME); } diff --git a/lib/Zend/Validator/CreditCard.php b/lib/Zend/Validator/CreditCard.php index 9867e56b62..4d55e0b90e 100644 --- a/lib/Zend/Validator/CreditCard.php +++ b/lib/Zend/Validator/CreditCard.php @@ -51,7 +51,7 @@ class CreditCard extends AbstractValidator self::INVALID => "Invalid type given. String expected", self::LENGTH => "The input contains an invalid amount of digits", self::PREFIX => "The input is not from an allowed institute", - self::SERVICE => "The input seems to be an invalid credit card number.", + self::SERVICE => "The input seems to be an invalid credit card number", self::SERVICEFAILURE => "An exception has been raised while validating the input", ); diff --git a/lib/Zend/Validator/Explode.php b/lib/Zend/Validator/Explode.php index da36805652..e8a80499d0 100644 --- a/lib/Zend/Validator/Explode.php +++ b/lib/Zend/Validator/Explode.php @@ -20,7 +20,7 @@ class Explode extends AbstractValidator * @var array */ protected $messageTemplates = array( - self::INVALID => "Invalid type given.", + self::INVALID => "Invalid type given", ); /** diff --git a/lib/Zend/Validator/File/ExcludeMimeType.php b/lib/Zend/Validator/File/ExcludeMimeType.php index 942c7c4f44..2d2477455e 100644 --- a/lib/Zend/Validator/File/ExcludeMimeType.php +++ b/lib/Zend/Validator/File/ExcludeMimeType.php @@ -61,13 +61,12 @@ public function isValid($value, $file = null) $mimefile = $this->getMagicFile(); if (class_exists('finfo', false)) { - $const = defined('FILEINFO_MIME_TYPE') ? FILEINFO_MIME_TYPE : FILEINFO_MIME; if (!$this->isMagicFileDisabled() && (!empty($mimefile) && empty($this->finfo))) { - $this->finfo = finfo_open($const, $mimefile); + $this->finfo = finfo_open(FILEINFO_MIME_TYPE, $mimefile); } if (empty($this->finfo)) { - $this->finfo = finfo_open($const); + $this->finfo = finfo_open(FILEINFO_MIME_TYPE); } $this->type = null; diff --git a/lib/Zend/Validator/File/MimeType.php b/lib/Zend/Validator/File/MimeType.php index c565b1e5d4..251ec925a8 100644 --- a/lib/Zend/Validator/File/MimeType.php +++ b/lib/Zend/Validator/File/MimeType.php @@ -201,9 +201,8 @@ public function setMagicFile($file) $file )); } else { - $const = defined('FILEINFO_MIME_TYPE') ? FILEINFO_MIME_TYPE : FILEINFO_MIME; ErrorHandler::start(E_NOTICE|E_WARNING); - $this->finfo = finfo_open($const, $file); + $this->finfo = finfo_open(FILEINFO_MIME_TYPE, $file); $error = ErrorHandler::stop(); if (empty($this->finfo)) { $this->finfo = null; @@ -376,16 +375,15 @@ public function isValid($value, $file = null) $mimefile = $this->getMagicFile(); if (class_exists('finfo', false)) { - $const = defined('FILEINFO_MIME_TYPE') ? FILEINFO_MIME_TYPE : FILEINFO_MIME; if (!$this->isMagicFileDisabled() && (!empty($mimefile) && empty($this->finfo))) { ErrorHandler::start(E_NOTICE|E_WARNING); - $this->finfo = finfo_open($const, $mimefile); + $this->finfo = finfo_open(FILEINFO_MIME_TYPE, $mimefile); ErrorHandler::stop(); } if (empty($this->finfo)) { ErrorHandler::start(E_NOTICE|E_WARNING); - $this->finfo = finfo_open($const); + $this->finfo = finfo_open(FILEINFO_MIME_TYPE); ErrorHandler::stop(); } @@ -395,9 +393,10 @@ public function isValid($value, $file = null) } } - if (empty($this->type) && - (function_exists('mime_content_type') && ini_get('mime_magic.magicfile'))) { - $this->type = mime_content_type($file); + if (empty($this->type) + && (function_exists('mime_content_type') && ini_get('mime_magic.magicfile')) + ) { + $this->type = mime_content_type($file); } if (empty($this->type) && $this->getHeaderCheck()) { diff --git a/lib/Zend/Validator/File/WordCount.php b/lib/Zend/Validator/File/WordCount.php index 2d0223bdcb..7f473ae309 100644 --- a/lib/Zend/Validator/File/WordCount.php +++ b/lib/Zend/Validator/File/WordCount.php @@ -28,8 +28,8 @@ class WordCount extends AbstractValidator * @var array Error message templates */ protected $messageTemplates = array( - self::TOO_MUCH => "Too many words, maximum '%max%' are allowed but '%count%' were counted.", - self::TOO_LESS => "Too less words, minimum '%min%' are expected but '%count%' were counted", + self::TOO_MUCH => "Too many words, maximum '%max%' are allowed but '%count%' were counted", + self::TOO_LESS => "Too few words, minimum '%min%' are expected but '%count%' were counted", self::NOT_FOUND => "File is not readable or does not exist", ); diff --git a/lib/Zend/Validator/Iban.php b/lib/Zend/Validator/Iban.php index 6fcc8c2aca..58f7ae2917 100644 --- a/lib/Zend/Validator/Iban.php +++ b/lib/Zend/Validator/Iban.php @@ -76,6 +76,7 @@ class Iban extends AbstractValidator 'BE' => 'BE[0-9]{2}[0-9]{3}[0-9]{7}[0-9]{2}', 'BG' => 'BG[0-9]{2}[A-Z]{4}[0-9]{4}[0-9]{2}[A-Z0-9]{8}', 'BH' => 'BH[0-9]{2}[A-Z]{4}[A-Z0-9]{14}', + 'BR' => 'BR[0-9]{2}[0-9]{8}[0-9]{5}[0-9]{10}[A-Z][A-Z0-9]', 'CH' => 'CH[0-9]{2}[0-9]{5}[A-Z0-9]{12}', 'CR' => 'CR[0-9]{2}[0-9]{3}[0-9]{14}', 'CY' => 'CY[0-9]{2}[0-9]{3}[0-9]{5}[A-Z0-9]{16}', diff --git a/lib/Zend/Validator/InArray.php b/lib/Zend/Validator/InArray.php index 2732fa986e..d4392e0019 100644 --- a/lib/Zend/Validator/InArray.php +++ b/lib/Zend/Validator/InArray.php @@ -75,7 +75,7 @@ class InArray extends AbstractValidator */ public function getHaystack() { - if ($this->haystack == null) { + if ($this->haystack === null) { throw new Exception\RuntimeException('haystack option is mandatory'); } return $this->haystack; diff --git a/lib/Zend/Version/Version.php b/lib/Zend/Version/Version.php index 7e4a4377e7..4f0c0b5b73 100644 --- a/lib/Zend/Version/Version.php +++ b/lib/Zend/Version/Version.php @@ -19,7 +19,7 @@ final class Version /** * Zend Framework version identification - see compareVersion() */ - const VERSION = '2.1.5dev'; + const VERSION = '2.1.6dev'; /** * Github Service Identifier for version information is retreived from diff --git a/lib/Zend/View/Helper/FlashMessenger.php b/lib/Zend/View/Helper/FlashMessenger.php index 7d066118c6..e94aa8bcd0 100644 --- a/lib/Zend/View/Helper/FlashMessenger.php +++ b/lib/Zend/View/Helper/FlashMessenger.php @@ -124,7 +124,7 @@ public function render($namespace = PluginFlashMessenger::NAMESPACE_DEFAULT, arr // Generate markup $markup = sprintf($this->getMessageOpenFormat(), ' class="' . implode(' ', $classes) . '"'); - $markup .= implode($this->getMessageSeparatorString(), $messagesToPrint); + $markup .= implode(sprintf($this->getMessageSeparatorString(), ' class="' . implode(' ', $classes) . '"'), $messagesToPrint); $markup .= $this->getMessageCloseString(); return $markup; diff --git a/lib/Zend/View/Helper/Navigation.php b/lib/Zend/View/Helper/Navigation.php index 931817526a..a0b78fef6e 100644 --- a/lib/Zend/View/Helper/Navigation.php +++ b/lib/Zend/View/Helper/Navigation.php @@ -190,6 +190,10 @@ public function findHelper($proxy, $strict = true) $helper->setContainer(); $this->inject($helper); $this->injected[$hash] = true; + } else { + if ($this->getInjectContainer()) { + $helper->setContainer($container); + } } return $helper; diff --git a/lib/Zend/View/Resolver/TemplatePathStack.php b/lib/Zend/View/Resolver/TemplatePathStack.php index c5ebb487d1..e82c2f8d04 100644 --- a/lib/Zend/View/Resolver/TemplatePathStack.php +++ b/lib/Zend/View/Resolver/TemplatePathStack.php @@ -296,7 +296,7 @@ public function resolve($name, Renderer $renderer = null) // Ensure we have the expected file extension $defaultSuffix = $this->getDefaultSuffix(); - if (pathinfo($name, PATHINFO_EXTENSION) != $defaultSuffix) {; + if (pathinfo($name, PATHINFO_EXTENSION) != $defaultSuffix) { $name .= '.' . $defaultSuffix; } diff --git a/lib/Zend/View/View.php b/lib/Zend/View/View.php index 511f406ac1..c2f4cb21df 100644 --- a/lib/Zend/View/View.php +++ b/lib/Zend/View/View.php @@ -89,7 +89,7 @@ public function setEventManager(EventManagerInterface $events) { $events->setIdentifiers(array( __CLASS__, - get_called_class(), + get_class($this), )); $this->events = $events; return $this; @@ -184,6 +184,10 @@ public function render(Model $model) $event->setRenderer($renderer); $results = $events->trigger(ViewEvent::EVENT_RENDERER_POST, $event); + // If EVENT_RENDERER or EVENT_RENDERER_POST changed the model, make sure + // we use this new model instead of the current $model + $model = $event->getModel(); + // If we have children, render them first, but only if: // a) the renderer does not implement TreeRendererInterface, or // b) it does, but canRenderTrees() returns false diff --git a/lib/Zend/View/composer.json b/lib/Zend/View/composer.json index bb22db9ebc..6982ec17d2 100644 --- a/lib/Zend/View/composer.json +++ b/lib/Zend/View/composer.json @@ -19,7 +19,8 @@ "zendframework/zend-stdlib": "self.version" }, "suggest": { - "zendframework/zend-filter": "Zend\\Filter component" + "zendframework/zend-filter": "Zend\\Filter component", + "zendframework/zend-servicemanager": "self.version" }, "extra": { "branch-alias": { diff --git a/lib/vendor/index.html b/lib/vendor/index.html new file mode 100644 index 0000000000..990cbd6037 --- /dev/null +++ b/lib/vendor/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/usr/module/demo/locale/en/index.html b/usr/module/demo/locale/en/index.html new file mode 100644 index 0000000000..990cbd6037 --- /dev/null +++ b/usr/module/demo/locale/en/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/usr/module/page/src/Controller/Front/IndexController.php b/usr/module/page/src/Controller/Front/IndexController.php index 3e12a03b47..feae605a32 100644 --- a/usr/module/page/src/Controller/Front/IndexController.php +++ b/usr/module/page/src/Controller/Front/IndexController.php @@ -40,7 +40,7 @@ protected function render($row) } $title = $row->title; // Specify page head title - $this->view()->headTitle()->prepend($row->title); + $this->view()->headTitle($row->title); $model = $this->getModel('page'); $model->update(array('clicks' => new Expression('`clicks` + 1')), array('id' => $row->id)); } diff --git a/usr/module/system/config/config.php b/usr/module/system/config/config.php index 85030d5d58..fa9b121ef8 100644 --- a/usr/module/system/config/config.php +++ b/usr/module/system/config/config.php @@ -133,16 +133,20 @@ 'title' => 'Head meta', ), array( - 'name' => 'mail', - 'title' => 'Mailing', + 'name' => 'intl', + 'title' => 'Internationalization', + ), + array( + 'name' => 'user', + 'title' => 'User account', ), array( 'name' => 'text', 'title' => 'Text processing', ), array( - 'name' => 'user', - 'title' => 'User account', + 'name' => 'mail', + 'title' => 'Mailing', ), ); @@ -168,12 +172,6 @@ 'category' => 'general', ), - 'adminmail' => array( - 'title' => 'Admin email', - 'description' => 'Admin email address for convenient contact.', - 'category' => 'general', - ), - 'locale' => array( 'title' => 'Locale', 'description' => 'Locale for application content.', @@ -189,26 +187,16 @@ 'category' => 'general', ), - /* - 'timezone_server' => array( - 'title' => 'Server timezone', - 'description' => 'Timezone set by server.', - 'edit' => 'timezone', - 'category' => 'general', - ), - - 'timezone_system' => array( - 'title' => 'System timezone', + 'timezone' => array( + 'title' => 'Timezone', 'description' => 'Timezone for application system.', 'edit' => 'timezone', 'category' => 'general', ), - */ - 'timezone' => array( - 'title' => 'Timezone', - 'description' => 'Timezone for application system.', - 'edit' => 'timezone', + 'adminmail' => array( + 'title' => 'Admin email', + 'description' => 'Admin email address for convenient contact.', 'category' => 'general', ), @@ -249,6 +237,7 @@ ), // Meta section + 'copyright' => array( 'title' => 'Meta copyright', 'description' => 'The copyright meta tag defines any copyright statements you wish to disclose about your web page documents.', @@ -289,6 +278,109 @@ 'category' => 'meta', ), + // Internationalizaiton section + + 'number_style' => array( + 'title' => 'Default number style', + 'description' => 'See http://www.php.net/manual/en/class.numberformatter.php#intl.numberformatter-constants.unumberformatstyle', + 'edit' => array( + 'type' => 'select', + 'options' => array( + 'options' => array( + 'DEFAULT_STYLE' => 'Default format for the locale', + 'PATTERN_DECIMAL' => 'Decimal format defined by pattern', + 'DECIMAL' => 'Decimal format', + 'PERCENT' => 'Percent format', + 'SCIENTIFIC' => 'Scientific format', + 'SPELLOUT' => 'Spellout rule-based format', + 'ORDINAL' => 'Ordinal rule-based format', + 'DURATION' => 'Duration rule-based format', + 'PATTERN_RULEBASED' => 'Rule-based format defined by pattern', + ), + ), + ), + 'value' => 'DEFAULT_STYLE', + 'category' => 'intl', + ), + + 'number_pattern' => array( + 'title' => 'Default pattern for selected number style', + 'description' => 'Only if required by style', + 'edit' => 'text', + 'value' => '', + 'category' => 'intl', + ), + + 'number_currency' => array( + 'title' => 'Default currency type', + 'description' => 'The 3-letter ISO 4217 currency code indicating the currency to use.', + 'edit' => 'text', + 'value' => '', + 'category' => 'intl', + ), + + 'date_calendar' => array( + 'title' => 'Default calendar for the locale', + 'description' => '"persian" is suggested for Persian language. See http://www.php.net/manual/en/class.intldateformatter.php#intl.intldateformatter-constants.calendartypes', + 'edit' => 'text', + 'value' => '', + 'category' => 'intl', + ), + + 'date_datetype' => array( + 'title' => 'Default date type', + 'description' => 'See http://www.php.net/manual/en/class.intldateformatter.php#intl.intldateformatter-constants', + 'edit' => array( + 'type' => 'select', + 'options' => array( + 'options' => array( + 'NONE' => 'Do not include this element', + 'FULL' => 'Completely specified style (Tuesday, April 12, 1952 AD or 3:30:42pm PST)', + 'LONG' => 'Long style (January 12, 1952 or 3:30:32pm)', + 'MEDIUM' => 'Medium style (Jan 12, 1952)', + 'SHORT' => 'Most abbreviated style, only essential data (12/13/52 or 3:30pm)', + ), + ), + ), + 'value' => 'MEDIUM', + 'category' => 'intl', + ), + + 'date_timetype' => array( + 'title' => 'Default time type', + 'description' => 'See http://www.php.net/manual/en/class.intldateformatter.php#intl.intldateformatter-constants', + 'edit' => array( + 'type' => 'select', + 'options' => array( + 'options' => array( + 'NONE' => 'Do not include this element', + 'FULL' => 'Completely specified style (Tuesday, April 12, 1952 AD or 3:30:42pm PST)', + 'LONG' => 'Long style (January 12, 1952 or 3:30:32pm)', + 'MEDIUM' => 'Medium style (Jan 12, 1952)', + 'SHORT' => 'Most abbreviated style, only essential data (12/13/52 or 3:30pm)', + ), + ), + ), + 'value' => 'LONG', + 'category' => 'intl', + ), + + 'date_pattern' => array( + 'title' => 'Default formatting pattern for date-time', + 'description' => 'See http://userguide.icu-project.org/formatparse/datetime', + 'edit' => 'text', + 'value' => 'yyyy-MM-dd HH:mm:ss', + 'category' => 'intl', + ), + + 'date_format' => array( + 'title' => 'Default format for legacy date function', + 'description' => 'The format is required in case Intl extension is not available. See http://www.php.net/manual/en/function.date.php', + 'edit' => 'text', + 'value' => 'Y-m-d H:i:s', + 'category' => 'intl', + ), + // Mailing section 'mailmethod' => array( diff --git a/usr/module/system/config/module.php b/usr/module/system/config/module.php index eaf9fd305a..874089e1c4 100644 --- a/usr/module/system/config/module.php +++ b/usr/module/system/config/module.php @@ -29,7 +29,7 @@ // Description, for admin, optional 'description' => __('For administration of core functions of the site.'), // Version number, required - 'version' => '3.0.6', + 'version' => '3.1.1', // Distribution license, required 'license' => 'New BSD', // Logo image, for admin, optional diff --git a/usr/module/system/sql/mysql.system.sql b/usr/module/system/sql/mysql.system.sql index 1fc4b11897..68b534f4a4 100644 --- a/usr/module/system/sql/mysql.system.sql +++ b/usr/module/system/sql/mysql.system.sql @@ -200,7 +200,7 @@ CREATE TABLE `{core.config}` ( `title` varchar(255) NOT NULL default '', `value` text, `description` varchar(255) NOT NULL default '', - `edit` tinytext default NULL, # callback options for edit + `edit` text, # callback options for edit `filter` varchar(64) NOT NULL default '', `order` smallint(5) unsigned NOT NULL default '0', `visible` tinyint(1) unsigned NOT NULL default '1', @@ -287,6 +287,15 @@ CREATE TABLE `{core.module_schema}` ( PRIMARY KEY (`id`) ); +# Module dependency +CREATE TABLE `{core.module_dependency}` ( + `id` int(10) unsigned NOT NULL auto_increment, + `dependent` varchar(64) NOT NULL, + `independent` varchar(64) NOT NULL, + + PRIMARY KEY (`id`) +); + # ------------------------------------------------------ # Navigation # >>>> @@ -485,10 +494,10 @@ CREATE TABLE `{core.user_meta}` ( `title` varchar(255) NOT NULL default '', `attribute` varchar(255) default NULL, # profile column attribute `view` varchar(255) default NULL, # callback function for view - `edit` tinytext default NULL, # callback options for edit - `admin` tinytext default NULL, # callback options for administration - `search` tinytext default NULL, # callback options for search - `options` tinytext default NULL, # value options + `edit` text, # callback options for edit + `admin` text, # callback options for administration + `search` text, # callback options for search + `options` text, # value options `module` varchar(64) NOT NULL default '', `active` tinyint(1) NOT NULL default '0', `required` tinyint(1) NOT NULL default '0', diff --git a/usr/module/system/src/Api/Block.php b/usr/module/system/src/Api/Block.php index 024f527a29..e62cc64808 100644 --- a/usr/module/system/src/Api/Block.php +++ b/usr/module/system/src/Api/Block.php @@ -127,7 +127,7 @@ public function add($block) $roles = array('guest', 'member'); foreach ($roles as $role) { $rule = isset($access[$role]) ? $access[$role] : 1; - AclHandler::addRule($rule, $role, 'block', $rowBlock->id, $module); + AclHandler::addRule($rule, $role, 'block', $module, $rowBlock->id); /* $dataRule['role'] = $role; if (isset($access[$role])) { diff --git a/usr/module/system/src/Controller/Admin/ConfigController.php b/usr/module/system/src/Controller/Admin/ConfigController.php index 0d62405b47..35a9b61e41 100644 --- a/usr/module/system/src/Controller/Admin/ConfigController.php +++ b/usr/module/system/src/Controller/Admin/ConfigController.php @@ -59,8 +59,9 @@ public function indexAction() } if ($configs) { $groups = array(); - $configsByCategory = array(); - $categories = Pi::model('config_category')->select(array('module' => $module)); + //$configsByCategory = array(); + $select = Pi::model('config_category')->select()->where(array('module' => $module))->order(array('order ASC')); + $categories = Pi::model('config_category')->selectWith($select); if ($categories->count() > 1) { foreach ($categories as $category) { $groups[$category->name] = array( diff --git a/usr/module/system/src/Controller/Admin/NavController.php b/usr/module/system/src/Controller/Admin/NavController.php index 052a93878d..31cb3e9b84 100644 --- a/usr/module/system/src/Controller/Admin/NavController.php +++ b/usr/module/system/src/Controller/Admin/NavController.php @@ -59,7 +59,7 @@ public function indexAction() { $modules = Pi::service('registry')->module->read(); $modules[''] = array('title' => __('Custom')); - + $navList = array(); $navGlobal = Pi::model('config')->select(array( 'module' => 'system', @@ -98,7 +98,7 @@ public function listAction() ); $rowset = Pi::model('navigation')->select(array('module <> ?' => 'system', 'active' => 1)); - + foreach ($rowset as $row) { if ($row->module) { $navModule[$row->section][$row->module][] = array( @@ -317,7 +317,7 @@ public function deleteAction() protected function cloneNode($parent, $nav) { $model = Pi::model('navigation_node'); - $data = Pi::service('registry')->navigation->read($parent); + $data = Pi::service('registry')->navigation->read($parent) ?: array(); $node = array( 'navigation' => $nav, 'data' => $data, @@ -339,7 +339,7 @@ public function dataAction() //$row = Pi::model('navigation_node')->find($nav, 'navigation'); //$pages = $row->data; - $pages = Pi::service('registry')->navigation->read($nav); + $pages = Pi::service('registry')->navigation->read($nav) ?: array(); $plainList = array(); $no = 1; $depth = 0; @@ -372,7 +372,7 @@ public function dataAction() } $navigation = Pi::model('navigation')->find($nav, 'name'); $nav = $navigation->toArray(); - + $title = sprintf($title, $navigation->title); $this->view()->assign('readonly', $readonly); $this->view()->assign('navigation', $nav); diff --git a/usr/module/system/src/Controller/Front/LoginController.php b/usr/module/system/src/Controller/Front/LoginController.php index 5b466fb498..161cee7353 100644 --- a/usr/module/system/src/Controller/Front/LoginController.php +++ b/usr/module/system/src/Controller/Front/LoginController.php @@ -58,22 +58,8 @@ protected function renderForm($form, $message = '') $this->view()->setTemplate('login'); $configs = Pi::service('registry')->config->read('', 'user'); - //$message = ''; if (!empty($configs['attempts'])) { - /* - $sessionLogin = Pi::service('session')->login; - if (!empty($sessionLogin->attempts) && $sessionLogin->attempts >= $configs['attempts']) { - $wait = Pi::service('session')->manager()->getSaveHandler()->getLifeTime() / 60; - $message = sprintf(__('Login with the account is suspended, please wait for %d minutes to try again.'), $wait); - $this->view()->setTemplate('login-suspended'); - } elseif (!empty($sessionLogin->attempts)) { - $remaining = $configs['attempts'] - $sessionLogin->attempts; - $message = sprintf(__('You have %d times to try.'), $remaining); - } - */ $attempts = isset($_SESSION['PI_LOGIN']['attempts']) ? $_SESSION['PI_LOGIN']['attempts'] : 0; - //d((array)$_SESSION); - //d($attempts); if (!empty($attempts)) { if ($attempts >= $configs['attempts']) { $wait = Pi::service('session')->manager()->getSaveHandler()->getLifeTime() / 60; @@ -85,7 +71,6 @@ protected function renderForm($form, $message = '') } } } - //$form->assign($this->view); $this->view()->assign('title', __('User login')); $this->view()->assign('message', $message); $this->view()->assign('form', $form); @@ -93,9 +78,7 @@ protected function renderForm($form, $message = '') public function logoutAction() { - //$this->view()->assign('title', __('Logout')); - //Pi::service('session')->manager()->destroy(); - Pi::service('session')->manager()->getStorage()->clear(); + Pi::service('session')->manager()->destroy(); $this->jump(array('route' => 'home'), __('You logged out successfully. Now go back to homepage.')); } @@ -118,7 +101,6 @@ public function processAction() if (!$form->isValid()) { $this->renderForm($form, __('Invalid input, please try again.')); - //$this->view()->assign('message', __('Invalid input, please try again.')); return; } @@ -128,15 +110,6 @@ public function processAction() $identity = $values['identity']; $credential = $values['credential']; - /* - if (!empty($configs['attempts'])) { - $sessionLogin = Pi::service('session')->login; - if (!empty($sessionLogin->attempts) && $sessionLogin->attempts >= $configs['attempts']) { - $this->jump(array('route' => 'home'), __('You have tried too many times. Please try later.'), 5); - return; - } - } - */ if (!empty($configs['attempts'])) { $sessionLogin = isset($_SESSION['PI_LOGIN']) ? $_SESSION['PI_LOGIN'] : array(); if (!empty($sessionLogin['attempts']) && $sessionLogin['attempts'] >= $configs['attempts']) { @@ -148,12 +121,6 @@ public function processAction() $result = Pi::service('authentication')->authenticate($identity, $credential); if (!$result->isValid()) { - /* - if (!empty($configs['attempts'])) { - $sessionLogin = Pi::service('session')->login; - $sessionLogin->attempts = isset($sessionLogin->attempts) ? ($sessionLogin->attempts + 1) : 1; - } - */ if (!empty($configs['attempts'])) { if (!isset($_SESSION['PI_LOGIN'])) { $_SESSION['PI_LOGIN'] = array(); @@ -172,10 +139,6 @@ public function processAction() Pi::service('event')->trigger('login', $result->getIdentity()); if (!empty($configs['attempts'])) { - /* - $sessionLogin = Pi::service('session')->login; - unset($sessionLogin); - */ unset($_SESSION['PI_LOGIN']); } @@ -186,10 +149,6 @@ public function processAction() } $this->jump($redirect, __('You have logged in successfully.'), 2); - - //$this->view()->setTemplate('login-success'); - //$this->view()->assign('title', __('Login')); - //return $this->redirect()->toRoute('home'); } // login form diff --git a/usr/module/system/src/Controller/Module/DashboardController.php b/usr/module/system/src/Controller/Module/DashboardController.php index c8581f92ff..a4d2afb195 100644 --- a/usr/module/system/src/Controller/Module/DashboardController.php +++ b/usr/module/system/src/Controller/Module/DashboardController.php @@ -71,7 +71,7 @@ public function modeAction() break; case 'manage': $controller = ''; - $navConfig = Pi::service('registry')->navigation->read('system-component'); + $navConfig = Pi::service('registry')->navigation->read('system-component') ?: array(); foreach ($navConfig as $key => $item) { if (!isset($item['visible']) || $item['visible']) { $controller = $item['controller']; diff --git a/usr/module/system/src/Installer/Action/Update.php b/usr/module/system/src/Installer/Action/Update.php index 9894173675..eb6e3164d8 100644 --- a/usr/module/system/src/Installer/Action/Update.php +++ b/usr/module/system/src/Installer/Action/Update.php @@ -51,6 +51,73 @@ public function updateSchema(Event $e) { $moduleVersion = $e->getParam('version'); + + if (version_compare($moduleVersion, '3.1.1', '<')): + + // Add table of navigation data + $sql =<<<'EOD' +CREATE TABLE `{core.module_dependency}` ( + `id` int(10) unsigned NOT NULL auto_increment, + `dependent` varchar(64) NOT NULL, + `independent` varchar(64) NOT NULL, + + PRIMARY KEY (`id`) +); +EOD; + $sqlHandler = new SqlSchema; + try { + $sqlHandler->queryContent($sql); + } catch (\Exception $exception) { + $result = $e->getParam('result'); + $result['db'] = array( + 'status' => false, + 'message' => 'SQL schema query failed: ' . $exception->getMessage(), + ); + $e->setParam('result', $result); + return false; + } + + endif; + + if (version_compare($moduleVersion, '3.1.0', '<')): + + $sqlHandler = new SqlSchema; + $adapter = Pi::db()->getAdapter(); + + // Change fields from 'tinytext' to 'text' + $table = Pi::model('config')->getTable(); + $sql = sprintf('ALTER TABLE %s MODIFY `edit` text', $table); + try { + $adapter->query($sql, 'execute'); + } catch (\Exception $exception) { + $result = $e->getParam('result'); + $result['db'] = array( + 'status' => false, + 'message' => 'Table alter query failed: ' . $exception->getMessage(), + ); + $e->setParam('result', $result); + return false; + } + + $table = Pi::model('user_meta')->getTable(); + foreach (array('edit', 'admin', 'search', 'options') as $field) { + $sql = sprintf("ALTER TABLE %s MODIFY `{$field}` text", $table); + try { + $adapter->query($sql, 'execute'); + } catch (\Exception $exception) { + $result = $e->getParam('result'); + $result['db'] = array( + 'status' => false, + 'message' => 'Table alter query failed: ' . $exception->getMessage(), + ); + $e->setParam('result', $result); + return false; + } + } + + endif; + + if (version_compare($moduleVersion, '3.0.0-beta.3', '<')): // Add table of navigation data diff --git a/usr/module/system/src/Navigation.php b/usr/module/system/src/Navigation.php index fd83ad5bd0..00ae5db806 100644 --- a/usr/module/system/src/Navigation.php +++ b/usr/module/system/src/Navigation.php @@ -32,8 +32,8 @@ public static function front($module) $modules = Pi::service('registry')->modulelist->read('active'); unset($modules['system']); foreach ($modules as $key => $data) { - $node = Pi::service('registry')->navigation->read($key . '-front'); - if (!is_array($node)) { + $node = Pi::service('registry')->navigation->read($key . '-front') ?: array(); + if (!$node) { continue; } diff --git a/usr/module/system/template/admin/dashboard-module.phtml b/usr/module/system/template/admin/dashboard-module.phtml index 35783249d4..cd786acf64 100644 --- a/usr/module/system/template/admin/dashboard-module.phtml +++ b/usr/module/system/template/admin/dashboard-module.phtml @@ -13,7 +13,7 @@
-
+
@@ -27,7 +27,7 @@
escape($data['update']); ?>
escape($data['description']); ?> - +
escape($data['demo']); ?> diff --git a/usr/module/system/template/admin/dashboard-system.phtml b/usr/module/system/template/admin/dashboard-system.phtml index 580a056d49..02c98151f7 100644 --- a/usr/module/system/template/admin/dashboard-system.phtml +++ b/usr/module/system/template/admin/dashboard-system.phtml @@ -95,11 +95,15 @@

- Xoops/Pi Engine is a role oriented application development engine powered by Zend Framework for web and mobile, a successor of Xoops led by Ono Kazumi (onokazu), skalpa and Taiwen Jiang (phppp). - The Pi Team is inspired by them and benefits from their experiences and spirit. Pi Engine will continue to inherit and promote XOOPS brand. + Pi Engine is a role oriented application development engine for web and mobile, designed as the next generation and a successor to Xoops. + Pi is developed upon PHP and MySQL with selected third-party frameworks including but not limited to Zend Framework library, jQuery, Bootstrap and Backbone.

- The Engine is released under a New BSD License and the project is intended to promote a sustainable ecosystem that benefits all contributors and users. + Pi Project follows the philosophy of open standard, open design, open development and open structure. + Pi is born as a complete open source project and intended to build a sustainable ecosystem that benefits all contributors and users. +

+

+ Pi Team is highly inspired by the Xoops led by onokazu (Ono Kazumi), skalpa and phppp (Taiwen Jiang, or D.J.) successively since 2001 and will continue to support and promote Xoops.

diff --git a/usr/module/system/template/admin/module-available.phtml b/usr/module/system/template/admin/module-available.phtml index 7f99e14b02..a1aa5e62c9 100644 --- a/usr/module/system/template/admin/module-available.phtml +++ b/usr/module/system/template/admin/module-available.phtml @@ -28,7 +28,7 @@ - + $module) { ?> @@ -49,22 +49,22 @@
escape($module['author']['name']); ?>
- +
- +
- - + + \ No newline at end of file diff --git a/usr/theme/default/template/error-404.phtml b/usr/theme/default/template/error-404.phtml index 84f617af50..a437cbeacd 100644 --- a/usr/theme/default/template/error-404.phtml +++ b/usr/theme/default/template/error-404.phtml @@ -45,7 +45,7 @@ && $this->controller_class && $this->controller_class != $this->controller ) { - echo ' (resolves to' . $this->escape($this->controller_class) . ')'; + echo ' (resolves to ' . $this->escape($this->controller_class) . ')'; } ?> @@ -55,11 +55,11 @@ exception) && $this->exception): ?> -

escape(Pi\Security::sanitizePath($this->exception->getMessage())); ?>

+

escape(Pi::service('security')->path($this->exception->getMessage())); ?>

-    exception->getTraceAsString()); ?>
+    path($this->exception->getTraceAsString()); ?>
     
diff --git a/usr/theme/default/template/error-exception.phtml b/usr/theme/default/template/error-exception.phtml index 356fe5f612..2d184c671d 100644 --- a/usr/theme/default/template/error-exception.phtml +++ b/usr/theme/default/template/error-exception.phtml @@ -16,7 +16,7 @@
File:
-
exception->getFile()); ?>: exception->getLine(); ?>
+
path($this->exception->getFile()); ?>: exception->getLine(); ?>
Message:
@@ -24,7 +24,7 @@
Stack trace:
-
exception->getTraceAsString()); ?>
+
path($this->exception->getTraceAsString()); ?>
File:
-
getFile()); ?>: getLine(); ?>
+
path($e->getFile()); ?>: getLine(); ?>
Message:
@@ -48,7 +48,7 @@
Stack trace:
-
getTraceAsString()); ?>
+
path($e->getTraceAsString()); ?>
diff --git a/usr/theme/default/template/layout-admin.phtml b/usr/theme/default/template/layout-admin.phtml index 79dd6f7cb8..80e4746c1e 100644 --- a/usr/theme/default/template/layout-admin.phtml +++ b/usr/theme/default/template/layout-admin.phtml @@ -16,11 +16,7 @@ $module = Pi::service('module')->current(); - - - - headTitle(); ?> diff --git a/usr/theme/default/template/layout-front.phtml b/usr/theme/default/template/layout-front.phtml index e820d54afa..2920e28e1f 100644 --- a/usr/theme/default/template/layout-front.phtml +++ b/usr/theme/default/template/layout-front.phtml @@ -11,6 +11,8 @@ $this->css(array( $this->assetTheme('css/style.css'), $this->assetTheme('css/front.css'), )); + + /**#@+ * For demonstration */ @@ -26,18 +28,18 @@ $this->js($this->assetLocale('rtl.js')); - - - - headTitle(); ?> - + assemble('headTitle', 4); ?> + assemble('headMeta', 4); ?> + assemble('headLink', 4); ?> + assemble('headStyle', 4); ?> + assemble('headScript', 4); ?> @@ -84,7 +86,7 @@ $this->js($this->assetLocale('rtl.js')); -
+
@@ -178,5 +180,7 @@ $this->js($this->assetLocale('rtl.js'));
+ assemble('footScript', 4); ?> + \ No newline at end of file diff --git a/usr/theme/default/template/layout-simple.phtml b/usr/theme/default/template/layout-simple.phtml index 95578fb1a2..e739ba45a5 100644 --- a/usr/theme/default/template/layout-simple.phtml +++ b/usr/theme/default/template/layout-simple.phtml @@ -10,11 +10,7 @@ $this->css($this->assetTheme('css/style.css')); - - - - headTitle(); ?>
diff --git a/usr/theme/default/template/layout-style.phtml b/usr/theme/default/template/layout-style.phtml index ecd4ea4e05..e6f89631cf 100644 --- a/usr/theme/default/template/layout-style.phtml +++ b/usr/theme/default/template/layout-style.phtml @@ -5,12 +5,7 @@ $this->css($this->assetTheme('css/style.css')); - - - - headTitle(); ?> - diff --git a/var/config/cache.apc.php b/var/config/cache.apc.php index d35042a4c8..d29eace757 100644 --- a/var/config/cache.apc.php +++ b/var/config/cache.apc.php @@ -5,9 +5,8 @@ // Storage adapter 'adapter' => array( 'name' => 'apc', - // Options + // Options, see Zend\Cache\Storage\Adapter\ApcOptions 'options' => array( - //'namespace' => Pi::config('identifier'), ), ), // Plugin list diff --git a/var/config/cache.filesystem.php b/var/config/cache.filesystem.php index 1c20e16d24..ac5e898445 100644 --- a/var/config/cache.filesystem.php +++ b/var/config/cache.filesystem.php @@ -5,11 +5,12 @@ // Storage adapter 'adapter' => array( 'name' => 'filesystem', - // Options + // Options, see Zend\Cache\Storage\Adapter\FilesystemOptions 'options' => array( - //'namespace' => Pi::config('identifier'), - 'cache_dir' => Pi::path('cache'), - 'dir_level' => 1, + 'cache_dir' => Pi::path('cache'), + 'dir_level' => 1, + 'dir_permission' => 0700, + 'file_permission' => 0600, ), ), // Plugin list diff --git a/var/config/cache.memcached.php b/var/config/cache.memcached.php index 10a8baa7af..4bb53759d2 100644 --- a/var/config/cache.memcached.php +++ b/var/config/cache.memcached.php @@ -5,7 +5,7 @@ // Storage adapter 'adapter' => array( 'name' => 'memcached', - // Options + // Options, see Zend\Cache\Storage\Adapter\MemcachedOptions 'options' => array( 'servers' => array( array('127.0.0.1', 11211), diff --git a/var/config/host.demo.php b/var/config/host.demo.php new file mode 100644 index 0000000000..c1d36a2f11 --- /dev/null +++ b/var/config/host.demo.php @@ -0,0 +1,65 @@ + + * @version $Id$ + */ + +//Host definition file +//Paths/URLs to system folders +//URIs without a leading slash are considered relative to the current Pi Engine host location +//URIs with a leading slash are considered semi-relative (you must setup proper rewriting rules in your server conf) + +return array( + // URIs to resources + // If URI is a relative one then www root URI will be prepended + 'uri' => array( + // WWW root URI + 'www' => 'http://pi-demo', + // URI to access uploads directory + 'upload' => 'http://pi-demo/upload', + // URI to access assets directory + 'asset' => 'http://pi-demo/asset', + // URI to access static files directory + 'static' => 'http://pi-demo/static', + ), + + // Paths to resources + // If path is a relative one then www root path will be prepended + 'path' => array( + // User extension directory + 'usr' => '/path/to/pi-demo/usr', + // Application module directory + 'module' => '/path/to/pi-demo/usr/module', + // Theme directory + 'theme' => '/path/to/pi-demo/usr/theme', + // Path to vendor library directory + 'vendor' => '/path/to/pi-demo/lib/vendor', + + // Path to uploads directory + 'upload' => '/path/to/pi-demo-demo/upload', + // Path to assets directory + 'asset' => '/path/to/pi-demo-demo/asset', + // Path to static files directory + 'static' => '/path/to/pi-demo-demo/static', + + // User data directory + 'var' => '/path/to/pi-demo-demo/var', + // Path to global configuration directory + 'config' => '/path/to/pi-demo-demo/config', + // Path to cache files directory + 'cache' => '/path/to/pi-demo-demo/cache', + // Path to logs directory + 'log' => '/path/to/pi-demo-demo/log', + ) +); diff --git a/var/config/hosts.php b/var/config/hosts.php new file mode 100644 index 0000000000..fd4d6721b3 --- /dev/null +++ b/var/config/hosts.php @@ -0,0 +1,59 @@ + + * @version $Id$ + */ + +return array( + // Alias of hosts + 'alias' => array( + 'http://pi' => 'default', + 'http://www.pi' => 'default', + 'http://localhost/pi/www' => 'default', + 'http://pi-demo' => 'demo', + 'http://www.pi-demo' => 'demo', + ), + // Host specifications + 'hosts' => array( + // Specifications defined by files + 'default' => __DIR__ . '/host.php', + 'demo' => __DIR__ . '/host.demo.php', + /* + // Specifications defined instantly + 'default' => array( + // URIs to resources + 'uri' => array( + 'www' => 'http://pi', + 'upload' => 'http://pi/upload', + 'asset' => 'http://pi/asset', + 'static' => 'http://pi/static', + ), + // Paths to resources + 'path' => array( + 'usr' => '/path/to/pi/usr', + 'var' => '/path/to/pi/var', + 'module' => '/path/to/pi/usr/module', + 'theme' => '/path/to/pi/usr/theme', + 'upload' => '/path/to/pi/www/upload', + 'asset' => '/path/to/pi/www/asset', + 'static' => '/path/to/pi/www/static', + 'vendor' => '/path/to/pi/lib/vendor', + 'config' => '/path/to/pi/var/config', + 'cache' => '/path/to/pi/var/cache', + 'log' => '/path/to/pi/var/log', + ), + ), + */ + ), +); diff --git a/var/config/resource.security.php b/var/config/resource.security.php index 31c78b3e27..816695dcab 100644 --- a/var/config/resource.security.php +++ b/var/config/resource.security.php @@ -3,33 +3,21 @@ return array( // IP check: deny 'bad' IPs, approve 'good' IPs - 'ip' => array( - //'bad' => '^127.0|^10.0', - 'good' => '^127.0|^10.0', - 'checkProxy' => true, - ), + 'ip' => true, // Super GLOBALS - 'globals' => 'GLOBALS, _SESSION, _GET, _POST, _COOKIE, _REQUEST, _SERVER, _ENV, _FILES', + 'globals' => true, // XSS check - 'xss' => array( - 'post' => true, - 'get' => true, - 'filter' => 1, - 'length' => 32, - ), + 'xss' => true, // Enable DoS protection on HTTP_USER_AGENT - 'dos' => 1, + 'dos' => true, // crawl bots protection on HTTP_USER_AGENT - 'bot' => 'bad bot|evil bot', + 'bot' => true, // Both DoS and bot proection on HTTP_USER_AGENT // Note: disable above 'dos' and 'bot' if the below option is enabled - 'agent' => array( - 'dos' => 1, - 'bot' => 'bad bot|evil bot', - ), + 'agent' => true, ); diff --git a/var/config/service.database.php b/var/config/service.database.php index af3841fce1..88e8ea08cf 100644 --- a/var/config/service.database.php +++ b/var/config/service.database.php @@ -21,18 +21,26 @@ 'dsn' => 'mysql:dbname=pi;host=localhost', 'username' => 'root', 'password' => '', - 'options' => array( + + // driver_options. All attributes must be valid. + // @see http://www.php.net/manual/en/pdo.setattribute.php + 'driver_options' => array( PDO::MYSQL_ATTR_INIT_COMMAND => 'SET NAMES utf8 COLLATE utf8_general_ci', PDO::ATTR_PERSISTENT => false, + + // Custom PDOstatement class. Optional, default as Pi\Db\Adapter\Driver\Statement + // PDO::ATTR_STATEMENT_CLASS => array('PDOstatement'), + ), + + // Add custom options in this section + 'options' => array( ), - // To build connection upload. Optional, default as true - 'connect_onload' => true, ), // Database schema 'schema' => 'pi', // Prefix for all tables - 'table_prefix' => 'xc6c_', + 'table_prefix' => 'x2d1_', // Prefix for system tables; module identifiers will be used for its tables, respectively 'core_prefix' => 'core_' ); diff --git a/var/config/service.security.php b/var/config/service.security.php new file mode 100644 index 0000000000..daca0a0ea0 --- /dev/null +++ b/var/config/service.security.php @@ -0,0 +1,32 @@ + array( + 'bad' => '', + 'good' => '^127.0|^10.0', + 'checkProxy' => true, + ), + + // Super GLOBALS + 'globals' => array('GLOBALS', '_SESSION', '_GET', '_POST', '_COOKIE', '_REQUEST', '_SERVER', '_ENV', '_FILES'), + + // XSS check + 'xss' => array( + 'post' => true, + 'get' => true, + 'filter' => true, + 'length' => 32, + ), + + // crawl bots protection on HTTP_USER_AGENT + 'bot' => array('bad bot', 'evil bot'), + + // Both DoS and bot proection on HTTP_USER_AGENT + // Note: disable above 'dos' and 'bot' if the below option is enabled + 'agent' => array( + 'dos' => true, + 'bot' => array('bad bot', 'evil bot'), + ), +); diff --git a/var/config/service.session.php b/var/config/service.session.php index 8678aae059..0e6dc87928 100644 --- a/var/config/service.session.php +++ b/var/config/service.session.php @@ -31,7 +31,8 @@ // Validators: validator class => data 'validators' => array( 'Zend\\Session\\Validator\\HttpUserAgent' => isset($_SERVER['HTTP_USER_AGENT']) ? $_SERVER['HTTP_USER_AGENT'] : null, - 'Zend\\Session\\Validator\\RemoteAddr' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null, + // The following RemoteAddr validator must be disabled when "RememberMe" is enabled + //'Zend\\Session\\Validator\\RemoteAddr' => isset($_SERVER['REMOTE_ADDR']) ? $_SERVER['REMOTE_ADDR'] : null, ), ), diff --git a/var/log/index.html b/var/log/index.html new file mode 100644 index 0000000000..990cbd6037 --- /dev/null +++ b/var/log/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/www/asset/index.html b/www/asset/index.html new file mode 100644 index 0000000000..990cbd6037 --- /dev/null +++ b/www/asset/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/www/script/editor/index.html b/www/script/editor/index.html new file mode 100644 index 0000000000..990cbd6037 --- /dev/null +++ b/www/script/editor/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/www/script/index.html b/www/script/index.html new file mode 100644 index 0000000000..990cbd6037 --- /dev/null +++ b/www/script/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/www/setup/dist/service.database.php.dist b/www/setup/dist/service.database.php.dist index d2d53bfa82..d626907740 100644 --- a/www/setup/dist/service.database.php.dist +++ b/www/setup/dist/service.database.php.dist @@ -34,8 +34,6 @@ return array( // Add custom options in this section 'options' => array( - // To build connection upload. Optional, default as true - 'connect_onload' => true, ), ), diff --git a/www/setup/src/Controller/Finish.php b/www/setup/src/Controller/Finish.php index b13a0a4498..5ab8acd6ec 100644 --- a/www/setup/src/Controller/Finish.php +++ b/www/setup/src/Controller/Finish.php @@ -99,9 +99,9 @@ public function indexAction() $readPaths .= ""; $message = <<<'HTML' -

Congratulatons, everything is done! Ready to visit your site?

+

Congratulatons! The system is set up successfully. Click to visit your website!

Security advisory

-
    For security considerations you are strongly recommended to complete the following actions: +
      For security considerations please make sure the following operations are done:
    1. Remove the installation folder %s from your server.
    2. Set configuration directories and files to readonly: %s
    diff --git a/www/static/avatar/avatar.jpg b/www/static/avatar/avatar.jpg deleted file mode 100644 index e804687863..0000000000 Binary files a/www/static/avatar/avatar.jpg and /dev/null differ diff --git a/www/static/avatar/index.html b/www/static/avatar/index.html new file mode 100644 index 0000000000..990cbd6037 --- /dev/null +++ b/www/static/avatar/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/www/static/css/index.html b/www/static/css/index.html new file mode 100644 index 0000000000..990cbd6037 --- /dev/null +++ b/www/static/css/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/www/static/font/index.html b/www/static/font/index.html new file mode 100644 index 0000000000..990cbd6037 --- /dev/null +++ b/www/static/font/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/www/static/image/index.html b/www/static/image/index.html new file mode 100644 index 0000000000..990cbd6037 --- /dev/null +++ b/www/static/image/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/www/static/index.html b/www/static/index.html new file mode 100644 index 0000000000..990cbd6037 --- /dev/null +++ b/www/static/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/www/static/js/index.html b/www/static/js/index.html new file mode 100644 index 0000000000..990cbd6037 --- /dev/null +++ b/www/static/js/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/www/static/media/index.html b/www/static/media/index.html new file mode 100644 index 0000000000..990cbd6037 --- /dev/null +++ b/www/static/media/index.html @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/www/static/vendor/backbone/backbone-min.js b/www/static/vendor/backbone/backbone-min.js index 90bc0f776e..3541019c58 100644 --- a/www/static/vendor/backbone/backbone-min.js +++ b/www/static/vendor/backbone/backbone-min.js @@ -1,56 +1,4 @@ -// Backbone.js 0.9.2 - -// (c) 2010-2012 Jeremy Ashkenas, DocumentCloud Inc. -// Backbone may be freely distributed under the MIT license. -// For all details and documentation: -// http://backbonejs.org -(function(){var l=this,y=l.Backbone,z=Array.prototype.slice,A=Array.prototype.splice,g;g="undefined"!==typeof exports?exports:l.Backbone={};g.VERSION="0.9.2";var f=l._;!f&&"undefined"!==typeof require&&(f=require("underscore"));var i=l.jQuery||l.Zepto||l.ender;g.setDomLibrary=function(a){i=a};g.noConflict=function(){l.Backbone=y;return this};g.emulateHTTP=!1;g.emulateJSON=!1;var p=/\s+/,k=g.Events={on:function(a,b,c){var d,e,f,g,j;if(!b)return this;a=a.split(p);for(d=this._callbacks||(this._callbacks= -{});e=a.shift();)f=(j=d[e])?j.tail:{},f.next=g={},f.context=c,f.callback=b,d[e]={tail:g,next:j?j.next:f};return this},off:function(a,b,c){var d,e,h,g,j,q;if(e=this._callbacks){if(!a&&!b&&!c)return delete this._callbacks,this;for(a=a?a.split(p):f.keys(e);d=a.shift();)if(h=e[d],delete e[d],h&&(b||c))for(g=h.tail;(h=h.next)!==g;)if(j=h.callback,q=h.context,b&&j!==b||c&&q!==c)this.on(d,j,q);return this}},trigger:function(a){var b,c,d,e,f,g;if(!(d=this._callbacks))return this;f=d.all;a=a.split(p);for(g= -z.call(arguments,1);b=a.shift();){if(c=d[b])for(e=c.tail;(c=c.next)!==e;)c.callback.apply(c.context||this,g);if(c=f){e=c.tail;for(b=[b].concat(g);(c=c.next)!==e;)c.callback.apply(c.context||this,b)}}return this}};k.bind=k.on;k.unbind=k.off;var o=g.Model=function(a,b){var c;a||(a={});b&&b.parse&&(a=this.parse(a));if(c=n(this,"defaults"))a=f.extend({},c,a);b&&b.collection&&(this.collection=b.collection);this.attributes={};this._escapedAttributes={};this.cid=f.uniqueId("c");this.changed={};this._silent= -{};this._pending={};this.set(a,{silent:!0});this.changed={};this._silent={};this._pending={};this._previousAttributes=f.clone(this.attributes);this.initialize.apply(this,arguments)};f.extend(o.prototype,k,{changed:null,_silent:null,_pending:null,idAttribute:"id",initialize:function(){},toJSON:function(){return f.clone(this.attributes)},get:function(a){return this.attributes[a]},escape:function(a){var b;if(b=this._escapedAttributes[a])return b;b=this.get(a);return this._escapedAttributes[a]=f.escape(null== -b?"":""+b)},has:function(a){return null!=this.get(a)},set:function(a,b,c){var d,e;f.isObject(a)||null==a?(d=a,c=b):(d={},d[a]=b);c||(c={});if(!d)return this;d instanceof o&&(d=d.attributes);if(c.unset)for(e in d)d[e]=void 0;if(!this._validate(d,c))return!1;this.idAttribute in d&&(this.id=d[this.idAttribute]);var b=c.changes={},h=this.attributes,g=this._escapedAttributes,j=this._previousAttributes||{};for(e in d){a=d[e];if(!f.isEqual(h[e],a)||c.unset&&f.has(h,e))delete g[e],(c.silent?this._silent: -b)[e]=!0;c.unset?delete h[e]:h[e]=a;!f.isEqual(j[e],a)||f.has(h,e)!=f.has(j,e)?(this.changed[e]=a,c.silent||(this._pending[e]=!0)):(delete this.changed[e],delete this._pending[e])}c.silent||this.change(c);return this},unset:function(a,b){(b||(b={})).unset=!0;return this.set(a,null,b)},clear:function(a){(a||(a={})).unset=!0;return this.set(f.clone(this.attributes),a)},fetch:function(a){var a=a?f.clone(a):{},b=this,c=a.success;a.success=function(d,e,f){if(!b.set(b.parse(d,f),a))return!1;c&&c(b,d)}; -a.error=g.wrapError(a.error,b,a);return(this.sync||g.sync).call(this,"read",this,a)},save:function(a,b,c){var d,e;f.isObject(a)||null==a?(d=a,c=b):(d={},d[a]=b);c=c?f.clone(c):{};if(c.wait){if(!this._validate(d,c))return!1;e=f.clone(this.attributes)}a=f.extend({},c,{silent:!0});if(d&&!this.set(d,c.wait?a:c))return!1;var h=this,i=c.success;c.success=function(a,b,e){b=h.parse(a,e);if(c.wait){delete c.wait;b=f.extend(d||{},b)}if(!h.set(b,c))return false;i?i(h,a):h.trigger("sync",h,a,c)};c.error=g.wrapError(c.error, -h,c);b=this.isNew()?"create":"update";b=(this.sync||g.sync).call(this,b,this,c);c.wait&&this.set(e,a);return b},destroy:function(a){var a=a?f.clone(a):{},b=this,c=a.success,d=function(){b.trigger("destroy",b,b.collection,a)};if(this.isNew())return d(),!1;a.success=function(e){a.wait&&d();c?c(b,e):b.trigger("sync",b,e,a)};a.error=g.wrapError(a.error,b,a);var e=(this.sync||g.sync).call(this,"delete",this,a);a.wait||d();return e},url:function(){var a=n(this,"urlRoot")||n(this.collection,"url")||t(); -return this.isNew()?a:a+("/"==a.charAt(a.length-1)?"":"/")+encodeURIComponent(this.id)},parse:function(a){return a},clone:function(){return new this.constructor(this.attributes)},isNew:function(){return null==this.id},change:function(a){a||(a={});var b=this._changing;this._changing=!0;for(var c in this._silent)this._pending[c]=!0;var d=f.extend({},a.changes,this._silent);this._silent={};for(c in d)this.trigger("change:"+c,this,this.get(c),a);if(b)return this;for(;!f.isEmpty(this._pending);){this._pending= -{};this.trigger("change",this,a);for(c in this.changed)!this._pending[c]&&!this._silent[c]&&delete this.changed[c];this._previousAttributes=f.clone(this.attributes)}this._changing=!1;return this},hasChanged:function(a){return!arguments.length?!f.isEmpty(this.changed):f.has(this.changed,a)},changedAttributes:function(a){if(!a)return this.hasChanged()?f.clone(this.changed):!1;var b,c=!1,d=this._previousAttributes,e;for(e in a)if(!f.isEqual(d[e],b=a[e]))(c||(c={}))[e]=b;return c},previous:function(a){return!arguments.length|| -!this._previousAttributes?null:this._previousAttributes[a]},previousAttributes:function(){return f.clone(this._previousAttributes)},isValid:function(){return!this.validate(this.attributes)},_validate:function(a,b){if(b.silent||!this.validate)return!0;var a=f.extend({},this.attributes,a),c=this.validate(a,b);if(!c)return!0;b&&b.error?b.error(this,c,b):this.trigger("error",this,c,b);return!1}});var r=g.Collection=function(a,b){b||(b={});b.model&&(this.model=b.model);b.comparator&&(this.comparator=b.comparator); -this._reset();this.initialize.apply(this,arguments);a&&this.reset(a,{silent:!0,parse:b.parse})};f.extend(r.prototype,k,{model:o,initialize:function(){},toJSON:function(a){return this.map(function(b){return b.toJSON(a)})},add:function(a,b){var c,d,e,g,i,j={},k={},l=[];b||(b={});a=f.isArray(a)?a.slice():[a];c=0;for(d=a.length;c=b))this.iframe=i('