Updated libraries to latest version

This commit is contained in:
Cliff Ingham 2014-08-18 15:53:40 -04:00
parent 8b4eacd1e1
commit baad9f58c1
46 changed files with 1608 additions and 1419 deletions

2
.gitignore vendored
View File

@ -1,4 +1,6 @@
configuration.inc
site_config.inc
build
dist
data/sessions/*

6
.gitmodules vendored
View File

@ -1,3 +1,9 @@
[submodule "html/js/yui3"]
path = html/js/yui3
url = https://github.com/yui/yui3.git
[submodule "libraries/phpCAS"]
path = libraries/phpCAS
url = https://github.com/Jasig/phpCAS.git
[submodule "libraries/zf2"]
path = libraries/zf2
url = https://github.com/zendframework/zf2.git

View File

@ -1,45 +1,24 @@
<?php
/**
* Used to keep sessions on the same webserver seperate;
*/
define('APPLICATION_NAME','application_name');
/**
* Where on the filesystem this application is installed
*/
define('APPLICATION_HOME','/var/www/sites/application_name');
define('APPLICATION_HOME', __DIR__);
define('BLOSSOM', APPLICATION_HOME.'/libraries/Blossom');
define('ZEND', APPLICATION_HOME.'/libraries/zf2/library/Zend');
/**
* Where on the filesystem the framework is installed.
*/
define('FRAMEWORK',APPLICATION_HOME.'/libraries/framework');
/**
* This needs to point to the library directory inside your
* installation of the ZendFramework
* http://framework.zend.com
*/
define('ZEND',APPLICATION_HOME.'/libraries/ZendFramework/library');
ini_set('include_path','.'.PATH_SEPARATOR.ZEND);
require_once 'Zend/Loader/Autoloader.php';
Zend_Loader_Autoloader::getInstance();
/**
* The URL to get to this site
* Do NOT use a trailing slash
*/
define('BASE_URL','http://localhost/application_name');
define('BASE_URI', '/application_name');
/**
* Used when there's an error on the site. The Framework will
* print out a nice error message, encouraging users to report any problems
* See: FRAMEWORK/ITSFunctions.inc
* Multi-Site support
*
* This is also the default Admin user information that gets added to the database
* To allow multiple sites to use this same install base,
* define the SITE_HOME variable in the Apache config for each
* site you want to host.
*
* SITE_HOME is the directory where all site-specific data and
* configuration are stored. For backup purposes, backing up this
* directory would be sufficient for an easy full restore.
*/
define('ADMINISTRATOR_NAME','Site Admin');
define('ADMINISTRATOR_EMAIL','admin@servername.com');
define('SITE_HOME', !empty($_SERVER['SITE_HOME']) ? $_SERVER['SITE_HOME'] : __DIR__.'/data');
include SITE_HOME.'/site_config.inc';
/**
* Set how we want to handle errors
@ -47,7 +26,7 @@ define('ADMINISTRATOR_EMAIL','admin@servername.com');
*
* If you do not define error handling to PHP_DEFAULT
* the custom error handlers kick in. All of the custom error display
* frunctions are in FRAMEWORK/globalFunctions.inc. The custom error
* frunctions are in BLOSSOM/Classes/Error.php. The custom error
* function decide what to do based on $ERROR_REPORING array values
*
* PRETTY_PRINT - Display a message in the browser
@ -58,6 +37,7 @@ define('ADMINISTRATOR_EMAIL','admin@servername.com');
define('ERROR_REPORTING','PHP_DEFAULT');
//define('ERROR_REPORTING','CUSTOM');
//$ERROR_REPORTING = array('PRETTY_PRINT','SKIDDER');
/**
* Skidder is a web service for error notifications. Error reporting supports
* posting errors to a Skidder server. You must register for an application_id
@ -66,46 +46,24 @@ define('ERROR_REPORTING','PHP_DEFAULT');
//define('SKIDDER_URL','http://localhost/skidder/home.php');
//define('SKIDDER_APPLICATION_ID',);
//-------------------------------------------------------------------
// Bootstrap code
// No editing is usually needed after this point
//-------------------------------------------------------------------
/**
* Database Setup
* Refer to the PDO documentation for DSN sytnax for your database type
* http://www.php.net/manual/en/pdo.drivers.php
* Enable autoloading for the PHP libraries
*/
define('DB_ADAPTER','Pdo_Mysql');
define('DB_HOST','localhost');
define('DB_NAME',APPLICATION_NAME);
define('DB_USER',APPLICATION_NAME);
define('DB_PASS','password');
/**
* Directory Configuration
*
* This is required in order to use the LDAP or ADS authentication
* If you do not want to use external authentication, you can comment this out
*/
// Example for ADS style authentication
define('DIRECTORY_SERVER','ldaps://example.org:636');
define('DIRECTORY_BASE_DN','OU=Department,DC=example,DC=org');
define('DIRECTORY_USERNAME_ATTRIBUTE', 'CN');
define('DIRECTORY_USER_BINDING','{username}@bloomington.in.gov');
define('DIRECTORY_ADMIN_BINDING', 'admin@bloomington.in.gov');
define('DIRECTORY_ADMIN_PASS','password');
// Example for LDAP style authentication
//define('DIRECTORY_SERVER','ldaps://example.org:636');
//define('DIRECTORY_BASE_DN','ou=people,o=ldap.domain.somewhere');
//define('DIRECTORY_USERNAME_ATTRIBUTE', 'uid');
//define('DIRECTORY_USER_BINDING','uid={username},'.DIRECTORY_BASE_DN);
//define('DIRECTORY_ADMIN_BINDING', 'uid=admin,'.DIRECTORY_BASE_DN);
//define('DIRECTORY_ADMIN_PASS','password');
define('YUI', BASE_URI.'/js/yui3/build');
/**
* Import global functions that we use for many applications we write
*/
include FRAMEWORK.'/globalFunctions.php';
spl_autoload_register('autoload');
require_once ZEND.'/Loader/AutoloaderFactory.php';
$config = [
'Zend\Loader\StandardAutoloader' => [
'namespaces' => [
'Application' => APPLICATION_HOME,
'Blossom' => BLOSSOM,
'Zend' => ZEND
]
]
];
Zend\Loader\AutoloaderFactory::factory($config);
/**
* Session Startup
@ -113,27 +71,21 @@ spl_autoload_register('autoload');
* We only want sessions when PHP code is executed from the webserver
*/
if (!defined('STDIN')) {
ini_set('session.save_path',APPLICATION_HOME.'/data/sessions');
ini_set('session.save_path', SITE_HOME.'/sessions');
session_start();
}
/**
* CAS authentication http://www.jasig.org/cas
*
* https://wiki.jasig.org/display/CASC/phpCAS
*
* phpCAS is a PHP library for handling the calls to the CAS service
* It is the official library, part of the Jasig CAS project
*/
define('CAS', APPLICATION_HOME.'/libraries/phpCAS');
define('CAS_SERVER','cas.somewhere.org');
define('CAS_URI','cas');
if (ERROR_REPORTING != 'PHP_DEFAULT') {
set_error_handler ('Blossom\Classes\Error::customErrorHandler');
set_exception_handler('Blossom\Classes\Error::customExceptionHandler');
}
/**
* Load the Zend_Acl
* Access control is going to handled using the Zend_Acl
* We only need to load it, if someone is logged in
*/
if (isset($_SESSION['USER'])) {
include APPLICATION_HOME.'/access_control.inc';
}
include APPLICATION_HOME.'/access_control.inc';
/**
* Grab a timestamp for calculating process time
*/
$startTime = microtime(1);

View File

@ -0,0 +1,76 @@
<?php
define('APPLICATION_NAME','application');
/**
* The URL to get to this site
* Do NOT use a trailing slash
*/
define('BASE_URL','http://localhost/application');
define('BASE_URI','/application');
/**
* Used when there's an error on the site. The Framework will
* print out a nice error message, encouraging users to report any problems
* See: Blossom\Classes\Error
*/
define('ADMINISTRATOR_NAME','Site Admin');
define('ADMINISTRATOR_EMAIL','admin@servername.com');
/**
* Database Setup
* Refer to the PDO documentation for DSN sytnax for your database type
* http://www.php.net/manual/en/pdo.drivers.php
*/
define('DB_ADAPTER','Pdo_Mysql');
define('DB_HOST','localhost');
define('DB_NAME','application');
define('DB_USER','application');
define('DB_PASS','password');
/**
* Directory Configuration
*
* This supports doing user authentication from multiple external
* directories, such as LDAP or ADS. This is required since city staff
* are in a seperate LDAP directory from public user accounts.
* Classes that implement ExternalIdentity should have an entry here.
*
* See: ExternalIdentity
*/
// Example for ADS style authentication
$DIRECTORY_CONFIG = array(
// 'Employee'=>array(
// 'DIRECTORY_SERVER'=>'ldaps://example.org:636',
// 'DIRECTORY_BASE_DN'=>'OU=Department,DC=example,DC=org',
// 'DIRECTORY_USERNAME_ATTRIBUTE'=>'CN',
// 'DIRECTORY_USER_BINDING'=>'{username}@example.org',
// 'DIRECTORY_ADMIN_BINDING'=>'admin@example.org',
// 'DIRECTORY_ADMIN_PASS'=>'password'
// )
);
// Example for LDAP style authentication
//$DIRECTORY_CONFIG = array(
// 'Employee'=>array(
// 'DIRECTORY_SERVER'=>'ldaps://example.org:636');
// 'DIRECTORY_BASE_DN'=>'ou=people,o=ldap.domain.somewhere');
// 'DIRECTORY_USERNAME_ATTRIBUTE'=>'uid');
// 'DIRECTORY_USER_BINDING'=>'uid={username},'.DIRECTORY_BASE_DN);
// 'DIRECTORY_ADMIN_BINDING'=>'uid=admin,'.DIRECTORY_BASE_DN);
// 'DIRECTORY_ADMIN_PASS'=>'password');
// )
//);
/**
* CAS authentication http://www.jasig.org/cas
*
* https://wiki.jasig.org/display/CASC/phpCAS
*
* phpCAS is a PHP library for handling the calls to the CAS service
* It is the official library, part of the Jasig CAS project
*/
//define('CAS',APPLICATION_HOME.'/libraries/phpCAS');
//define('CAS_SERVER','cas.somewhere.org');
//define('CAS_URI','cas');
define('DATE_FORMAT', 'n/j/Y H:i:s');
define('YUI', BASE_URI.'/js/yui3/build');

View File

