/** * The recursive method powering addRouteFor(Request). * * @param array Part of a path in reverse order. * @param int Current index of path part array - decrements with each step. * @param Route The route being added * * @return FindRouteResult */ private function addRouteRecursively(&$pathParts, $index, $route) { // Base Case if ($index < 0) { foreach ($route->methods as $method) { if (isset($this->m[$method])) { Library::import('recess.framework.routing.DuplicateRouteException'); throw new DuplicateRouteException($method . ' ' . str_replace('//', '/', $route->path), $route->fileDefined, $route->lineDefined); } $this->m[$method] = new Rt($route); } return; } $nextPart = $pathParts[$index]; if ($nextPart[0] != '$') { $childrenArray =& $this->s; $nextKey = $nextPart; $isParam = false; } else { $childrenArray =& $this->p; $nextKey = substr($nextPart, 1); $isParam = true; } if (!isset($childrenArray[$nextKey])) { $child = new RtNode(); if ($isParam) { $child->c = $nextKey; } $childrenArray[$nextKey] = $child; } else { $child = $childrenArray[$nextKey]; } $child->addRouteRecursively($pathParts, $index - 1, $route); }
/** * Transform a model descriptor to a table descriptor. * * @param ModelDescriptor $descriptor * @return RecessTableDescriptor */ function modelToTableDescriptor(ModelDescriptor $descriptor) { Library::import('recess.database.pdo.RecessTableDescriptor'); Library::import('recess.database.pdo.RecessColumnDescriptor'); $tableDescriptor = new RecessTableDescriptor(); $tableDescriptor->name = $descriptor->getTable(); foreach ($descriptor->properties as $property) { $tableDescriptor->addColumn($property->name, $property->type, true, $property->isPrimaryKey, array(), $property->isAutoIncrement ? array('autoincrement' => true) : array()); } return $tableDescriptor; }
/** * Import and (as required) initialize helpers for use in the view. * Helper is the path and name of a class as used by Library::import(). * For multiple helpers, pass a single array of helpers or use multiple arguments. * * @param $helper */ public function loadHelper($helper) { $helpers = is_array($helper) ? $helper : func_get_args(); foreach ($helpers as $helper) { Library::import($helper); $init = array(Library::getClassName($helper), 'init'); if (is_callable($init)) { call_user_func($init, $this); } } }
/** * Retrieve the a table's RecessTableDescriptor. * * @param string $table Name of table. * @return RecessTableDescriptor */ function getTableDescriptor($table) { Library::import('recess.database.pdo.RecessTableDescriptor'); $tableDescriptor = new RecessTableDescriptor(); $tableDescriptor->name = $table; try { $results = $this->pdo->query('SHOW COLUMNS FROM ' . $table . ';'); $tableDescriptor->tableExists = true; } catch (PDOException $e) { $tableDescriptor->tableExists = false; return $tableDescriptor; } foreach ($results as $result) { $tableDescriptor->addColumn($result['Field'], $this->getRecessType($result['Type']), $result['Null'] == 'NO' ? false : true, $result['Key'] == 'PRI' ? true : false, $result['Default'] == null ? '' : $result['Default'], $result['Extra'] == 'auto_increment' ? array('autoincrement' => true) : array()); } return $tableDescriptor; }
function getAnnotations() { Library::import('recess.lang.Annotation'); $docstring = $this->getDocComment(); if ($docstring == '') { return array(); } else { $returns = array(); try { $returns = Annotation::parse($docstring); } catch (InvalidAnnotationValueException $e) { throw new InvalidAnnotationValueException('In class "' . $this->name . '".' . $e->getMessage(), 0, 0, $this->getFileName(), $this->getStartLine(), array()); } catch (UnknownAnnotationException $e) { throw new UnknownAnnotationException('In class "' . $this->name . '".' . $e->getMessage(), 0, 0, $this->getFileName(), $this->getStartLine(), array()); } } return $returns; }
<?php Library::import('recess.framework.Application'); class WelcomeApplication extends Application { public function __construct() { $this->name = 'Welcome to Recess (GC)'; $this->viewsDir = $_ENV['dir.apps'] . 'welcome/views/'; $this->modelsPrefix = 'welcome.models.'; $this->controllersPrefix = 'welcome.controllers.'; $this->routingPrefix = '/'; $this->assetUrl = 'recess/recess/apps/tools/public/'; } }
* distribute, sublicense, and/or sell copies of the Software, and to * permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ Library::import('recess.lang.Annotation'); class LabelAnnotation extends Annotation { public function isFor() { return Annotation::FOR_PROPERTY; } public function usage() { return '!Label "Column Label"'; } public function expand($class, $reflection, $descriptor) { $propertyName = $reflection->getName(); if (isset($descriptor->properties[$propertyName])) { $property =& $descriptor->properties[$propertyName];
<?php Library::import('recess.framework.forms.FormInput'); class PasswordInput extends FormInput { function render() { echo '<input type="password" name="', $this->name, '"', ' id="' . $this->name . '"'; if ($this->class != '') { echo ' class="', $this->class, '"'; } if ($this->value != '') { echo ' value="', $this->value, '"'; } echo ' />'; } } ?>
* permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ Library::import('ValidationPlugin.annotations.ValidatesAnnotation'); Library::import('ValidationPlugin.wrappers.ValidatesPresenceOfWrapper'); // // ValidatesPresenceOf // // This annotation adds a validator to a Model class that ensures // the specified fields' values are set and not empty. // // USAGE: // // /** // * !ValidatesPresenceOf Fields: (title, author), On: (save, insert, update) // */ // class Book extends Model { // public $title; // public $author; // }
<?php Library::import('recess.framework.controllers.Controller'); /** * !RespondsWith Layouts * !Prefix Views: home/, Routes: / */ class IconHarvesterHomeController extends Controller { /** !Route GET */ function index() { $this->redirect('ThemeController::index'); } }
<?php Library::import('recess.database.sql.ISqlSelectOptions'); Library::import('recess.database.sql.ISqlConditions'); /** * PdoDataSet is used as a proxy to query results that is realized once the results are * iterated over or accessed using array notation. Queries can thus be built incrementally * and an SQL request will only be issued once needed. * * Example usage: * * $results = new PdoDataSet(Databases::getDefault()); * $results->from('tableName')->equal('someColumn', 'Hi')->limit(10)->offset(50); * foreach($results as $result) { // This is when the query is run! * print_r($result); * } * * @author Kris Jordan <*****@*****.**> * @copyright 2008, 2009 Kris Jordan * @package Recess PHP Framework * @license MIT * @link http://www.recessframework.org/ */ class PdoDataSet implements Iterator, Countable, ArrayAccess, ISqlSelectOptions, ISqlConditions { /** * The SqlBuilder instance we use to build up the query string. * * @var SqlBuilder */ protected $sqlBuilder;
<?php require_once 'PHPUnit/Framework.php'; Library::import('recess.lang.Object'); class MyObject extends Object { } class MyNewClassMethodProvider { function callMe() { return 'Hello World!'; } } class ObjectTest extends PHPUnit_Framework_TestCase { function testAttachedMethod() { $myObject = new MyObject(); try { $this->assertEquals('Hello World!', $myObject->helloWorld()); $this->hasFailed(); } catch (RecessException $e) { // Success } $attachedMethodProvider = new MyNewClassMethodProvider(); MyObject::attachMethod('MyObject', 'helloWorld', $attachedMethodProvider, 'callMe'); try { $this->assertEquals($myObject->helloWorld(), 'Hello World!'); // Success } catch (RecessException $e) {
<?php Library::import('recess.lang.codegen.CodeGenClassMember'); /** * @author Kris Jordan <*****@*****.**> * @copyright 2008, 2009 Kris Jordan * @package Recess PHP Framework * @license MIT * @link http://www.recessframework.org/ */ class CodeGenMethod extends CodeGenClassMember { function toCode($blockIndent = '') { $code = $this->doccomment->toCode(); $method; if ($this->accessLevel != CodeGen::PUB) { $method = $this->accessLevel; } if ($method != '') { $method .= ' '; } if ($this->isStatic) { $method .= CodeGen::STAT; } if ($method != '') { $method .= ' '; } $method .= 'function ' . $this->name . ' {};'; $code .= $method; return $code;
* permit persons to whom the Software is furnished to do so, subject to * the following conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ Library::import('recesss.lang.Annotation'); Library::import('PaginationPlugin.models.PaginatorDelegate'); /** * Pagination Annotation * * This annotation attaches the paginate() method to a Model object. * * USAGE: * * !Paginate Limit: 5 * * Limit: * - Optional * - Determines the number of results to show per page * * @author Josh Lockhart <*****@*****.**> * @since Verson 1.0
/** !Route GET, model/gen/analyzeModelName/$modelName */ public function analyzeModelName($modelName) { Library::import('recess.lang.Inflector'); $this->tableName = Inflector::toPlural(Inflector::toUnderscores($modelName)); $this->isValid = preg_match('/^[a-zA-Z][_a-zA-z0-9]*$/', $modelName) == 1; }
<?php Library::import('recess.lang.Annotation'); Library::import('recess.database.pdo.RecessType'); /** * An annotation used on Model properties which specifies information about the column * a given property maps to in the data source. * * @author Kris Jordan <*****@*****.**> * @copyright 2008, 2009 Kris Jordan * @package Recess PHP Framework * @license MIT * @link http://www.recessframework.org/ */ class ColumnAnnotation extends Annotation { const PRIMARY_KEY = 'PrimaryKey'; const AUTO_INCREMENT = 'AutoIncrement'; public function usage() { return '!Column type [, PrimaryKey] [, AutoIncrement]'; } public function isFor() { return Annotation::FOR_PROPERTY; } protected function validate($class) { $this->acceptsNoKeyedValues(); $this->minimumParameterCount(1); $this->maximumParameterCount(3);
static function getRoutes() { Library::import('recess.framework.routing.RtNode'); Library::import('recess.framework.routing.Route'); $router = Cache::get(self::ROUTES_CACHE_KEY); if ($router === false) { $router = new RtNode(); foreach (self::$applications as $app) { try { $app->addRoutesToRouter($router); } catch (DuplicateRouteException $e) { throw new RecessErrorException("Conflicting routes found: " . $e->getMessage(), 0, 0, $e->file, $e->line, array()); } } Cache::set(self::ROUTES_CACHE_KEY, $router); } return $router; }
function urlTo($methodName) { $args = func_get_args(); list($controllerName, $methodName) = explode('::', $methodName, 2); $args[0] = $methodName; Library::import($this->controllersPrefix . $controllerName); $controller = new $controllerName($this); return call_user_func_array(array($controller, 'urlTo'), $args); }
<?php Library::import('recess.http.Request'); Library::import('recess.http.Methods'); Library::import('recess.http.Accepts'); /** * @author Kris Jordan <*****@*****.**> * @contributor Luiz Alberto Zaiats * * @copyright 2008, 2009 Kris Jordan * @package Recess PHP Framework * @license MIT * @link http://www.recessframework.org/ */ class Environment { public static function getRawRequest() { $request = new Request(); $request->method = $_SERVER['REQUEST_METHOD']; $request->format = 'html'; $request->setResource(self::stripQueryString($_SERVER['REQUEST_URI'])); $request->get = $_GET; $request->post = $_POST; if ($request->method == Methods::POST || $request->method == Methods::PUT) { $request->input = file_get_contents('php://input'); if ($request->method == Methods::POST) { $request->post = $_POST; } else { $request->put = self::getPutParameters($request->input); }
<?php Library::import('recess.database.orm.annotations'); /** * An annotation used on Model Classes, the Database annotations sets the name * of the data source (Databases::getSource($name)) this Model should talk to. * * @author Kris Jordan <*****@*****.**> * @copyright 2008, 2009 Kris Jordan * @package Recess PHP Framework * @license MIT * @link http://www.recessframework.org/ */ class DatabaseAnnotation extends Annotation { public function usage() { return '!Database databaseName'; } public function isFor() { return Annotation::FOR_CLASS; } protected function validate($class) { $this->acceptsNoKeyedValues(); $this->exactParameterCount(1); $this->validOnSubclassesOf($class, Model::CLASSNAME); } protected function expand($class, $reflection, $descriptor) {
<?php Library::import('recess.lang.Annotation'); Library::import('KrisJordan.recess-annotation-examples.UnsafeProtectionWrapper'); class UnsafeProtectionAnnotation extends Annotation { public function usage() { return '!UnsafeProtection User: [user], Pass: [password], UnauthorizedAction: [action]'; } public function isFor() { return Annotation::FOR_CLASS; } protected function validate($class) { $this->exactParameterCount(3); // Keys are strtolower'ed $this->acceptedKeys(array('unauthorizedaction', 'user', 'pass')); $this->acceptsNoKeylessValues(); $this->validOnSubclassesOf($class, 'Controller'); } protected function expand($class, $reflection, $descriptor) { // Our goal here is to wrap an UnsafeProtectionWrapper // around a controller's serve method. $username = $this->user; $password = $this->pass; $unauthorizedAction = $this->unauthorizedaction; $descriptor->addWrapper('serve', new UnsafeProtectionWrapper($username, $password, $unauthorizedAction)); // I just realized how unfortunate and inappropriately
<?php Library::import('recess.database.pdo.exceptions.DataSourceCouldNotConnectException'); Library::import('recess.database.pdo.exceptions.ProviderDoesNotExistException'); Library::import('recess.database.pdo.PdoDataSet'); Library::import('recess.database.pdo.RecessTableDescriptor'); Library::import('recess.database.pdo.RecessColumnDescriptor'); /** * A PDO wrapper in the Recess PHP Framework that provides a single interface for commonly * needed operations (i.e.: list tables, list columns in a table, etc). * * @author Kris Jordan <*****@*****.**> * @copyright 2008, 2009 Kris Jordan * @package Recess PHP Framework * @license MIT * @link http://www.recessframework.org/ */ class PdoDataSource extends PDO { const PROVIDER_CLASS_LOCATION = 'recess.database.pdo.'; const PROVIDER_CLASS_SUFFIX = 'DataSourceProvider'; const CACHE_PREFIX = 'Recess::PdoDS::'; protected $provider = null; protected $cachePrefix; /** * Creates a data source instance to represent a connection to the database. * The first argument can either be a string DSN or an array which contains * the construction arguments. * * @param mixed $dsn String DSN or array of arguments (dsn, username, password) * @param string $username
<?php Library::import('recess.framework.helpers.blocks.Block'); Library::import('recess.framework.helpers.blocks.HtmlBlock'); Library::import('recess.framework.helpers.blocks.ListBlock'); Library::import('recess.framework.AbstractHelper'); /** * Buffer is a helper class that acts as a factory for * HtmlBlocks. Buffer and blocks are often used in conjunction * with layouts as an easy mechanism for transferring chunks of * HTML from a child template to a parent Layout. * * Buffer can be used to fill unempty HtmlBlocks, * overwrite HtmlBlocks, or append/prepend to them. Here are some * example usages: * * Buffer::to($block); * echo 'hello world'; * Buffer::end(); * // $block is now an HtmlBlock with contents 'hello world' * * Buffer::append($block); * echo '!<br />'; * Buffer::end(); * // $block is now an HtmlBlock with contents 'hello world!<br />' * * Buffer::to($block); * print_r($block); * Block::end(); * // $block is still 'hello world!<br />' *
<?php Library::import('recess.lang.codegen.CodeGen', true); class ModelGen { static function toCode(ModelDescriptor $descriptor) { $classFile = new CodeGenClassFile(); $class = new CodeGenClass($descriptor->modelClass); $class->setExtends('Model'); $classFile->addClass($class); $classDocComment = new CodeGenDocComment(); $classDocComment->addLine('!Database ' . $descriptor->source); $classDocComment->addLine('!Table ' . $descriptor->getTable()); $class->setDocComment($classDocComment); foreach ($descriptor->properties as $prop) { $property = new CodeGenProperty($prop->name); $columnDocComment = '!Column '; if ($prop->isPrimaryKey) { $columnDocComment .= 'PrimaryKey, '; } $columnDocComment .= $prop->type; if ($prop->isAutoIncrement) { $columnDocComment .= ', AutoIncrement'; } $propertyDocComment = new CodeGenDocComment($columnDocComment); $property->setDocComment($propertyDocComment); $class->addProperty($property); } return $classFile->toCode(); }
<?php Library::import('recess.framework.AbstractView'); class NativeView extends AbstractView { protected function getTemplateFor($response) { $format = $response->request->accepts->format(); if (is_string($format)) { $extension = ".{$format}.php"; } else { $extension = '.php'; } $template = $response->meta->viewsPrefix . $response->meta->viewName . $extension; return $template; } public function canRespondWith(Response $response) { // TODO: Cache in production mode return Application::active()->findView($this->getTemplateFor($response)); } protected function render(Response $response) { $context = $response->data; $context['viewsDir'] = $response->meta->app->getViewsDir(); extract($context); include $this->getTemplateFor($response); } }
<?php Library::import('recess.lang.Inflector'); Library::import('recess.database.pdo.PdoDataSet'); class ModelSet extends PdoDataSet { function __call($name, $arguments) { if (empty($arguments)) { $descriptor = Model::getDescriptor($this->rowClass); $attachedMethod = $descriptor->getAttachedMethod($name); if (!$attachedMethod) { if (Inflector::isPlural($name)) { $attachedMethod = $descriptor->getAttachedMethod(Inflector::toSingular($name)); } } if ($attachedMethod) { $params = $attachedMethod->getParameters(); if (count($params) === 0) { return call_user_func(array($attachedMethod->object, $attachedMethod->method), $this); } } } throw new RecessException('Method "' . $name . '" does not exist on ModelSet nor is attached to ' . $this->rowClass . '.', get_defined_vars()); } function update() { return $this->source->executeStatement($this->sqlBuilder->useAssignmentsAsConditions(false)->update(), $this->sqlBuilder->getPdoArguments()); } function delete($cascade = true) {
Library::import('recess.lang.Inflector'); Library::import('recess.lang.Object'); Library::import('recess.lang.reflection.RecessReflectionClass'); Library::import('recess.lang.Annotation'); Library::import('recess.database.Databases'); Library::import('recess.database.sql.ISqlConditions'); Library::import('recess.database.orm.ModelClassInfo'); Library::import('recess.database.sql.SqlBuilder'); Library::import('recess.database.orm.annotations.HasManyAnnotation', true); Library::import('recess.database.orm.annotations.BelongsToAnnotation', true); Library::import('recess.database.orm.annotations.DatabaseAnnotation', true); Library::import('recess.database.orm.annotations.TableAnnotation', true); Library::import('recess.database.orm.annotations.ColumnAnnotation', true); Library::import('recess.database.orm.relationships.Relationship'); Library::import('recess.database.orm.relationships.HasManyRelationship'); Library::import('recess.database.orm.relationships.BelongsToRelationship'); /** * Model is the basic unit of organization in Recess' simple ORM. * * @author Kris Jordan <*****@*****.**> * @copyright 2008, 2009 Kris Jordan * @package Recess PHP Framework * @license MIT * @link http://www.recessframework.org/ */ abstract class Model extends Object implements ISqlConditions { const CLASSNAME = 'Model'; const INSERT = 'insert'; const UPDATE = 'update'; const DELETE = 'delete';
<?php Library::import('recess.framework.helpers.blocks.Block'); class HtmlClasses extends Block { protected $classes; function __construct() { $args = func_get_args(); $argCount = func_num_args(); if ($argCount == 1) { if (is_array($args[0])) { $this->classes = $args[0]; } else { if (is_string($args[0])) { $this->classes = array($args[0]); } } } else { if ($argCount > 1) { $this->classes = $args; } else { $this->classes = array(); } } } function add($class) { $this->classes[] = $class; $this->classes = array_unique($this->classes); return $this;
<?php Library::import('recess.http.Response'); Library::import('recess.http.ResponseCodes'); class NoContentResponse extends Response { public function __construct(Request $request) { parent::__construct($request, ResponseCodes::HTTP_NO_CONTENT, ResponseCodes::getMessageForCode(ResponseCodes::HTTP_NO_CONTENT)); } }
<?php Layout::extend('layouts/master'); $title = 'Home'; ?> <ul> <?php // This is a really slow way to generate navigation. // You probably should not use this in a real app. Thx -Kris Library::import('recess.lang.Inflector'); $app = $controller->application(); $controllers = $app->listControllers(); foreach ($controllers as $controllerClass) { $title = Inflector::toEnglish(str_replace('Controller', '', $controllerClass)); ?> <li><?php echo Html::anchor(Url::action($controllerClass . '::index'), $title); ?> </li> <?php } ?> </ul>