@ -0,0 +1,212 @@
<?php
/**
* @copyright 2011-2013 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
namespace Blossom\Classes;
use Zend\Db\Sql\Sql;
abstract class ActiveRecord
{
protected $tablename;
protected $data = array();
const MYSQL_DATE_FORMAT = 'Y-m-d H:i:s';
abstract public function validate();
/**
* Callback from TableGateway
*/
public function exchangeArray($data)
{
$this->data = $data;
}
/**
* Writes the database back to the database
*/
protected function save()
{
$this->validate();
$zend_db = Database::getConnection();
$sql = new Sql($zend_db, $this->tablename);
if ($this->getId()) {
$update = $sql->update()
->set($this->data)
->where(array('id'=>$this->getId()));
$sql->prepareStatementForSqlObject($update)->execute();
}
else {
$insert = $sql->insert()->values($this->data);
$sql->prepareStatementForSqlObject($insert)->execute();
$this->data['id'] = $zend_db->getDriver()->getLastGeneratedValue();
}
}
/**
* Removes this record from the database
*/
protected function delete()
{
if ($this->getId()) {
$sql = new Sql(Database::getConnection(), $this->tablename);
$delete = $sql->delete()->where(['id'=>$this->getId()]);
$sql->prepareStatementForSqlObject($delete)->execute();
}
}
/**
* Returns any field stored in $data
*
* @param string $fieldname
*/
protected function get($fieldname)
{
if (isset($this->data[$fieldname])) {
return $this->data[$fieldname];
}
}
/**
* @param string $fieldname
* @param string $value
*/
protected function set($fieldname, $value)
{
$value = trim($value);
$this->data[$fieldname] = $value ? $value : null;
}
/**
* Returns the date/time in the desired format
*
* Format is specified using PHP's date() syntax
* http://www.php.net/manual/en/function.date.php
* If no format is given, the database's raw data is returned
*
* @param string $field
* @param string $format
* @param DateTimeZone $timezone
* @return string
*/
protected function getDateData($dateField, $format=null, \DateTimeZone $timezone=null)
{
if (isset($this->data[$dateField])) {
if ($format) {
$date = new \DateTime($this->data[$dateField]);
if ($timezone) { $date->setTimezone($timezone); }
return $date->format($format);
}
else {
return $this->data[$dateField];
}
}
}
/**
* Sets a date
*
* Dates should be in DATE_FORMAT, set in configuration.inc
* If we cannot parse the string using DATE_FORMAT, we will
* fall back to trying something strtotime() understands
* http://www.php.net/manual/en/function.strtotime.php
*
* @param string $dateField
* @param string $date
*/
protected function setDateData($dateField, $date)
{
$date = trim($date);
if ($date) {
$d = \DateTime::createFromFormat(DATE_FORMAT, $date);
if (!$d) {
try {
$d = new \DateTime($date);
}
catch (Exception $e) {
throw new \Exception('unknownDateFormat');
}
}
$this->data[$dateField] = $d->format(self::MYSQL_DATE_FORMAT);
}
else {
$this->data[$dateField] = null;
}
}
/**
* Loads and returns an object for a foreign key _id field
*
* Will cache the object in a protected variable to avoid multiple database
* lookups. Make sure to declare a protected variable matching the class
*
* @param string $class Fully namespaced classname
* @param string $field
*/
protected function getForeignKeyObject($class, $field)
{
$var = preg_replace('/_id$/', '', $field);
if (!$this->$var && isset($this->data[$field])) {
$this->$var = new $class($this->data[$field]);
}
return $this->$var;
}
/**
* Verifies and saves the ID for a foreign key field
*
* Loads the object record for the foreign key and caches
* the object in a private variable
*
* @param string $class Fully namespaced classname
* @param string $field Name of field to set
* @param string $id The value to set
*/
protected function setForeignKeyField($class, $field, $id)
{
$id = trim($id);
$var = preg_replace('/_id$/', '', $field);
if ($id) {
$this->$var = new $class($id);
$this->data[$field] = $this->$var->getId();
}
else {
$this->$field = null;
$this->data[$field] = null;
}
}
/**
* Verifies and saves the ID for a foreign key object
*
* Caches the object in a private variable and sets
* the ID value in the data
*
* @param string $class Fully namespaced classname
* @param string $field Name of field to set
* @param Object $object Value to set
*/
protected function setForeignKeyObject($class, $field, $object)
{
if ($object instanceof $class) {
$var = preg_replace('/_id$/', '', $field);
$this->data[$field] = $object->getId();
$this->$var = $object;
}
else {
throw new \Exception('Object does not match the given class');
}
}
/**
* Returns whether the value can be an ID for a record
*
* return @bool
*/
public static function isId($id)
{
return ((is_int($id) && $id>0) || (is_string($id) && ctype_digit($id)));
}
}

View File

@ -0,0 +1,98 @@
<?php
/**
* Represents a block of content in a template
*
* Blocks are partial view scripts.
* They are contained in APPLICATION/blocks
* They are organized by $outputFormat
* APPLICATION_HOME/blocks/html/...
* APPLICATION_HOME/blocks/xml/...
* APPLICATION_HOME/blocks/json/..
*
* @copyright 2006-2013 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
namespace Blossom\Classes;
class Block extends View
{
private $file;
private $template;
/**
* Establishes the block script to use for rendering
*
* Blocks are files contained in the base path of:
* APPLICATION_HOME/blocks/$outpuform
*
* @param string $file
* @param array $vars An associative array of variables to set
*/
public function __construct($file,array $vars=null)
{
parent::__construct($vars);
$this->file = $file;
}
/**
* Includes the block script and returns the output as a string
*
* We allow for passing the Template that this block is being rendered in.
* This allows the blocks to update information in the template on the fly.
* This is most commonly used in adding script urls to the Template
*
* @param string $outputFormat
* @return string
*/
public function render($outputFormat='html', Template $template=null)
{
$block = "/blocks/$outputFormat/{$this->file}";
$this->template = $template;
if (is_file(SITE_HOME.$block)) {
$file = SITE_HOME.$block;
}
elseif (is_file(APPLICATION_HOME.$block)) {
$file = APPLICATION_HOME.$block;
}
elseif (is_file(BLOSSOM.$block)) {
$file = BLOSSOM.$block;
}
else {
throw new \Exception('unknownBlock/'.$this->file);
}
ob_start();
include $file;
return ob_get_clean();
}
/**
* @return string
*/
public function getFile()
{
return $this->file;
}
/**
* Includes the given filename.
*
* Supports SITE_HOME overriding.
* Specify a relative path starting from /blocks/
* $file paths should not start with a slash.
*
* @param string $file
*/
public function _include($file)
{
if (is_file(SITE_HOME."/blocks/$file")) {
include SITE_HOME."/blocks/$file";
}
else {
include APPLICATION_HOME."/blocks/$file";
}
}
}

View File

@ -0,0 +1,20 @@
<?php
/**
* @copyright 2012-2013 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
namespace Blossom\Classes;
abstract class Controller
{
protected $template;
abstract public function index();
public function __construct(Template &$template)
{
$this->template = $template;
$this->template->controller = get_class($this);
}
}

View File

@ -2,10 +2,13 @@
/**
* Singleton for the Database connection
*
* @copyright 2006-2009 City of Bloomington, Indiana
* @copyright 2006-2013 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
namespace Blossom\Classes;
use Zend\Db\Adapter\Adapter;
class Database
{
private static $connection;
@ -21,13 +24,13 @@ class Database
}
if (!self::$connection) {
try {
$parameters = array('host'=>DB_HOST,
$parameters = array('driver' =>DB_ADAPTER,
'hostname'=>DB_HOST,
'username'=>DB_USER,
'password'=>DB_PASS,
'dbname'=>DB_NAME,
'options'=>array(Zend_Db::AUTO_QUOTE_IDENTIFIERS=>false));
self::$connection = Zend_Db::factory(DB_ADAPTER,$parameters);
self::$connection->getConnection();
'database' =>DB_NAME,
'charset' =>'utf8');
self::$connection = new Adapter($parameters);
}
catch (Exception $e) {
die($e->getMessage());

View File

@ -0,0 +1,122 @@
<?php
/**
* A class for working with entries in LDAP.
*
* This class is written specifically for the City of Bloomington's
* LDAP layout. If you are going to be doing LDAP authentication
* with your own LDAP server, you will probably need to customize
* the fields used in this class.
*
* @copyright 2011-2013 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
namespace Blossom\Classes;
class Employee implements ExternalIdentity
{
private static $connection;
private $config;
private $entry;
/**
* @param array $config
* @param string $username
* @param string $password
* @throws Exception
*/
public static function authenticate($username,$password)
{
global $DIRECTORY_CONFIG;
$config = $DIRECTORY_CONFIG['Employee'];
$bindUser = sprintf(str_replace('{username}','%s',$config['DIRECTORY_USER_BINDING']),$username);
$connection = ldap_connect($config['DIRECTORY_SERVER']) or die("Couldn't connect to ADS");
ldap_set_option($connection, LDAP_OPT_PROTOCOL_VERSION, 3);
if (ldap_bind($connection,$bindUser,$password)) {
return true;
}
}
/**
* Loads an entry from the LDAP server for the given user
*
* @param array $config
* @param string $username
*/
public function __construct($username)
{
global $DIRECTORY_CONFIG;
$this->config = $DIRECTORY_CONFIG['Employee'];
$this->openConnection();
$result = ldap_search(
self::$connection,
$this->config['DIRECTORY_BASE_DN'],
$this->config['DIRECTORY_USERNAME_ATTRIBUTE']."=$username"
);
if (ldap_count_entries(self::$connection,$result)) {
$entries = ldap_get_entries(self::$connection, $result);
$this->entry = $entries[0];
}
else {
throw new \Exception('ldap/unknownUser');
}
}
/**
* Creates the connection to the LDAP server
*/
private function openConnection()
{
if (!self::$connection) {
if (self::$connection = ldap_connect($this->config['DIRECTORY_SERVER'])) {
ldap_set_option(self::$connection, LDAP_OPT_PROTOCOL_VERSION,3);
ldap_set_option(self::$connection, LDAP_OPT_REFERRALS, 0);
if (!empty($this->config['DIRECTORY_ADMIN_BINDING'])) {
if (!ldap_bind(
self::$connection,
$this->config['DIRECTORY_ADMIN_BINDING'],
$this->config['DIRECTORY_ADMIN_PASS']
)) {
throw new \Exception(ldap_error(self::$connection));
}
}
else {
if (!ldap_bind(self::$connection)) {
throw new \Exception(ldap_error(self::$connection));
}
}
}
else {
throw new \Exception(ldap_error(self::$connection));
}
}
}
/**
* @return string
*/
public function getUsername() { return $this->get('cn'); }
public function getFirstname() { return $this->get('givenname'); }
public function getLastname() { return $this->get('sn'); }
public function getEmail() { return $this->get('mail'); }
public function getPhone() { return $this->get('telephonenumber'); }
public function getAddress() { return $this->get('postaladdress'); }
public function getCity() { return $this->get('l'); }
public function getState() { return $this->get('st'); }
public function getZip() { return $this->get('postalcode'); }
/**
* Returns the first scalar value from the entry's field
*
* @param string $field
* @return string
*/
private function get($field) {
return isset($this->entry[$field][0]) ? $this->entry[$field][0] : '';
}
}

View File

@ -0,0 +1,140 @@
<?php
/**
* Class for custom error handling
*
* Applications need to do more with errors than just display or log the error.
* Error handling should be configurable in the configuration.inc
* The $ERROR_REPORTING variable declared in configuration.inc controls the
* various possibile things to do with errors.
*
* @copyright 2013 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
namespace Blossom\Classes;
class Error
{
/**
* Provide nicely formatted error messages when PHP bombs out.
*/
public static function customErrorHandler($errno, $errstr, $errfile, $errline)
{
global $ERROR_REPORTING;
if (isset($ERROR_REPORTING)) {
if (in_array('PRETTY_PRINT',$ERROR_REPORTING)) {
echo "
<div id=\"errorMessages\">
<p><em>from ".ADMINISTRATOR_NAME.":</em>
There is an error in the code on this page that is through no fault of your own.
Errors of this sort need to be fixed immediately, though.
Please help us out by copying and pasting the following error message into an email and sending it to me at
<a href=\"mailto:".ADMINISTRATOR_EMAIL."\">".ADMINISTRATOR_EMAIL."</a>.
</p>
<p><strong>Code Error:</strong> Error on line $errline of file $errfile:</p>
<p>$errstr</p>
</div>
";
}
if (in_array('EMAIL_ADMIN',$ERROR_REPORTING)) {
$subject = APPLICATION_NAME.' Error';
$message = "\t$_SERVER[REQUEST_URI]\n\nError on line $errline of file $errfile:\n$errstr\n\n";
$message.= print_r(debug_backtrace(),true);
mail(ADMINISTRATOR_EMAIL,$subject,$message,"From: apache@$_SERVER[SERVER_NAME]");
}
if (in_array('EMAIL_USER',$ERROR_REPORTING)
&& isset($_SESSION['USER'])
&& $_SESSION['USER']->getEmail()) {
$subject = APPLICATION_NAME.' Error';
$message = "\t$_SERVER[REQUEST_URI]\n\nError on line $errline of file $errfile:\n$errstr\n\n";
$message.= print_r(debug_backtrace(),true);
mail($_SESSION['USER']->getEmail(),
$subject,
$message,
"From: apache@$_SERVER[SERVER_NAME]");
}
if (in_array('SKIDDER',$ERROR_REPORTING)) {
$script = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : $_SERVER['SCRIPT_NAME'];
$message = "$script\nError on line $errline of file $errfile:\n$errstr\n";
$message.= print_r(debug_backtrace(),true);
$skidder = curl_init(SKIDDER_URL);
curl_setopt($skidder,CURLOPT_POST,true);
curl_setopt($skidder,CURLOPT_HEADER,true);
curl_setopt($skidder,CURLOPT_RETURNTRANSFER,true);
curl_setopt($skidder,CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($skidder,
CURLOPT_POSTFIELDS,
array('application_id'=>SKIDDER_APPLICATION_ID,
'script'=>$script,
'type'=>$errstr,
'message'=>$message));
curl_exec($skidder);
}
}
}
/**
* Object oriented exceptions are handled differently from other PHP errors.
*/
public static function customExceptionHandler($exception)
{
global $ERROR_REPORTING;
if (isset($ERROR_REPORTING)) {
if (in_array('PRETTY_PRINT',$ERROR_REPORTING)) {
echo "
<div id=\"errorMessages\">
<p><em>from ".ADMINISTRATOR_NAME.":</em>
There is an error in the code on this page that is through no fault of your own.
Errors of this sort need to be fixed immediately, though.
Please help me out by copying and pasting the following error message into an email and sending it to me at
<a href=\"mailto:".ADMINISTRATOR_EMAIL."\">".ADMINISTRATOR_EMAIL."</a>.
</p>
<p><strong>Uncaught exception:</strong>
Exception on line {$exception->getLine()} of file {$exception->getFile()}:
</p>
<p>{$exception->getMessage()}</p>
</div>
";
}
if (in_array('EMAIL_ADMIN',$ERROR_REPORTING)) {
$subject = APPLICATION_NAME.' Exception';
$message = "\t$_SERVER[REQUEST_URI]\n\nException on line {$exception->getLine()} of file {$exception->getFile()}:\n{$exception->getMessage()}\n\n";
$message.= print_r(debug_backtrace(),true);
mail(ADMINISTRATOR_EMAIL,$subject,$message,"From: apache@$_SERVER[SERVER_NAME]");
}
if (in_array('EMAIL_USER',$ERROR_REPORTING)
&& isset($_SESSION['USER'])
&& $_SESSION['USER']->getEmail()) {
$subject = APPLICATION_NAME.' Exception';
$message = "\t$_SERVER[REQUEST_URI]\n\nException on line {$exception->getLine()} of file {$exception->getFile()}:\n{$exception->getMessage()}\n\n";
$message.= print_r(debug_backtrace(),true);
mail($_SESSION['USER']->getEmail(),
$subject,
$message,
"From: apache@$_SERVER[SERVER_NAME]");
}
if (in_array('SKIDDER',$ERROR_REPORTING)) {
$script = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : $_SERVER['SCRIPT_NAME'];
$message = "Error on line {$exception->getLine()} of file {$exception->getFile()}:\n{$exception->getMessage()}\n";
$message.= print_r(debug_backtrace(),true);
$skidder = curl_init(SKIDDER_URL);
curl_setopt($skidder,CURLOPT_POST,true);
curl_setopt($skidder,CURLOPT_HEADER,true);
curl_setopt($skidder,CURLOPT_RETURNTRANSFER,true);
curl_setopt($skidder,CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($skidder,
CURLOPT_POSTFIELDS,
array('application_id'=>SKIDDER_APPLICATION_ID,
'script'=>$script,
'type'=>'Uncaught Exception',
'message'=>$message));
curl_exec($skidder);
}
}
}
}

View File

@ -1,9 +1,10 @@
<?php
/**
* @copyright 20011 City of Bloomington, Indiana
* @copyright 2011-2013 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
namespace Blossom\Classes;
interface ExternalIdentity
{
@ -25,15 +26,11 @@ interface ExternalIdentity
* @return string
*/
public function getFirstname();
/**
* @return string
*/
public function getLastname();
/**
* @return string
*/
public function getEmail();
}
public function getPhone();
public function getAddress();
public function getCity();
public function getState();
public function getZip();
}

View File

@ -2,10 +2,12 @@
/**
* Takes an array and splits it up into pages (an array of arrays)
*
* @copyright 2008-2009 City of Bloomington, Indiana
* @copyright 2008-2013 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
namespace Blossom\Classes;
class Paginator implements ArrayAccess,SeekableIterator,Countable
{
private $pageSize;

View File

@ -0,0 +1,27 @@
<?php
/**
* @copyright 2012-2013 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
namespace Blossom\Classes;
class SolrPaginatorAdapter implements \Zend\Paginator\Adapter\AdapterInterface
{
private $solrObject;
public function __construct(\Apache_Solr_Response $solrObject)
{
$this->solrObject = $solrObject;
}
public function count()
{
return $this->solrObject->response->numFound;
}
public function getItems($offset, $itemCountPerPage)
{
return array();
}
}

View File

@ -0,0 +1,104 @@
<?php
/**
* A base class that streamlines creation of ZF2 TableGateway
*
* @copyright 2014 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
namespace Blossom\Classes;
use Zend\Db\TableGateway\TableGateway as ZendTableGateway;
use Zend\Db\ResultSet\ResultSet;
use Zend\Db\Sql\Select;
use Zend\Paginator\Adapter\DbSelect;
use Zend\Paginator\Paginator;
abstract class TableGateway
{
protected $resultSetPrototype;
protected $tableGateway;
/**
* @param string $table The name of the database table
* @param string $class The class model to use as a resultSetPrototype
*
* You must pass in the fully namespaced classname. We do not assume
* any particular namespace for the models.
*/
public function __construct($table, $class)
{
$this->resultSetPrototype = new ResultSet();
$this->resultSetPrototype->setArrayObjectPrototype(new $class());
$this->tableGateway = new ZendTableGateway(
$table,
Database::getConnection(),
null,
$this->resultSetPrototype
);
}
/**
* Simple, default implementation for find
*
* This will allow you to do queries for rows in the table,
* where you provide field=>values for the where clause.
* Only fields actually in the table can be included this way.
*
* You generally want to override this implementation with your own
* However, this basic implementation will allow you to get up and
* running quicker.
*
* @param array $fields Key value pairs to select on
* @param string $order The default ordering to use for select
* @param boolean $paginated If set to true, will return a paginator
* @param int $limit
*/
public function find($fields=null, $order=null, $paginated=false, $limit=null)
{
$select = new Select($this->tableGateway->getTable());
if (count($fields)) {
foreach ($fields as $key=>$value) {
$select->where([$key=>$value]);
}
}
return $this->performSelect($select, $order, $paginated, $limit);
}
/**
* @param Zend\Db\Sql\Select $select
* @return Zend\Db\ResultSet
*/
public function performSelect(Select $select, $order, $paginated=false, $limit=null)
{
if ($order) { $select->order($order); }
if ($limit) { $select->limit($limit); }
if ($paginated) {
$adapter = new DbSelect($select, $this->tableGateway->getAdapter(), $this->resultSetPrototype);
$paginator = new Paginator($adapter);
return $paginator;
}
else {
return $this->tableGateway->selectWith($select);
}
}
/**
* Returns the generated sql
*
* @param Zend\Db\Sql\Select
*/
public function getSqlForSelect(Select $select)
{
return $select->getSqlString($this->tableGateway->getAdapter()->getPlatform());
}
/**
* @param Zend\Db\ResultSet
*/
public static function getSqlForResult(ResultSet $result)
{
return $result->getDataSource()->getResource()->queryString;
}
}

View File

@ -0,0 +1,227 @@
<?php
/**
* Defines the overall page layout
*
* The template collects all the blocks from the controller
*
* @copyright 2006-2014 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
namespace Blossom\Classes;
class Template extends View
{
private $path;
private $filename;
public $outputFormat = 'html';
public $blocks = array();
private $assets = array();
private $helpers = array();
/**
* @param string $filename
* @param string $outputFormat
* @param array $vars
*/
public function __construct($filename='default',$outputFormat='html',array $vars=null)
{
parent::__construct($vars);
$this->filename = $filename;
$this->outputFormat = preg_replace('/[^a-zA-Z]/','',$outputFormat);
// Check for a SITE_HOME override
$this->path = is_file(SITE_HOME."/templates/{$this->outputFormat}/{$this->filename}.inc")
? SITE_HOME.'/templates'
: APPLICATION_HOME.'/templates';
// Make sure the output format exists
if (!is_file("{$this->path}/{$this->outputFormat}/{$this->filename}.inc")) {
$this->filename = 'default';
$this->outputFormat = 'html';
}
}
/**
* @param string $filename
*/
public function setFilename($filename)
{
if ( is_file(SITE_HOME."/templates/{$this->outputFormat}/{$this->filename}.inc")) {
$this->path = SITE_HOME.'/templates';
}
elseif ( is_file(APPLICATION_HOME."/templates/{$this->outputFormat}/$filename.inc")) {
$this->path = APPLICATION_HOME.'/templates';
}
else {
throw new \Exception('unknownTemplate');
}
$this->filename = $filename;
}
/**
* @param string $format
*/
public function setOutputFormat($format)
{
$format = preg_replace('/[^a-zA-Z]/','',$format);
if ( is_file(SITE_HOME."/templates/$format/{$this->filename}.inc")) {
$this->path = SITE_HOME.'/templates';
}
elseif ( is_file(APPLICATION_HOME."/templates/$format/{$this->filename}.inc")) {
$this->path = APPLICATION_HOME.'/templates';
}
else {
throw new \Exception('unknownOutputFormat');
}
$this->outputFormat = $format;
}
/**
* Returns all the rendered content of the template
*
* Template files must include a call to $this->includeBlocks(),
* when they're ready for content
*
* @return string
*/
public function render()
{
ob_start();
include "{$this->path}/{$this->outputFormat}/{$this->filename}.inc";
return ob_get_clean();
}
/**
* Callback function for template files
*
* Renders blocks for the main content area, unless $panel is given. If $panel is given
* it will render any blocks that the controllers have assigned to that panel.
*
* Template files make calls to this function to render all the blocks that the controller
* has loaded for this Template. Controllers will populate the blocks array with content.
* If a template file can render content in a panel that is not the main content panel,
* the template file will need to include the panel's name in the includeBlocks() call.
*
* $this->blocks is a multi-dimensional array. The top level elements, non-array elements
* are for the default, main content area. Other panels will be arrays in $this->blocks with
* the panel name as the key.
*
* Panels are nothing but a name on a div, the $panel string can be whatever the template
* author thinks makes sense. Controllers are expected to know what the template authors
* have written.
*
* $this->blocks[] = "main content block one";
* $this->blocks[] = "main content block two";
* $this->blocks['panel-one'][] = "left sidebar block one";
* $this->blocks['panel-one'][] = "left sidebar block two";
* $this->blocks['panel-two'][] = "right sidebar block one";
*
* @param string $panel
* @return string
*/
private function includeBlocks($target=null)
{
ob_start();
if ($target) {
// Render any blocks for the given panel
if (isset($this->blocks[$target]) && is_array($this->blocks[$target])) {
foreach ($this->blocks[$target] as $block) {
echo $block->render($this->outputFormat,$this);
}
}
else {
// Go through the template looking for what they asked for
foreach ($this->blocks as $key=>$value) {
// If we find a block that matches, render that block
if ($value instanceof Block) {
if ($value->getFile() == $target) {
echo $value->render($this->outputFormat,$this);
continue;
}
}
// The block they asked for might be inside a panel
else {
foreach ($value as $block) {
if ($block->getFile() == $target
|| $block->title == $target) {
echo $block->render($this->outputFormat,$this);
continue;
}
}
}
}
}
}
else {
// Render only the blocks for the main content area
foreach ($this->blocks as $block) {
if (!is_array($block)) {
echo $block->render($this->outputFormat,$this);
}
}
}
return ob_get_clean();
}
/**
* Adds data to an asset, making sure to not duplicate existing data
*
* @param string $name The name of the asset
* @param mixed $data
*/
public function addToAsset($name,$data)
{
if (!isset($this->assets[$name]) || !is_array($this->assets[$name])) {
$this->assets[$name] = array();
}
if (!in_array($data,$this->assets[$name])) {
$this->assets[$name][] = $data;
}
}
/**
* Loads and returns a helper object
*/
public function getHelper($functionName)
{
if (!array_key_exists($functionName, $this->helpers)) {
$class = ucfirst($functionName);
$file = "/templates/{$this->outputFormat}/helpers/$class.php";
if ( is_file(SITE_HOME.$file)) {
require_once SITE_HOME.$file;
}
else {
require_once APPLICATION_HOME.$file;
}
$class = "Application\\Templates\\Helpers\\$class";
$this->helpers[$functionName] = new $class($this);
}
return $this->helpers[$functionName];
}
/**
* Includes the given filename.
*
* Supports SITE_HOME overriding.
* Specify a relative path starting from /templates/
* $file paths should not start with a slash.
*
* @param string $file
*/
public function _include($file)
{
if (is_file(SITE_HOME."/templates/{$this->outputFormat}/$file")) {
include SITE_HOME."/templates/{$this->outputFormat}/$file";
}
else {
include APPLICATION_HOME."/templates/{$this->outputFormat}/$file";
}
}
}

View File

@ -7,11 +7,13 @@
* $url->somevar = $somevar;
* echo $url->getURL();
*
* @copyright 2006-2009 City of Bloomington, Indiana.
* @copyright 2006-2013 City of Bloomington, Indiana.
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
class URL
namespace Blossom\Classes;
class Url
{
private $scheme;
private $host;
@ -20,26 +22,43 @@ class URL
public $parameters = array();
/**
* Performs an HTTP GET and returns response string
*
* @param string $url
* @return string
*/
public static function get($url)
{
$request = curl_init($url);
curl_setopt($request, CURLOPT_RETURNTRANSFER,true);
curl_setopt($request, CURLOPT_FOLLOWLOCATION, true);
if (substr($url, 0, 5) == 'https://') {
curl_setopt($request, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($request, CURLOPT_SSLVERSION, 3);
}
return curl_exec($request);
}
public function __construct($script)
{
$script = urldecode($script);
// If scheme wasn't provided add one to the start of the string
if (!preg_match('|://|',$script)) {
$scheme = $_SERVER['SERVER_PORT']==443 ? 'https://' : 'http://';
if (!strpos(substr($script,0,20),'://')) {
$scheme = (isset($_SERVER['SERVER_PORT']) && $_SERVER['SERVER_PORT']==443)
? 'https://'
: 'http://';
$script = $scheme.$script;
}
$url = parse_url($script);
$this->scheme = $url['scheme'];
$this->host = $url['host'];
$this->path = $url['path'];
if (isset($url['fragment'])) {
$this->anchor = $url['fragment'];
}
if (isset($url['query'])) {
parse_str($url['query'],$this->parameters);
}
if (isset($url['host'])) { $this->host = $url['host']; }
if (isset($url['path'])) { $this->path = $url['path']; }
if (isset($url['fragment'])) { $this->anchor = $url['fragment']; }
if (isset($url['query'])) { parse_str($url['query'],$this->parameters); }
}
/**
@ -83,7 +102,7 @@ class URL
*/
public function getScheme() {
if (!$this->scheme) {
$this->scheme = 'http://';
$this->scheme = 'http';
}
return $this->scheme;
}
@ -94,9 +113,7 @@ class URL
*/
public function setScheme($string)
{
if (!preg_match('|://|',$string)) {
$string .= '://';
}
$string = preg_replace('|://|', '', $string);
$this->scheme = $string;
}

View File

@ -0,0 +1,128 @@
<?php
/**
* @copyright 2006-2013 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
namespace Blossom\Classes;
use Zend\I18n\Translator\Translator;
abstract class View
{
protected $vars = array();
private static $translator;
abstract public function render();
/**
* Instantiates the Zend Translator
*
* See: ZendFramework documentation for full information
* http://framework.zend.com/manual/2.2/en/modules/zend.i18n.translating.html
* @see http://framework.zend.com/manual/2.2/en/modules/zend.i18n.translating.html
*/
public function __construct(array $vars=null)
{
if (count($vars)) {
foreach ($vars as $name=>$value) {
$this->vars[$name] = $value;
}
}
if (!self::$translator) {
self::$translator = new Translator();
self::$translator->addTranslationFilePattern(
'gettext',
APPLICATION_HOME.'/language',
'%s.mo'
);
}
}
/**
* Magic Method for setting object properties
*
* @param string $key
* @param mixed $value
*/
public function __set($key,$value) {
$this->vars[$key] = $value;
}
/**
* Magic method for getting object properties
*
* @param string $key
* @return mixed
*/
public function __get($key)
{
if (isset($this->vars[$key])) {
return $this->vars[$key];
}
return null;
}
/**
* @param string $key
* @return boolean
*/
public function __isset($key) {
return array_key_exists($key,$this->vars);
}
/**
* Cleans strings for output
*
* There are more bad characters than htmlspecialchars deals with. We just want
* to add in some other characters to clean. While here, we might as well
* have it trim out the whitespace too.
*
* @param array|string $string
* @param CONSTANT $quotes Optional, the desired constant to use for the htmlspecidalchars call
* @return string
*/
public static function escape($input,$quotes=ENT_QUOTES)
{
if (is_array($input)) {
foreach ($input as $key=>$value) {
$input[$key] = self::escape($value,$quotes);
}
}
else {
$input = htmlspecialchars(trim($input), $quotes, 'UTF-8');
}
return $input;
}
/**
* Returns the gettext translation of msgid
*
* For entries in the PO that are plurals, you must pass msgid as an array
* $this->translate(array('msgid', 'msgid_plural', $num))
*
* See: ZendFramework documentation for full information
* http://framework.zend.com/manual/2.2/en/modules/zend.i18n.translating.html
*
* @see http://framework.zend.com/manual/2.2/en/modules/zend.i18n.translating.html
* @param mixed $msgid String or Array
* @return string
*/
public function translate($msgid)
{
if (is_array($msgid)) {
return self::$translator->translatePlural($msgid[0], $msgid[1], $msgid[2]);
}
else {
return self::$translator->translate($msgid);
}
}
/**
* Alias of $this->translate()
*/
public function _($msgid)
{
return $this->translate($msgid);
}
}

View File

@ -1,38 +1,44 @@
<?php
/**
* @copyright 2007-2009 City of Bloomington, Indiana
* Displays page navigation for any list that has pagination turned on
*
* @copyright 2007-2013 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
* @param Zend_Paginator $this->pages
* @param Zend\Paginator $this->paginator
*/
if ($this->pages->pageCount > 1) {
$url = new URL($_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI']);
use Blossom\Classes\Url;
if ($this->paginator->count() > 1) {
$pages = $this->paginator->getPages();
$url = new Url($_SERVER['SERVER_NAME'].$_SERVER['REQUEST_URI']);
$url->purgeEmptyParameters();
echo '<ul class="pageNavigation">';
// Show the Back button
if (isset($this->pages->previous)) {
$url->page = $this->pages->first;
if (isset($pages->previous)) {
$url->page = $pages->first;
echo "<li><a href=\"$url\" class=\"first\">First</a></li>";
$url->page = $this->pages->previous;
$url->page = $pages->previous;
echo "<li><a href=\"$url\" class=\"previous\">Back</a></li>";
}
// Show the page number links
// Show only $maxNumLinks pages at a time
foreach ($this->pages->pagesInRange as $page) {
foreach ($pages->pagesInRange as $page) {
$url->page = $page;
$class = ($page == $this->pages->current) ? 'class="current"' : '';
$class = ($page == $pages->current) ? 'class="current"' : '';
echo "<li><a href=\"$url\" $class>$page</a></li>";
}
// Show the Next button
if (isset($this->pages->next)) {
$url->page = $this->pages->next;
if (isset($pages->next)) {
$url->page = $pages->next;
echo "<li><a href=\"$url\" class=\"next\">Next</a></li>";
$url->page = $this->pages->last;
$url->page = $pages->last;
echo "<li><a href=\"$url\" class=\"last\">Last</a></li>";
}

View File

@ -1,9 +1,11 @@
<?php
/**
* @copyright 2007-2009 City of Bloomington, Indiana
* @copyright 2007-2013 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
use Blossom\Classes\Block;
if (isset($_SESSION['errorMessages'])) {
$errorBlock = new Block('errorMessages.inc',array('errorMessages'=>$_SESSION['errorMessages']));
echo $errorBlock->render($this->outputFormat);

View File

@ -0,0 +1,89 @@
<?php
/**
* @copyright 2014 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
$_SERVER['SITE_HOME'] = __DIR__;
require_once realpath(__DIR__.'/../../../configuration.inc');
class ActiveRecordTest extends PHPUnit_Framework_TestCase
{
private $testModel;
public function __construct()
{
$this->testModel = new TestModel();
}
public function testGetAndSet()
{
$this->testModel->set('testField', 'testValue');
$this->assertEquals('testValue', $this->testModel->get('testField'));
}
public function testGetAndSetDate()
{
$dateString = '2012-01-01 01:23:43';
$this->testModel->setDateData('testField', $dateString);
$this->assertEquals($dateString, $this->testModel->getDateData('testField'));
}
public function testDateFormat()
{
$dateString = '1/3/2013 01:23:43';
$this->testModel->setDateData('testField', $dateString);
$this->assertEquals('Jan 3rd 2013', $this->testModel->getDateData('testField', 'M jS Y'));
}
public function testRawDateDataIsMySQLFormat()
{
$dateString = '1/3/2013 01:23:43';
$mysqlDate = '2013-01-03 01:23:43';
$this->testModel->setDateData('testField', $dateString);
$this->assertEquals($mysqlDate, $this->testModel->getDateData('testField'));
}
public function testForeignKeyObject()
{
$this->testModel->setTestModel(new TestModel(1));
$o = $this->testModel->getTestModel();
$this->assertEquals(1, $o->get('id'));
}
}
class TestModel extends Blossom\Classes\ActiveRecord
{
protected $foreignkey;
public function __construct($id=null)
{
if ($id) { parent::set('id', $id); }
}
public function validate() { }
public function getId() { return parent::get('id'); }
public function get($field) { return parent::get($field); }
public function set($field, $value) { parent::set($field, $value); }
public function getDateData($field, $format=null, \DateTimeZone $timezone=null)
{
return parent::getDateData($field, $format, $timezone);
}
public function setDateData($field, $date) { parent::setDateData($field, $date); }
public function getTestModel()
{
return parent::getForeignKeyObject('TestModel', 'foreignkey_id');
}
public function setTestModel(TestModel $o)
{
parent::setForeignKeyObject('TestModel', 'foreignkey_id', $o);
}
}

View File

@ -0,0 +1,38 @@
<?php
/**
* @copyright 2014 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
$_SERVER['SITE_HOME'] = __DIR__;
require_once realpath(__DIR__.'/../../../configuration.inc');
use Blossom\Classes\Block;
use Blossom\Classes\Template;
class BlockTest extends PHPUnit_Framework_TestCase
{
public function testVars()
{
$block = new Block('test', ['test'=>'something']);
$this->assertEquals('something', $block->test);
$block->one = 'another';
$this->assertEquals('another', $block->one);
}
/**
* SITE_HOME should be able to override any block
*/
public function testSiteOverrides()
{
$template = new Template('test', 'test');
$block = new Block('test.inc');
$expectedOutput = file_get_contents(__DIR__.'/blocks/test/test.inc');
$this->assertEquals($expectedOutput, $block->render('test', $template));
$block = new Block('includes.inc');
$this->assertEquals($expectedOutput, $block->render('test', $template));
}
}

View File

@ -0,0 +1,16 @@
<?php
/**
* @copyright 2014 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
$_SERVER['SITE_HOME'] = __DIR__;
require_once realpath(__DIR__.'/../../../configuration.inc');
class ConfigurationTest extends PHPUnit_Framework_TestCase
{
public function testSiteConfigLoaded()
{
$this->assertEquals('testApp', APPLICATION_NAME);
}
}

View File

@ -0,0 +1,40 @@
<?php
/**
* @copyright 2014 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
$_SERVER['SITE_HOME'] = __DIR__;
require_once realpath(__DIR__.'/../../../configuration.inc');
use Blossom\Classes\Template;
class TemplateTest extends PHPUnit_Framework_TestCase
{
public function testVars()
{
$template = new Template('default', 'html', ['test'=>'something']);
$this->assertEquals('something', $template->test);
$template->one = 'another';
$this->assertEquals('another', $template->one);
}
/**
* SITE_HOME sites should be able to override any template
*/
public function testSiteOverrides()
{
$template = new Template('test', 'test');
$expectedOutput = file_get_contents(__DIR__.'/templates/test/test.inc');
$this->assertEquals($expectedOutput, $template->render());
$helper = $template->getHelper('test');
$this->assertEquals('something', $helper->test('something'));
$template = new Template('partials', 'test');
$expectedOutput = file_get_contents(__DIR__.'/templates/test/partials/testPartial.inc');
$this->assertEquals($expectedOutput, $template->render());
}
}

View File

@ -0,0 +1,36 @@
<?php
/**
* @copyright 2014 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
$_SERVER['SITE_HOME'] = __DIR__;
require_once realpath(__DIR__.'/../../../configuration.inc');
use Blossom\Classes\Url;
class UrlTest extends PHPUnit_Framework_TestCase
{
public function testUrlOutput()
{
$testUrl = 'http://www.somewhere.com/test';
$url = new Url($testUrl);
$this->assertEquals($testUrl, "$url");
}
public function testChangeScheme()
{
$url = new Url('http://www.somewhere.com');
$url->setScheme('webcal://');
$this->assertEquals('webcal://www.somewhere.com', "$url");
}
public function testUrlWithoutScheme()
{
$url = new Url('bloomington.in.gov/test');
$this->assertEquals('http', $url->getScheme());
$this->assertEquals('http://bloomington.in.gov/test', "$url");
}
}

View File

@ -0,0 +1,32 @@
<?php
/**
* @copyright 2014 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
$_SERVER['SITE_HOME'] = __DIR__;
require_once realpath(__DIR__.'/../../../configuration.inc');
use Blossom\Classes\View;
class ViewTest extends PHPUnit_Framework_TestCase
{
public function testVars()
{
$view = new ViewStub(['test'=>'something']);
$this->assertEquals('something', $view->test);
$view->one = 'another test';
$this->assertEquals('another test', $view->one);
}
}
class ViewStub extends View
{
public function __construct($vars=null)
{
parent::__construct($vars);
}
public function render() { return 'test content'; }
}

View File

@ -0,0 +1,2 @@
<?php
$this->_include('test/test.inc');

View File

@ -0,0 +1 @@
This is a custom block override

View File

@ -0,0 +1,19 @@
<?php
define('APPLICATION_NAME','testApp');
/**
* The URL to get to this site
* Do NOT use a trailing slash
*/
define('BASE_URL','http://localhost/testApp');
define('BASE_URI','/testApp');
/**
* Used when there's an error on the site. The Framework will
* print out a nice error message, encouraging users to report any problems
* See: Blossom\Classes\Error
*/
define('ADMINISTRATOR_NAME','Site Admin');
define('ADMINISTRATOR_EMAIL','admin@localhost');
define('DATE_FORMAT', 'n/j/Y H:i:s');

View File

@ -0,0 +1,26 @@
<?php
/**
* Test Helper
*
* @copyright 2014 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
namespace Application\Templates\Helpers;
use Blossom\Classes\Template;
class Test
{
private $template;
public function __construct(Template $template)
{
$this->template = $template;
}
public function test($string)
{
return $string;
}
}

View File

@ -0,0 +1,2 @@
<?php
$this->_include('partials/testPartial.inc');

View File

@ -0,0 +1 @@
This is a test partial

View File

@ -0,0 +1 @@
This is a customized site template

View File

@ -1,62 +0,0 @@
<?php
/**
* Represents a block of main content in a template
*
* Blocks are partial view scripts.
* They are contained in APPLICATION/blocks
* They are organized by $outputFormat
* APPLICATION_HOME/blocks/html/...
* APPLICATION_HOME/blocks/xml/...
* APPLICATION_HOME/blocks/json/..
*
* @copyright 2006-2009 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
class Block extends View
{
private $file;
/**
* Establishes the block script to use for rendering
*
* Blocks are files contained in the base path of:
* APPLICATION_HOME/blocks/$outpuform
*
* @param string $file
* @param array $vars An associative array of variables to set
*/
public function __construct($file,array $vars=null)
{
$this->file = $file;
if (count($vars)) {
foreach ($vars as $name=>$value) {
$this->vars[$name] = $value;
}
}
}
/**
* Includes the block script and returns the output as a string
*
* @param string $outputFormat
* @return string
*/
public function render($outputFormat='html')
{
$block = "/blocks/$outputFormat/{$this->file}";
if (file_exists(APPLICATION_HOME.$block)) {
ob_start();
include APPLICATION_HOME.$block;
return ob_get_clean();
}
elseif (file_exists(FRAMEWORK.$block)) {
ob_start();
include FRAMEWORK.$block;
return ob_get_clean();
}
throw new Exception('unknownBlock');
}
}

View File

@ -1,46 +0,0 @@
<?php
/**
* @copyright 2009 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
class Date extends DateTime
{
/**
* Handles array dates passed in the constructor.
*
* Wrapper for DateTime constructor. If arrays are passed, they will be
* handled here. Anything else will be passed to the DateTime constructor.
* Arrays should be in the form of PHP's getdate() array
*
* @param array $date
*/
public function __construct($date=null)
{
if (is_array($date)) {
if ($date['year'] && $date['mon'] && $date['mday']) {
$dateString = "$date[year]-$date[mon]-$date[mday]";
if (isset($date['hours']) || isset($date['minutes']) || isset($date['seconds'])) {
$time = (isset($date['hours']) && $date['hours']) ? "$date[hours]:" : '00:';
$time.= (isset($date['minutes']) && $date['minutes']) ? "$date[minutes]:" : '00:';
$time.= (isset($date['seconds']) && $date['seconds']) ? $date['seconds'] : '00';
$dateString.= " $time";
}
$date = $dateString;
}
}
if (is_int($date)) {
$date = date('Y-m-d',$date);
}
if (!$date instanceof DateTime) {
parent::__construct($date);
}
}
public function __toString()
{
return $this->format('n/j/Y');
}
}

View File

@ -1,112 +0,0 @@
<?php
/**
* A class for working with entries in LDAP.
*
* This class is written specifically for the City of Bloomington's
* LDAP layout. If you are going to be doing LDAP authentication
* with your own LDAP server, you will probably need to customize
* the fields used in this class.
*
* @copyright 2011 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
class Employee implements ExternalIdentity
{
private static $connection;
private $entry;
/**
* @param string $username
* @param string $password
* @throws Exception
*/
public static function authenticate($username,$password)
{
$bindUser = sprintf(str_replace('{username}','%s',DIRECTORY_USER_BINDING),$username);
$connection = ldap_connect(DIRECTORY_SERVER) or die("Couldn't connect to ADS");
ldap_set_option($connection, LDAP_OPT_PROTOCOL_VERSION, 3);
if (ldap_bind($connection,$bindUser,$password)) {
return true;
}
}
/**
* Loads an entry from the LDAP server for the given user
*
* @param string $username
*/
public function __construct($username)
{
$this->openConnection();
$result = ldap_search(
self::$connection,
DIRECTORY_BASE_DN,
DIRECTORY_USERNAME_ATTRIBUTE."=$username"
);
if (ldap_count_entries(self::$connection,$result)) {
$entries = ldap_get_entries(self::$connection, $result);
$this->entry = $entries[0];
}
}
/**
* @return string
*/
public function getUsername()
{
return $this->entry['uid'];
}
/**
* @return string
*/
public function getFirstname()
{
return $this->entry['givenname'][0];
}
/**
* @return string
*/
public function getLastname()
{
return $this->entry['sn'][0];
}
/**
* @return string
*/
public function getEmail()
{
return $this->entry['mail'][0];
}
/**
* Creates the connection to the LDAP server
*/
private function openConnection()
{
if (!self::$connection) {
if (self::$connection = ldap_connect(DIRECTORY_SERVER)) {
ldap_set_option(self::$connection,LDAP_OPT_PROTOCOL_VERSION,3);
if (defined('DIRECTORY_ADMIN_BINDING') && DIRECTORY_ADMIN_BINDING) {
if (!ldap_bind(self::$connection,DIRECTORY_ADMIN_BINDING,DIRECTORY_ADMIN_PASS)) {
throw new Exception(ldap_error(self::$connection));
}
}
else {
if (!ldap_bind(self::$connection)) {
throw new Exception(ldap_error(self::$connection));
}
}
}
else {
throw new Exception(ldap_error(self::$connection));
}
}
}
}

View File

@ -1,332 +0,0 @@
<?php
/**
* Pluralize and singularize English words.
*
* Orinally written by the CakePHP Project
* CakePHP(tm) : Rapid Development Framework <http://www.cakephp.org/>
* Copyright 2005-2008, Cake Software Foundation, Inc.
* 1785 E. Sahara Avenue, Suite 490-204
* Las Vegas, Nevada 89104
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
*
* @filesource
* @copyright Copyright 2005-2008, Cake Software Foundation, Inc.
* @link http://www.cakefoundation.org/projects/info/cakephp CakePHP(tm) Project
* @package cake
* @subpackage cake.cake.libs
* @since CakePHP(tm) v 0.2.9
* @version $Revision: 6311 $
* @modifiedby $LastChangedBy: phpnut $
* @lastmodified $Date: 2008-01-02 00:33:52 -0600 (Wed, 02 Jan 2008) $
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*
* Modified to work in City of Bloomington's Framework
* Relicensed under GPL
* Redistributions must retain all copyright notices
* @copyright 2006-2008 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
*/
class Inflector
{
/**
* Return $word in plural form.
*
* @param string $word Word in singular
* @return string Word in plural
*/
public static function pluralize($word) {
$corePluralRules = array('/(s)tatus$/i' => '\1\2tatuses',
'/(quiz)$/i' => '\1zes',
'/^(ox)$/i' => '\1\2en',
'/([m|l])ouse$/i' => '\1ice',
'/(matr|vert|ind)(ix|ex)$/i' => '\1ices',
'/(x|ch|ss|sh)$/i' => '\1es',
'/([^aeiouy]|qu)y$/i' => '\1ies',
'/(hive)$/i' => '\1s',
'/(?:([^f])fe|([lr])f)$/i' => '\1\2ves',
'/sis$/i' => 'ses',
'/([ti])um$/i' => '\1a',
'/(p)erson$/i' => '\1eople',
'/(m)an$/i' => '\1en',
'/(c)hild$/i' => '\1hildren',
'/(buffal|tomat)o$/i' => '\1\2oes',
'/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|vir)us$/i' => '\1i',
'/us$/' => 'uses',
'/(alias)$/i' => '\1es',
'/(ax|cri|test)is$/i' => '\1es',
'/s$/' => 's',
'/$/' => 's',);
$coreUninflectedPlural = array('.*[nrlm]ese', '.*deer', '.*fish', '.*measles', '.*ois', '.*pox', '.*sheep', 'Amoyese',
'bison', 'Borghese', 'bream', 'breeches', 'britches', 'buffalo', 'cantus', 'carp', 'chassis', 'clippers',
'cod', 'coitus', 'Congoese', 'contretemps', 'corps', 'debris', 'diabetes', 'djinn', 'eland', 'elk',
'equipment', 'Faroese', 'flounder', 'Foochowese', 'gallows', 'Genevese', 'Genoese', 'Gilbertese', 'graffiti',
'headquarters', 'herpes', 'hijinks', 'Hottentotese', 'information', 'innings', 'jackanapes', 'Kiplingese',
'Kongoese', 'Lucchese', 'mackerel', 'Maltese', 'media', 'mews', 'moose', 'mumps', 'Nankingese', 'news',
'nexus', 'Niasese', 'Pekingese', 'Piedmontese', 'pincers', 'Pistoiese', 'pliers', 'Portuguese', 'proceedings',
'rabies', 'rice', 'rhinoceros', 'salmon', 'Sarawakese', 'scissors', 'sea[- ]bass', 'series', 'Shavese', 'shears',
'siemens', 'species', 'swine', 'testes', 'trousers', 'trout', 'tuna', 'Vermontese', 'Wenchowese',
'whiting', 'wildebeest', 'Yengeese',);
$coreIrregularPlural = array('atlas' => 'atlases',
'beef' => 'beefs',
'brother' => 'brothers',
'child' => 'children',
'corpus' => 'corpuses',
'cow' => 'cows',
'ganglion' => 'ganglions',
'genie' => 'genies',
'genus' => 'genera',
'graffito' => 'graffiti',
'hoof' => 'hoofs',
'loaf' => 'loaves',
'man' => 'men',
'money' => 'monies',
'mongoose' => 'mongooses',
'move' => 'moves',
'mythos' => 'mythoi',
'numen' => 'numina',
'occiput' => 'occiputs',
'octopus' => 'octopuses',
'opus' => 'opuses',
'ox' => 'oxen',
'penis' => 'penises',
'person' => 'people',
'sex' => 'sexes',
'soliloquy' => 'soliloquies',
'testis' => 'testes',
'trilby' => 'trilbys',
'turf' => 'turfs',);
$pluralRules = $corePluralRules;
$uninflected = $coreUninflectedPlural;
$irregular = $coreIrregularPlural;
if (file_exists(FRAMEWORK.'/includes/inflections.inc')) {
include(FRAMEWORK.'/includes/inflections.inc');
$pluralRules = array_merge($pluralRules, $corePluralRules);
$uninflected = array_merge($uninflectedPlural, $coreUninflectedPlural);
$irregular = array_merge($irregularPlural, $coreIrregularPlural);
}
$regexUninflected = self::enclose(join( '|', $uninflected));
$regexIrregular = self::enclose(join( '|', array_keys($irregular)));
if (preg_match('/^(' . $regexUninflected . ')$/i', $word, $regs)) {
return $word;
}
if (preg_match('/(.*)\\b(' . $regexIrregular . ')$/i', $word, $regs)) {
return $regs[1] . $irregular[strtolower($regs[2])];
}
foreach ($pluralRules as $rule => $replacement) {
if (preg_match($rule, $word)) {
$replace = preg_replace($rule, $replacement, $word);
return $replace;
}
}
return $word;
}
/**
* Return $word in singular form.
*
* @param string $word Word in plural
* @return string Word in singular
*/
public static function singularize($word) {
$coreSingularRules = array('/(s)tatuses$/i' => '\1\2tatus',
'/^(.*)(menu)s$/i' => '\1\2',
'/(quiz)zes$/i' => '\\1',
'/(matr)ices$/i' => '\1ix',
'/(vert|ind)ices$/i' => '\1ex',
'/^(ox)en/i' => '\1',
'/(alias)(es)*$/i' => '\1',
'/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|viri?)i$/i' => '\1us',
'/(cris|ax|test)es$/i' => '\1is',
'/(shoe)s$/i' => '\1',
'/(o)es$/i' => '\1',
'/ouses$/' => 'ouse',
'/uses$/' => 'us',
'/([m|l])ice$/i' => '\1ouse',
'/(x|ch|ss|sh)es$/i' => '\1',
'/(m)ovies$/i' => '\1\2ovie',
'/(s)eries$/i' => '\1\2eries',
'/([^aeiouy]|qu)ies$/i' => '\1y',
'/([lr])ves$/i' => '\1f',
'/(tive)s$/i' => '\1',
'/(hive)s$/i' => '\1',
'/(drive)s$/i' => '\1',
'/([^f])ves$/i' => '\1fe',
'/(^analy)ses$/i' => '\1sis',
'/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' => '\1\2sis',
'/([ti])a$/i' => '\1um',
'/(p)eople$/i' => '\1\2erson',
'/(m)en$/i' => '\1an',
'/(c)hildren$/i' => '\1\2hild',
'/(n)ews$/i' => '\1\2ews',
'/^(.*us)$/' => '\\1',
'/s$/i' => '');
$coreUninflectedSingular = array('.*[nrlm]ese', '.*deer', '.*fish', '.*measles', '.*ois', '.*pox', '.*sheep', '.*ss', 'Amoyese',
'bison', 'Borghese', 'bream', 'breeches', 'britches', 'buffalo', 'cantus', 'carp', 'chassis', 'clippers',
'cod', 'coitus', 'Congoese', 'contretemps', 'corps', 'debris', 'diabetes', 'djinn', 'eland', 'elk',
'equipment', 'Faroese', 'flounder', 'Foochowese', 'gallows', 'Genevese', 'Genoese', 'Gilbertese', 'graffiti',
'headquarters', 'herpes', 'hijinks', 'Hottentotese', 'information', 'innings', 'jackanapes', 'Kiplingese',
'Kongoese', 'Lucchese', 'mackerel', 'Maltese', 'media', 'mews', 'moose', 'mumps', 'Nankingese', 'news',
'nexus', 'Niasese', 'Pekingese', 'Piedmontese', 'pincers', 'Pistoiese', 'pliers', 'Portuguese', 'proceedings',
'rabies', 'rice', 'rhinoceros', 'salmon', 'Sarawakese', 'scissors', 'sea[- ]bass', 'series', 'Shavese', 'shears',
'siemens', 'species', 'swine', 'testes', 'trousers', 'trout', 'tuna', 'Vermontese', 'Wenchowese',
'whiting', 'wildebeest', 'Yengeese',);
$coreIrregularSingular = array('atlases' => 'atlas',
'beefs' => 'beef',
'brothers' => 'brother',
'children' => 'child',
'corpuses' => 'corpus',
'cows' => 'cow',
'ganglions' => 'ganglion',
'genies' => 'genie',
'genera' => 'genus',
'graffiti' => 'graffito',
'hoofs' => 'hoof',
'loaves' => 'loaf',
'men' => 'man',
'monies' => 'money',
'mongooses' => 'mongoose',
'moves' => 'move',
'mythoi' => 'mythos',
'numina' => 'numen',
'occiputs' => 'occiput',
'octopuses' => 'octopus',
'opuses' => 'opus',
'oxen' => 'ox',
'penises' => 'penis',
'people' => 'person',
'sexes' => 'sex',
'soliloquies' => 'soliloquy',
'testes' => 'testis',
'trilbys' => 'trilby',
'turfs' => 'turf',);
$singularRules = $coreSingularRules;
$uninflected = $coreUninflectedSingular;
$irregular = $coreIrregularSingular;
if (file_exists(FRAMEWORK.'/includes/inflections.inc')) {
include(FRAMEWORK.'/includes/inflections.inc');
$singularRules = array_merge($singularRules, $coreSingularRules);
$uninflected = array_merge($uninflectedSingular, $coreUninflectedSingular);
$irregular = array_merge($irregularSingular, $coreIrregularSingular);
}
$regexUninflected = self::enclose(join( '|', $uninflected));
$regexIrregular = self::enclose(join( '|', array_keys($irregular)));
if (preg_match('/^(' . $regexUninflected . ')$/i', $word, $regs)) {
return $word;
}
if (preg_match('/(.*)\\b(' . $regexIrregular . ')$/i', $word, $regs)) {
return $regs[1] . $irregular[strtolower($regs[2])];
}
foreach ($singularRules as $rule => $replacement) {
if (preg_match($rule, $word)) {
$replace = preg_replace($rule, $replacement, $word);
return $replace;
}
}
return $word;
}
/**
* Returns given $lower_case_and_underscored_word as a camelCased word.
*
* @param string $lower_case_and_underscored_word Word to camelize
* @return string Camelized word. likeThis.
*/
public static function camelize($lowerCaseAndUnderscoredWord) {
$replace = str_replace(" ", "", ucwords(str_replace("_", " ", $lowerCaseAndUnderscoredWord)));
return $replace;
}
/**
* Returns an underscore-syntaxed ($like_this_dear_reader) version of the $camel_cased_word.
*
* @param string $camel_cased_word Camel-cased word to be "underscorized"
* @return string Underscore-syntaxed version of the $camel_cased_word
*/
public static function underscore($camelCasedWord) {
$replace = strtolower(preg_replace('/(?<=\\w)([A-Z])/', '_\\1', $camelCasedWord));
return $replace;
}
/**
* Returns a human-readable string from $lower_case_and_underscored_word,
* by replacing underscores with a space, and by upper-casing the initial characters.
*
* @param string $lower_case_and_underscored_word String to be made more readable
* @return string Human-readable string
*/
public static function humanize($lowerCaseAndUnderscoredWord) {
$replace = ucwords(str_replace("_", " ", $lowerCaseAndUnderscoredWord));
return $replace;
}
/**
* Returns corresponding table name for given $class_name. ("posts" for the model class "Post").
*
* @param string $class_name Name of class to get database table name for
* @return string Name of the database table for given class
*/
public static function tableize($className) {
$replace = self::pluralize(self::underscore($className));
return $replace;
}
/**
* Returns Cake model class name ("Post" for the database table "posts".) for given database table.
*
* @param string $tableName Name of database table to get class name for
* @return string
*/
public static function classify($tableName) {
$replace = self::camelize(self::singularize($tableName));
return $replace;
}
/**
* Returns camelBacked version of a string.
*
* @param string $string
* @return string
* @access public
* @static
*/
public static function variable($string) {
$string = self::camelize(self::underscore($string));
$replace = strtolower(substr($string, 0, 1));
$variable = preg_replace('/\\w/', $replace, $string, 1);
return $variable;
}
/**
* Returns a string with all spaces converted to $replacement and non word characters removed.
*
* @param string $string
* @param string $replacement
* @return string
* @access public
* @static
*/
public static function slug($string, $replacement = '_') {
$string = preg_replace(array('/[^\w\s]/', '/\\s+/') , array(' ', $replacement), $string);
return $string;
}
/**
* Enclose a string for preg matching.
*
* @param string $string String to enclose
* @return string Enclosed string
*/
public static function enclose($string) {
return '(?:' . $string . ')';
}
}
?>

View File

@ -1,90 +0,0 @@
<?php
/**
* Handles authentication and password handling for all city LDAP people.
*
* Applications should extend this class for their own users. That way,
* a city employee will have the same username and password on all applications.
* Applications should use these public functions for their own users.
*
* @copyright 2006-2012 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
abstract class SystemUser
{
abstract public function getId();
abstract public function getUsername();
abstract public function getAuthenticationMethod();
abstract public function getRoles();
abstract public function hasRole($roles);
abstract public function setAuthenticationMethod($method);
abstract public function setRoles($roles);
abstract public function setUsername($username);
/**
* Passwords are set in clear text. The only times you would want to set a password
* is when you're adding a new password or changing a person's password.
* Either way, it's up to the individual save routines to handle encrypting the new password
* before storing it. Passwords should not be loaded in the constructor - they're
* supposed to be encrypted, so what's the point?
*/
abstract public function setPassword($password);
/**
* Used to hand authentication off to the application
*/
abstract protected function authenticateDatabase($password);
/**
* Used to hand password saving off to the application
*/
abstract protected function saveLocalPassword();
/**
* Determines which authentication scheme to use for the user and calls the appropriate method
*
* @param string $password
* @return boolean
*/
public function authenticate($password)
{
switch($this->getAuthenticationMethod()) {
case "local":
return $this->authenticateDatabase($password);
break;
default:
$type = $this->getAuthenticationMethod();
return $type::authenticate($this->getUsername(),$password);
}
}
/**
* Establishes a new Session and loads the default information for the user
*/
public function startNewSession()
{
session_destroy();
session_start();
$_SESSION['USER'] = $this;
$_SESSION['IP_ADDRESS'] = $_SERVER['REMOTE_ADDR'];
}
/**
* Used to save passwords to the database
*
* Only local passwords should be saved. External Identities should have
* their own methods for users to change passwords
*/
public function savePassword()
{
switch($this->getAuthenticationMethod()) {
case "local":
$this->saveLocalPassword();
break;
}
}
}

View File

@ -1,105 +0,0 @@
<?php
/**
* Defines the overall page layout
*
* The template collects all the blocks from the controller
*
* @copyright 2006-2009 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
class Template extends View
{
private $filename;
public $outputFormat = 'html';
public $blocks = array();
/**
* @param string $filename
* @param string $outputFormat
* @param array $vars
*/
public function __construct($filename='default',$outputFormat='html',array $vars=null)
{
$this->filename = $filename;
$this->outputFormat = preg_replace('/[^a-zA-Z]/','',$outputFormat);
// Make sure the output format exists
if (!is_file(APPLICATION_HOME."/templates/{$this->outputFormat}/{$this->filename}.inc")) {
$this->filename = 'default';
$this->outputFormat = 'html';
}
if (count($vars)) {
foreach ($vars as $name=>$value) {
$this->vars[$name] = $value;
}
}
}
/**
* Returns all the rendered content of the template
*
* Template files must include a call to $this->includeBlocks(),
* when they're ready for content
*
* @return string
*/
public function render()
{
ob_start();
include APPLICATION_HOME."/templates/{$this->outputFormat}/{$this->filename}.inc";
return ob_get_clean();
}
/**
* Callback function for template files
*
* Renders blocks for the main content area, unless $panel is given. If $panel is given
* it will render any blocks that the controllers have assigned to that panel.
*
* Template files make calls to this function to render all the blocks that the controller
* has loaded for this Template. Controllers will populate the blocks array with content.
* If a template file can render content in a panel that is not the main content panel,
* the template file will need to include the panel's name in the includeBlocks() call.
*
* $this->blocks is a multi-dimensional array. The top level elements, non-array elements
* are for the default, main content area. Other panels will be arrays in $this->blocks with
* the panel name as the key.
*
* Panels are nothing but a name on a div, the $panel string can be whatever the template
* author thinks makes sense. Controllers are expected to know what the template authors
* have written.
*
* $this->blocks[] = "main content block one";
* $this->blocks[] = "main content block two";
* $this->blocks['panel-one'][] = "left sidebar block one";
* $this->blocks['panel-one'][] = "left sidebar block two";
* $this->blocks['panel-two'][] = "right sidebar block one";
*
* @param string $panel
* @return string
*/
private function includeBlocks($panel=null)
{
ob_start();
if ($panel) {
// Render any blocks for the given panel
if (isset($this->blocks[$panel]) && is_array($this->blocks[$panel])) {
foreach ($this->blocks[$panel] as $block) {
echo $block->render($this->outputFormat);
}
}
}
else {
// Render only the blocks for the main content area
foreach ($this->blocks as $block) {
if (!is_array($block)) {
echo $block->render($this->outputFormat);
}
}
}
return ob_get_clean();
}
}

View File

@ -1,89 +0,0 @@
<?php
/**
* @copyright 2006-2009 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*/
abstract class View
{
protected $vars = array();
abstract public function render();
/**
* Magic Method for setting object properties
* @param string $key
* @param mixed $value
*/
public function __set($key,$value) {
$this->vars[$key] = $value;
}
/**
* Magic method for getting object properties
* @param string $key
* @return mixed
*/
public function __get($key)
{
if (isset($this->vars[$key])) {
return $this->vars[$key];
}
return null;
}
/**
* @param string $key
* @return boolean
*/
public function __isset($key) {
return array_key_exists($key,$this->vars);
}
/**
* Cleans strings for output
*
* There are more bad characters than htmlspecialchars deals with. We just want
* to add in some other characters to clean. While here, we might as well
* have it trim out the whitespace too.
*
* @param array|string $string
* @param CONSTANT $quotes Optional, the desired constant to use for the htmlspecidalchars call
* @return string
*/
public static function escape($input,$quotes=ENT_QUOTES)
{
if (is_array($input)) {
foreach ($input as $key=>$value) {
$input[$key] = self::escape($value,$quotes);
}
}
else {
$input = htmlspecialchars(trim($input),$quotes);
}
return $input;
}
/**
* Return the first $n words of the given string
*
* @param string $string Source string
* @param int $numWords Number of words
* @return string
*/
public static function limitWords($string,$numWords)
{
$output = '';
$words = preg_split('/\s+/',$string);
$c = 0;
foreach ($words as $word) {
$output.= "$word ";
$c++;
if ($c >= $numWords) {
$output.= '...';
break;
}
}
return $output;
}
}

View File

@ -1,181 +0,0 @@
<?php
/**
* @copyright 2009 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
*
*/
abstract class ZendDbResultIterator implements ArrayAccess,SeekableIterator,Countable
{
protected $zend_db;
protected $select;
protected $result = array();
protected $paginator = null;
protected $itemsPerPage = null;
protected $currentPage = 1;
private $valid = false;
private $cacheEnabled = true;
private $cache = array();
private $key;
abstract public function find($fields=null,$order='',$limit=null,$groupBy=null);
abstract protected function loadResult($key);
/**
* Creates an empty collection
*
* Setting itemsPerPage turns on pagination mode
* In pagination mode, this will only load the results for one page
*/
public function __construct($itemsPerPage=null,$currentPage=null)
{
$this->zend_db = Database::getConnection();
$this->select = new Zend_Db_Select($this->zend_db);
if ($itemsPerPage) {
$this->itemsPerPage = (integer)$itemsPerPage;
if ($currentPage && $currentPage > 1) {
$this->currentPage = $currentPage;
}
}
}
/**
* Runs the query and stores the results
*
* In pagination mode, this will only load the results for one page
*/
protected function populateList()
{
$this->result = array();
if (!$this->itemsPerPage) {
$this->result = $this->zend_db->fetchAll($this->select);
}
else {
// Only load the results for one page
$this->paginator = new Zend_Paginator(new Zend_Paginator_Adapter_DbSelect($this->select));
$this->paginator->setItemCountPerPage($this->itemsPerPage);
$this->paginator->setCurrentPageNumber($this->currentPage);
foreach ($this->paginator as $row) {
$this->result[] = $row;
}
}
}
/**
* @return string
*/
public function getSQL()
{
return $this->select->__toString();
}
/**
* @return Zend_Paginator
*/
public function getPaginator()
{
return $this->paginator;
}
// Array Access section
/**
* @param int $offset
* @return boolean
*/
public function offsetExists($offset) {
return array_key_exists($offset,$this->result);
}
/**
* Unimplemented stub requried for interface compliance
* @ignore
*/
public function offsetSet($offset,$value) { } // Read-only for now
/**
* Unimplemented stub requried for interface compliance
* @ignore
*/
public function offsetUnset($offset) { } // Read-only for now
/**
* @param int $offset
* @return mixed
*/
public function offsetGet($offset)
{
if ($this->offsetExists($offset)) {
return $this->loadResult($offset);
}
else {
throw new OutOfBoundsException('Invalid seek position');
}
}
// SPLIterator Section
/**
* Reset the pionter to the first element
*/
public function rewind() {
$this->key = 0;
}
/**
* Advance to the next element
*/
public function next() {
$this->key++;
}
/**
* Return the index of the current element
* @return int
*/
public function key() {
return $this->key;
}
/**
* @return boolean
*/
public function valid() {
return array_key_exists($this->key,$this->result);
}
/**
* @return mixed
*/
public function current()
{
return $this->loadResult($this->key);
}
/**
* @param int $index
*/
public function seek($index)
{
if (isset($this->result[$index])) {
$this->key = $index;
}
else {
throw new OutOfBoundsException('Invalid seek position');
}
}
/**
* @return Iterator
*/
public function getIterator()
{
return $this;
}
// Countable Section
/**
* @return int
*/
public function count()
{
return count($this->result);
}
}

View File

@ -1,167 +0,0 @@
<?php
/**
* Global, shared functions for all PHP web applications
* @copyright 2006-2009 City of Bloomington, Indiana.
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
* @author Cliff Ingham <inghamn@bloomington.in.gov>
* @package GlobalFunctions
*/
/**
* Load classes on the fly as needed
* @param string $class
*/
function autoload($class)
{
if (file_exists(APPLICATION_HOME."/classes/$class.php")) {
require_once(APPLICATION_HOME."/classes/$class.php");
}
elseif (file_exists(FRAMEWORK."/classes/$class.php")) {
require_once(FRAMEWORK."/classes/$class.php");
}
}
/**
* Provide nicely formatted error messages when PHP bombs out.
*/
function customErrorHandler ($errno, $errstr, $errfile, $errline)
{
global $ERROR_REPORTING;
if (isset($ERROR_REPORTING)) {
if (in_array('PRETTY_PRINT',$ERROR_REPORTING)) {
echo "
<div id=\"errorMessages\">
<p><em>from ".ADMINISTRATOR_NAME.":</em>
There is an error in the code on this page that is through no fault of your own.
Errors of this sort need to be fixed immediately, though.
Please help us out by copying and pasting the following error message into an email and sending it to me at
<a href=\"mailto:".ADMINISTRATOR_EMAIL."\">".ADMINISTRATOR_EMAIL."</a>.
</p>
<p><strong>Code Error:</strong> Error on line $errline of file $errfile:</p>
<p>$errstr</p>
</div>
";
}
if (in_array('EMAIL_ADMIN',$ERROR_REPORTING)) {
$subject = APPLICATION_NAME.' Error';
$message = "\t$_SERVER[REQUEST_URI]\n\nError on line $errline of file $errfile:\n$errstr\n\n";
$message.= print_r(debug_backtrace(),true);
mail(ADMINISTRATOR_EMAIL,$subject,$message,"From: apache@$_SERVER[SERVER_NAME]");
}
if (in_array('EMAIL_USER',$ERROR_REPORTING)
&& isset($_SESSION['USER'])
&& $_SESSION['USER']->getEmail()) {
$subject = APPLICATION_NAME.' Error';
$message = "\t$_SERVER[REQUEST_URI]\n\nError on line $errline of file $errfile:\n$errstr\n\n";
$message.= print_r(debug_backtrace(),true);
mail($_SESSION['USER']->getEmail(),
$subject,
$message,
"From: apache@$_SERVER[SERVER_NAME]");
}
if (in_array('SKIDDER',$ERROR_REPORTING)) {
$message = "Error on line $errline of file $errfile:\n$errstr\n";
$message.= print_r(debug_backtrace(),true);
$skidder = curl_init(SKIDDER_URL);
curl_setopt($skidder,CURLOPT_POST,true);
curl_setopt($skidder,CURLOPT_HEADER,true);
curl_setopt($skidder,CURLOPT_RETURNTRANSFER,true);
curl_setopt($skidder,
CURLOPT_POSTFIELDS,
array('application_id'=>SKIDDER_APPLICATION_ID,
'script'=>$_SERVER['REQUEST_URI'],
'type'=>$errstr,
'message'=>$message));
curl_exec($skidder);
}
}
}
if (ERROR_REPORTING != 'PHP_DEFAULT') {
set_error_handler('customErrorHandler');
}
/**
* Object oriented exceptions are handled differently from other PHP errors.
*/
function customExceptionHandler($exception)
{
global $ERROR_REPORTING;
if (isset($ERROR_REPORTING)) {
if (in_array('PRETTY_PRINT',$ERROR_REPORTING)) {
echo "
<div id=\"errorMessages\">
<p><em>from ".ADMINISTRATOR_NAME.":</em>
There is an error in the code on this page that is through no fault of your own.
Errors of this sort need to be fixed immediately, though.
Please help me out by copying and pasting the following error message into an email and sending it to me at
<a href=\"mailto:".ADMINISTRATOR_EMAIL."\">".ADMINISTRATOR_EMAIL."</a>.
</p>
<p><strong>Uncaught exception:</strong>
Exception on line {$exception->getLine()} of file {$exception->getFile()}:
</p>
<p>{$exception->getMessage()}</p>
</div>
";
}
if (in_array('EMAIL_ADMIN',$ERROR_REPORTING)) {
$subject = APPLICATION_NAME.' Exception';
$message = "\t$_SERVER[REQUEST_URI]\n\nException on line {$exception->getLine()} of file {$exception->getFile()}:\n{$exception->getMessage()}\n\n";
$message.= print_r(debug_backtrace(),true);
mail(ADMINISTRATOR_EMAIL,$subject,$message,"From: apache@$_SERVER[SERVER_NAME]");
}
if (in_array('EMAIL_USER',$ERROR_REPORTING)
&& isset($_SESSION['USER'])
&& $_SESSION['USER']->getEmail()) {
$subject = APPLICATION_NAME.' Exception';
$message = "\t$_SERVER[REQUEST_URI]\n\nException on line {$exception->getLine()} of file {$exception->getFile()}:\n{$exception->getMessage()}\n\n";
$message.= print_r(debug_backtrace(),true);
mail($_SESSION['USER']->getEmail(),
$subject,
$message,
"From: apache@$_SERVER[SERVER_NAME]");
}
if (in_array('SKIDDER',$ERROR_REPORTING)) {
$message = "Error on line {$exception->getLine()} of file {$exception->getFile()}:\n{$exception->getMessage()}\n";
$message.= print_r(debug_backtrace(),true);
$skidder = curl_init(SKIDDER_URL);
curl_setopt($skidder,CURLOPT_POST,true);
curl_setopt($skidder,CURLOPT_HEADER,true);
curl_setopt($skidder,CURLOPT_RETURNTRANSFER,true);
curl_setopt($skidder,
CURLOPT_POSTFIELDS,
array('application_id'=>SKIDDER_APPLICATION_ID,
'script'=>$_SERVER['REQUEST_URI'],
'type'=>'Uncaught Exception',
'message'=>$message));
curl_exec($skidder);
}
}
}
if (ERROR_REPORTING != 'PHP_DEFAULT') {
set_exception_handler('customExceptionHandler');
}
/**
* Checks if the user is logged in and is supposed to have acces to the resource
*
* This is implemented by checking against a Zend_Acl object
* The Zend_Acl should be created in configuration.inc
* @param Zend_Acl_Resource|string $resource
* @return boolean
*/
function userIsAllowed($resource)
{
global $ZEND_ACL;
if (isset($_SESSION['USER'])) {
foreach ($_SESSION['USER']->getRoles() as $role) {
if ($ZEND_ACL->isAllowed($role,$resource)) {
return true;
}
}
}
return false;
}

View File

@ -1,68 +0,0 @@
<?php
/* SVN FILE: $Id: inflections.php 3028 2006-06-08 02:18:18Z phpnut $ */
/**
* Custom Inflected Words.
*
* This file is used to hold words that are not matched in the normail Inflector::pluralize() and
* Inflector::singularize()
*
* Orinally written by the CakePHP Project
* CakePHP : Rapid Development Framework <http://www.cakephp.org/>
* Copyright (c) 2006, Cake Software Foundation, Inc.
* 1785 E. Sahara Avenue, Suite 490-204
* Las Vegas, Nevada 89104
*
* Licensed under The MIT License
* Redistributions of files must retain the above copyright notice.
* @copyright Copyright (c) 2006, Cake Software Foundation, Inc.
* @license http://www.opensource.org/licenses/mit-license.php The MIT License
*
* Modified to work in City of Bloomington's Framework
* Relicensed under GPL
* Redistributions must retain all copyright notices
* @copyright 2006 City of Bloomington, Indiana
* @license http://www.gnu.org/licenses/agpl.txt GNU/AGPL, see LICENSE.txt
*/
/**
* This is a key => value array of regex used to match words.
* If key matches then the value is returned.
*
* $pluralRules = array('/(s)tatus$/i' => '\1\2tatuses', '/^(ox)$/i' => '\1\2en', '/([m|l])ouse$/i' => '\1ice');
*/
$pluralRules = array();
/**
* This is a key only array of plural words that should not be inflected.
* Notice the last comma
*
* $uninflectedPlural = array('.*[nrlm]ese', '.*deer', '.*fish', '.*measles', '.*ois', '.*pox');
*/
$uninflectedPlural = array();
/**
* This is a key => value array of plural irregular words.
* If key matches then the value is returned.
*
* $irregularPlural = array('atlas' => 'atlases', 'beef' => 'beefs', 'brother' => 'brothers')
*/
$irregularPlural = array();
/**
* This is a key => value array of regex used to match words.
* If key matches then the value is returned.
*
* $singularRules = array('/(s)tatuses$/i' => '\1\2tatus', '/(matr)ices$/i' =>'\1ix','/(vert|ind)ices$/i')
*/
$singularRules = array();
/**
* This is a key only array of singular words that should not be inflected.
* You should not have to change this value below if you do change it use same format
* as the $uninflectedPlural above.
*/
$uninflectedSingular = $uninflectedPlural;
/**
* This is a key => value array of singular irregular words.
* Most of the time this will be a reverse of the above $irregularPlural array
* You should not have to change this value below if you do change it use same format
*
* $irregularSingular = array('atlases' => 'atlas', 'beefs' => 'beef', 'brothers' => 'brother')
*/
$irregularSingular = array_flip($irregularPlural);
?>

1
libraries/phpCAS Submodule

@ -0,0 +1 @@
Subproject commit 12d6f65aa0ed31e5503c7f7aed13b742dbc35b53

1
libraries/zf2 Submodule

@ -0,0 +1 @@
Subproject commit b1e33265a731aab365aad59a7263f557d0cfdd08

View File

@ -0,0 +1,15 @@
alter table people add username varchar(40) unique;
alter table people add password varchar(40);
alter table people add authenticationMethod varchar(40);
alter table people add role varchar(30);
update people p, users u
set p.username=u.username, p.authenticationMethod=u.authenticationMethod
where p.id=u.person_id;
update people set role='Staff';
update people set role='Administrator' where id=1;
drop table user_roles;
drop table roles;
drop table users;

View File

@ -1,36 +1,16 @@
-- @copyright 2009 City of Bloomington, Indiana
-- @copyright 2009-2014 City of Bloomington, Indiana
-- @license http://www.gnu.org/copyleft/gpl.html GNU/GPL, see LICENSE.txt
-- @author Cliff Ingham <inghamn@bloomington.in.gov>
create table people (
id int unsigned not null primary key auto_increment,
firstname varchar(128) not null,
lastname varchar(128) not null,
email varchar(255) not null
) engine=InnoDB;
create table users (
id int unsigned not null primary key auto_increment,
person_id int unsigned not null unique,
username varchar(30) not null unique,
password varchar(32),
authenticationMethod varchar(40) not null default 'LDAP',
foreign key (person_id) references people(id)
) engine=InnoDB;
create table roles (
id int unsigned not null primary key auto_increment,
name varchar(30) not null unique
) engine=InnoDB;
insert roles values(1,'Administrator');
insert roles values(2,'Editor');
create table user_roles (
user_id int unsigned not null,
role_id int unsigned not null,
primary key (user_id,role_id),
foreign key(user_id) references users (id),
foreign key(role_id) references roles (id)
) engine=InnoDB;
id int unsigned not null primary key auto_increment,
firstname varchar(128) not null,
lastname varchar(128) not null,
email varchar(255) not null,
username varchar(40) unique,
password varchar(40),
authenticationMethod varchar(40),
role varchar(30)
);
create table cemeteries (
id int unsigned not null primary key auto_increment,