Please login or register.

Login with username, password and session length
Advanced search  
Pages: 1 [2] 3

Author Topic: Discussions on ideas for a core framework  (Read 4463 times)

sibas

  • Sr. Member
  • ****
  • Karma: 23
  • Posts: 451
    • www.simply4all.net
Re: Discussions on ideas for a core framework
« Reply #15 on: June 16, 2012, 01:32:11 PM »

Hey nukpana
I would like to give a try and see the general idea about this core but obviously like this is very difficult to try connect all pieces,
I think if you put it all in a folder to download, "ready to work" you get a better answers.
« Last Edit: June 16, 2012, 01:36:44 PM by sibas »
Logged

mosh

  • Hero Member
  • *****
  • Karma: 77
  • Posts: 510
  • Awesome day :)
    • cms-zen
Re: Discussions on ideas for a core framework
« Reply #16 on: June 16, 2012, 05:22:50 PM »

@nukpana
I will start by passing some karma to you for all your time and sharing.

I dont realy know oop, very complex to my brain, hehe :)

Hey nukpana
I would like to give a try and see the general idea about this core but obviously like this is very difficult to try connect all pieces,
I think if you put it all in a folder to download, "ready to work" you get a better answers.


This will help to try to understand, and to give some feedback about the project.

Thank you :)

nukpana

  • Hero Member
  • *****
  • Karma: 71
  • Posts: 663
Re: Discussions on ideas for a core framework
« Reply #17 on: June 17, 2012, 02:15:07 AM »

@sibas, @mosh, thank you both for your interest.

Quote
I would like to give a try and see the general idea about this core but obviously like this is very difficult to try connect all pieces,
I think if you put it all in a folder to download, "ready to work" you get a better answers.
Off the bat, I need to break down what each function/object/area does, how it works, etc. in the format of the OP. I will probably do that soon.

a) A Ready to Work download. 

It's not "ready to work", hence why there isn't a download. (It's not even done lol!!!) It's not the point of this thread to have a "ready to work" download, but to have a base to get the "ready to work" code up and running

I could post the file structure I have and you can do a copy/paste into the files noted. It will be almost identical to the code I have been posting here.

Please note, what you will be getting is very very basic functionality, but that is not really the point of the this thread as stated.

The templates (and the supporting functions) themselves, I believe are mostly the code you will be interested in… which leads me to…

b) OOP
The core code is OOP driven,  but in all honesty, if you are interested in the template or plugin writing, then very basic OOP is needed (extending a class for plugins), if at all. Take a look at the template-functions.php, template, or the custom template function thread to get an idea of how much OOP they would be using (almost none - one class).


The code:


mySQL.sql
Code: [Select]
-- mySQL

CREATE TABLE plugins (
name VARCHAR(255) NOT NULL,
UNIQUE (name)
) ENGINE = InnoDB;

CREATE TABLE settings (
name VARCHAR(255) NOT NULL,
value VARCHAR(255) NOT NULL,
INDEX (name),
UNIQUE (name)
) ENGINE = InnoDB;

-- Example
INSERT INTO settings VALUES('template', 'Default');

CREATE TABLE users (
id INT(8) NOT NULL AUTO_INCREMENT,
email VARCHAR(255) NOT NULL,
password VARCHAR(255) NOT NULL,

PRIMARY KEY (id),
UNIQUE (email)
) ENGINE = InnoDB;

-- Example using whirlpool hash - test@test.com/test
INSERT INTO users VALUES(1, 'aaf9398c4f59024dd27735901ef674b6a293704920a562c8f8f2e02aec837a7f3934fa473e29b9d742588a5710f6ac21da8113fc8a8970567c39f043d73744d3', 'b913d5bbb8e461c2c5961cbe0edcdadfd29f068225ceb37da6defcf89849368f8c6c2eb6a4c4ac75775d032a0ecfdfe8550573062b653fe92fc7b8fb3b7be8d6');

CREATE TABLE pages (
id INT(11) AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
uri VARCHAR(255) NOT NULL,
status INT(1) NOT NULL DEFAULT '1',
seq INT(5) NOT NULL DEFAULT '1',
text LONGTEXT NOT NULL,

PRIMARY KEY (id),
INDEX (
uri,
status,
seq
),
UNIQUE (uri)
) ENGINE = InnoDB;

INSERT INTO pages VALUES(1, 'Home', '', 1, 1, 'Welcome to the testCMS. Enjoy your unstable time here.');


config.ini
Notes - change the dbname to whatever you name the DB.  Also, there isn't an htaccess file so there is no point in changing the rewrite.url
Code: [Select]
; Configuration File

; Database

; DSN: mysql:host=localhost;dbname=dbName
database.dsn = "mysql:host=localhost;dbname=testCMS3"

; Database User
database.user = "root"

; Database Password
database.pass = "root"

; Paths
path.languages = ""
path.extensions = ""
path.templates = "tpl"

; Rewrite - change to TRUE if mod_rewrite is installed
; removes ?/ from internal urls ie:
; http://localhost/cms/?/admin/post/2/edit rewrite.url = FALSE
; http://localhost/cms/admin/post/2/edit rewrite.url = TRUE
rewrite.url = "FALSE";

index.php
Code: [Select]
<?php

error_reporting(-1);

session_start();

define('ADMIN', isset($_SESSION['Logged_In']));

#---------- Helper Functions ---------------------------------------------------

function get_ini$key$file 'config.ini' ) {
$array parse_ini_file($fileTRUE);
if( isset($array[$key]) ) return $array[$key];
}

function db() {
$db_conn FALSE;
try {
$db_conn = new PDO(
get_ini('database.dsn'),
get_ini('database.user'),
get_ini('database.pass')
);
} catch( PDOException $e ) {
die( $e->getMessage() );
}
return $db_conn;
}

// Modified version of http://php.net/manual/en/function.ksort.php#105399
function ksort_recursive(array &$array) {
ksort($array);
foreach( $array as &$a ) {
if( is_array($a) ) ksort_recursive($a);
}
}

// From http://us3.php.net/manual/en/function.stripslashes.php Example #2
function stripslashes_deep($value) {
return is_array($value)
array_map('stripslashes_deep'$value)
stripslashes($value);
}

// From http://www.php.net/manual/en/function.strip-tags.php#62705
function strip_tags_deep($value) {
return is_array($value
array_map('strip_tags_deep'$value
strip_tags($value);
}

// Based from https://wiki.php.net/rfc/functionarraydereferencing
function value($key$array) {
if( isset($array[$key]) ) return $array[$key];
}

// Remove index.php, and duplicate slashes from $_SERVER['REQUEST_URI']
// Based on http://brandonwamboldt.ca/my-php-router-class-825/
function _prepare_uri() {
$uri $_SERVER['REQUEST_URI'];
$uri str_replacedirname($_SERVER['PHP_SELF']), ''$uri );
$uri str_replace('index.php'''$uri);
$uri str_replace('?/'''$uri);
$uri preg_replace'/\/+/''/'$uri );
$uri ltrim$uri'/' );

return $uri;
}

function parse_uri($component null) {
$array = array();

$uri _prepare_uri();
$uri parse_url($uri);

if( isset($uri['path']) ) {
$uri['path'] = trim($uri['path'], '/');
$array['path'] = explode('/'$uri['path']);
}
if( isset($uri['query']) ) {
parse_str($uri['query'], $array['query']);
}

return isset($array[$component])
$array[$component]
$array;
}

function uri_part($num) {
return value($numparse_uri('path'));
}

function uri_qstr($key) {
return value($keyparse_uri('query'));
}

function build_url() {
$str  'http://' $_SERVER['HTTP_HOST'];
$str .= str_replace'index.php'''$_SERVER['SCRIPT_NAME'] );
$qs get_ini('rewrite.url') === TRUE
''
'?/';
$args func_get_args();

if( !empty($args) ) {
$args implode('/'$args);
return $str $qs $args;
} else {
return $str;
}
}

#---------- Router Class -------------------------------------------------------

// Modified from http://brandonwamboldt.ca/my-php-router-class-825/
final class Router {
private $_callback,
$_params = array(),
$_routes = array(),
$_uri;

function __construct$uri ) {
$this->_uri $uri;
}

    function route$route$callback ) {
$route ltrim$route'/' );

// Custom, format: <:var_name|regex>
$route preg_replace'/\<\:(.*?)\|(.*?)\>/''(?P<\1>\2)'$route );

// Alphanumeric, format: <:var_name>
$route preg_replace'/\<\:(.*?)\>/''(?P<\1>[A-Za-z0-9\-\_]+)'$route );

// Numeric, format: <#var_name>
$route preg_replace'/\<\#(.*?)\>/''(?P<\1>[0-9]+)'$route );

// Wildcard (INCLUDING dir separators), format: <*var_name>
$route preg_replace'/\<\*(.*?)\>/''(?P<\1>.+)'$route );

// Wildcard (EXCLUDING dir separators), format: <!var_name>
$route preg_replace'/\<\!(.*?)\>/', '(?P<\1>[^\/]+)'$route );

// Add regex for a full match or no match
$route '#^' $route '$#';

        // Add the route to our routing array
        $this->_routes[$route] = $callback;
}

    function execute() {
foreach ( $this->_routes as $route => $callback ) {
if ( preg_match$route$this->_uri$matches ) ) {
foreach ( $matches as $key => $match ) {
if ( is_string$key ) ) {
$this->_params[$key] = $match;
}
}
$this->_callback $callback;
}
}
    if ( $this->_callback === NULL) return;

    $fn $this->_callback;
    $fn$this->_params );
    }
}

function add_route($route$callback) {
$rtr = new Router(_prepare_uri());
$rtr->route($route$callback);
$rtr->execute();
}

#---------- Registry Class -----------------------------------------------------

final class Registry {
private static $_data = array();

static function get$key ) {
if( isset(self::$_data[$key]) ) {
return self::$_data[$key];
}
}

static function set$key$value '' ) {
self::$_data[$key] = $value;
}
}

#---------- Observable & Observer classes --------------------------------------

class Observable {
private $_event,
$_observers = array();

final function createEvent$event ) {
$this->_event = (string) $event;
$this->_notify();
}

final function getEvent() {
return $this->_event;
}

final function attachObserver $observer ) {
$i array_search($observer$this->_observers);
if ($i === false) {
$this->_observers[] = $observer;
}
}

final private function _notify() {
foreach($this->_observers as $observer) {
$observer->update$this );
}
}
}

interface Observer {
function updateObservable $subject );
}

#---------- AddOn Template -----------------------------------------------------

abstract class AddOn extends Observable {
protected $_active,
  $_list = array();

abstract function load();
abstract function get();
abstract function process($str);

abstract protected function set($addon);
}

function addon_init(AddOn $addon) {
$addon->load();
}

function addon_get(AddOn $addon) {
return $addon->get();
}

function addon_process(AddOn $addon$str) {
$addon->process($str);
}

#---------- Settings CRUD Class ------------------------------------------------

final class Settings {
private static $_data = array(),
   $_db;

static function init$db ) {
self::$_db $db;
$sql 'SELECT name, value FROM settings';
foreach ( self::$_db->query($sql) as $r ) {
self::$_data[$r['name']] = $r['value'];
}
}

static function get$key ) {
if( self::exists($key) ) {
return self::$_data[$key];
}
}

static function set$key$value ) {
if( self::exists($key) ) {
$sql "UPDATE settings 
SET value = :value 
WHERE name = :key"
;
} else {
$sql "INSERT INTO settings 
VALUES(:key, :value)
LIMIT 1"
;
}
$sth self::$_db->prepare($sql);
$sth->bindParam(':key'$keyPDO::PARAM_STR);
$sth->bindParam(':value'$valuePDO::PARAM_STR);
$sth->execute();
}

static function delete$key ) {
if( self::exists($key) ) {
$sth self::$_db->query("
DELETE 
FROM settings 
WHERE name = :key
"
);
$sth->bindParam(':key'$keyPDO::PARAM_STR);
$sth->execute();
}
}

static function exists$key ) {
return array_key_exists($keyself::$_data);
}
}
// initialize settings
Settings::init(db());

#---------- Language Helper ----------------------------------------------------

define'LANG_PATH'get_ini('path.languages') );

Registry::set('lang', array());

function lang() {
return Registry::get('lang');
}

final class Languages extends AddOn {

final function __construct() {
$this->_active Settings::get('language');
}

final function load() {
$array = array();
$file LANG_PATH .'/'$this->_active '.php';
if( file_exists($file) ) {
$array = require $file;
}
Registry::set('lang'$array);


final function get() {
$dir opendir(LANG_PATH);
if ($dir) {
while (false !== ($file readdir($dir))) {
if (
$file != '.' && 
$file != '..' && 
file_exists(LANG_PATH .'/'$file)
) {
$filename basename($file'.php');
$this->_list[$filename] = array();

if( $filename === $this->_active ) {
$this->_list[$filename]['active'] = TRUE;
}
}
}
}
return $this->_list;
}

final protected function set$addon ) {
Settings::set'language'$addon );
}

final function process$str ) {
$this->set$str );
}
}
// initialize languages
addon_init(new Languages);

// Function to translate strings 
// Uses http://php.net/manual/en/function.strtr.php
// Do not translate placeholder
function __$string, array $args NULL ) {
$string value($stringlang())
value($stringlang())
$string;

return $args === null
$string
strtr($string$args);
}

#---------- Plugin Helper ------------------------------------------------------

define'EXT_PATH'get_ini('path.extensions') );

Registry::set('ext'
array(
'ext' => array(),
'hook'=> array()
)
);

function ext() {
return Registry::get('ext');
}

final class Extension {
private static $_data = array();
private static $_db;

static function init$db ) {
self::$_db $db;
$sql 'SELECT name FROM plugins';
foreach ( self::$_db->query($sql) as $r ) {
self::$_data[] = $r['name'];
}
}

static function get() {
return self::$_data;
}

static function add$name ) {
if( !self::exists($name) ) {
$sth self::$_db->query("
INSERT INTO plugins 
VALUES(:name)
LIMIT 1
"
);
$sth->bindParam(':name'$namePDO::PARAM_STR);
$sth->execute();
}
}

static function delete$name  ) {
if( self::exists($name) ) {
$sth self::$_db->query("
DELETE 
FROM plugins
WHERE name = :name 
"
);
$sth->bindParam(':name'$namePDO::PARAM_STR);
$sth->execute();
}
}

static function exists$name ) {
return in_array($nameself::$_data); 
}
}

abstract class Ext implements Observer {
protected $_name;
protected $_data = array();
private $_hook = array();
private $_ext;

final function __construct() {
$this->_ext  ext();
$this->_name get_class($this);
$this->_data value(
$this->_name,
addon_get(new Extensions)
);
}

abstract function main();

final function add$hook$callback$priority 10 ) {
$this->_hook[$hook][$priority][] = $callback;
}

final private function _check_requirements() {
if( isset($this->_data['dependencies']['requires']) ) {
$requirement $this->_data['dependencies']['requires'];
foreach( $requirement as $dep ) {
if( !isset($this->_ext['ext'][$dep]) ) {
$this->_data['req_error'] = TRUE;
}
}
}
}

final function commit() {

$this->_check_requirements();
$this->main();

if(    !isset($this->_data['req_error']) 
|| $this->_data['req_error'] === FALSE 
) {

$this->_ext['ext'][$this->_name] = $this->_data;

if( isset($this->_data['hooks']) ) {
foreach( $this->_data['hooks'] as $hook => $calls ) {
if( is_array($calls) ) {
foreach( $calls as $k => $func ) {
$this->_ext['hook'][$hook][10][] = $func;
}
} else {
$this->_ext['hook'][$hook][10][] = $calls;
}
}
}

foreach ($this->_hook as $hook => $calls) {
foreach( $calls as $k => $call ) {
foreach( $call as $func ) {
$this->_ext['hook'][$hook][$k][] = $func;
}
}
}
ksort_recursive($this->_ext['hook']);
}
Registry::set('ext'$this->_ext);
}

final function updateObservable $subject ) {
switch( $subject->getEvent() ) {
case( 'activated_' $this->_name ):
if( method_exists($this'install') ) {
$this->install();
}
break;
case( 'deactivated_' $this->_name  ):
if( method_exists($this'uninstall') ) {
$this->uninstall();
}
break;
}
}
}

function ext_commit(Ext $ext) {
$ext->commit();

// Log this transaction
$e ext();
$e['ext'][get_class($ext)]['internal_commit'] = TRUE
Registry::set('ext'$e);
}

final class Extensions extends AddOn {

function __construct() {
$this->_active Extension::get();
}

final function load() {
foreach( $this->_active as $p ) {

$file EXT_PATH'/' .$p'/index.php';

if( file_exists$file ) ) {
require( $file );

if( class_exists($p) ) {

$i = new $p;
$i->commit();
// Attach the observer
$this->attach($i);
}
}
}


final function get() {
$dir opendir(EXT_PATH);
if( $dir ) {
while( false !== ($file readdir($dir)) ) {
if( 
   $file != '.' 
&& $file != '..' 
&& file_exists(EXT_PATH'/' .$file'/index.php')
&& file_exists(EXT_PATH'/' .$file'/plugin.ini')
) {

$this->_list[$file] = $this->data(
EXT_PATH'/' .$file'/plugin.ini'
);

if( in_array($file$this->_active) ) {
$this->_list[$file]['active'] = TRUE;
}
}
}
}
return $this->_list;
}

final protected function data$file ) {
$array = array();
$array['information'] = get_ini'plugin.information', $file );
$array['dependencies']= get_ini'plugin.dependencies', $file );
$array['hooks'   = get_ini'plugin.hooks' $file );
return strip_tags_deep($array);
}

final protected function set$addon ) {
Extension::set$addon );
$this->createEvent('activated_' $addon);
}

final protected function delete$addon ) {
Extension::delete$addon );
$this->createEvent('deactivated_' $addon);
}

final function process$str ) {
switch (true) {
case (strpos($str'activate') === ):
$this->set(substr($str'9'));
break;
case (strpos($str'deactivate') === ):
$this->delete(substr($str'11'));
break;
}
}
}

function exec_ext$hook$var NULL ) {
$ext ext();

if( isset($ext['hook'][$hook]) ) { 
foreach( $ext['hook'][$hook] as $k => $calls ) {
foreach( $calls as $func ) {
$var $func($var);
}
}
}
return $var;
}

#---------- Template Helper ----------------------------------------------------

define'TPL_PATH', get_ini('path.templates') );

final class Templates extends AddOn {
final function __construct() {
$this->_active Settings::get('template');
}

final function load() {
$file TPL_PATH .'/'$this->_active '/index.php';
if( file_exists($file) ) require($file);


final function get() {
$dir opendir(TPL_PATH);
if( $dir ) {
while( false !== ($file readdir($dir)) ) {
if( 
   $file != '.' 
&& $file != '..' 
&& file_exists(TPL_PATH'/' .$file'/index.php')
&& file_exists(TPL_PATH'/' .$file'/template.ini')
) {
$this->_list[$file] = $this->data(
TPL_PATH'/' .$file'/template.ini'
);
if( $file === $this->_active ) {
$this->_list[$file]['active'] = TRUE;
}
}
}
}
return $this->_list;
}

final protected function data$file ) {
$array = array();
$array['information'] = get_ini
'template.information',  
$file 
);
return strip_tags_deep($array);
}

final protected function set$addon ) {
Settings::set'template'$addon );
}

final function process$str ) {
if( strpos($str'activate') === ) {
$this->set(substr($str'9'));
}
}
}

#---------- Form Validator Class -----------------------------------------------

abstract class Validator {
protected $_errorMsg 'undefined';

    function getError() {
     return $this->_errorMsg;
    }

abstract function validate($value);
}

class Validate {
private $_data = array(),
$_errors = array();

function addValidator($fieldValidator $obj) {
$this->_data[$field][] = $obj;
return $this;
}

function isValid($array) {
$valid true;

foreach( $this->_data as $field => $objects ) {
foreach($objects as $i => $obj) {
if( !$obj->validate($array[$field]) ) {

$valid false;
$this->_errors[] = array(
'field' => $field,
'error' => $obj->getError()
);
break;
}
}
}
return $valid;
}

function getErrors() {
return $this->_errors;
}
}

function get_validation_error($field, array $array) {
$exists false;
foreach( $array as $k => $v ) {
if(  isset($array[$k]['field']) 
&&  $array[$k]['field'] === $field 
) {
$exists true;
}
}
if( $exists ) return $array[$k]['error'];
}

#---------- Admin Base Functions -----------------------------------------------

abstract class AdminModule extends Ext {
function register_admin_module() {
$this->_data['admin_module'][] = substr($this->_name5);
}
}

function registered_admin_modules() {
$modules = array();
foreach( value('ext'ext()) as $ext ) {
if( isset($ext['admin_module'][0]) ) {
$modules[] = strtolower(
$ext['admin_module'][0]
);
}
}
$modules array_flip($modules);
return $modules;
}

#---------- *&&*         *&&* --------------------------------------------------

Extension::init(db());
addon_init(new Extensions);

function center() {
echo exec_ext('center');
}

$baseController 'PageController';
switch( true ) {
case( uri_part(0) ):
$fn uri_part(0) . 'Controller';
if( function_exists($fn) ) {
$fn();
} else {
$baseController();
}
break;

default:
$baseController();
unset($baseController);
break;
}

function AdminController() {
require('admin/index.php');
}

function PageController() {
addon_init(new Templates);
}

template-functions.php
Code: [Select]
<?php

function 
parse404() {
$array get_page();
if( !$array ) {
header('HTTP/1.1 404 Not Found'); 
}
}
parse404();

function list_pages() {
$array = array();
$sql '
SELECT * 
FROM pages 
WHERE status = 1 
ORDER BY seq DESC
'
;
foreach( db()->query($sql) as $r ) {
$array[] = array(
'url' => build_url($r['uri']),
'title' => $r['name']
);
}
return $array;
}

function get_page() {
$array = array();
$uri uri_part(0);
$sql '
SELECT * 
FROM pages
WHERE uri = :uri
AND status = 1
'
;
$sth db()->prepare($sql);
$sth->bindParam(':uri'$uri);
$sth->execute();
while( $r $sth->fetch(PDO::FETCH_ASSOC) ) {
$r['edit_link'] = build_url('admin''page'$r['id']);
$array $r;
}
return $array;
}

switch( true ) {
case( uri_part(0) ):
class Page extends Ext {
function main() {
$this->add(
'center'
'view_'strtolower(get_class($this))
);
}
}
ext_commit(new Page);
break;
default:
class Home extends Ext {
function main() {
$this->add(
'center'
'view_'strtolower(get_class($this))
);
}
}
ext_commit(new Home);
break;
}
   
admin/index.php
Login (test@test.com/test) & Logout functions only
Code: [Select]
<?php

class 
Admin extends Ext {
function main() {
$this->add('center''AdminCenterController');
}
}
ext_commit(new Admin);

function AdminCenterController() {
$modules registered_admin_modules();
if( ADMIN ) {
if( isset($modules[uri_part(1)]) ) {
$fn 'Admin'ucfirst(uri_part(1)) .'Controller';
if( function_exists($fn) ) $fn();
}
} else {
AdminLoginController();
}
}

#-------------------------------------------------------------------------------
#---------- Login --------------------------------------------------------------
#-------------------------------------------------------------------------------

class AdminLogin extends AdminModule {
function main() {
$this->register_admin_module();
}
}
ext_commit(new AdminLogin);

function AdminLoginController() {
switch( true ) {
case( uri_part(2) ):
add_route('admin/login/process''process_login');
break;
default:
login();
break;
}
}

function login() {
if( !ADMIN ) {
?>

<h2><?php echo __('Login'); ?></h2>
<form method="post" action="<?php echo build_url('admin''login''process'); ?>">
<p>
<?php echo __('Email'); ?>:
<input type="text" name="email" />
</p>
<p>
<?php echo __('Password'); ?>:
<input type="password" name="password" />
</p>
<p>
<input type="submit" name="submit" value="<?php echo __('Login'); ?>">
</p>
</form>
<?php
}
}

function process_login() {
if( isset($_POST['submit']) ) {
$sth db()->query("SELECT * FROM users");
$sth->execute();
$r $sth->fetch(PDO::FETCH_ASSOC);
if(    hash('whirlpool'$_POST['email']) === $r['email'
&& hash('whirlpool'$_POST['password']) === $r['password']
) {
$_SESSION['Logged_In'] = "True";
echo '<meta http-equiv="refresh" content="0; url='.build_url().'">';
} else {
echo '<meta http-equiv="refresh" content="0; url='.build_url('admin''login').'">';
}
}
}

#-------------------------------------------------------------------------------
#---------- Logout -------------------------------------------------------------
#-------------------------------------------------------------------------------

class AdminLogout extends AdminModule {
function main() {
$this->register_admin_module();

$this->add('admin_menu''addLogoutToAdminMenu'999);
}
}

ext_commit(new AdminLogout);

function addLogoutToAdminMenu$array ) {
$array[] = array(
'url' => build_url('admin''logout'),
'title' => __('Logout')
);
return $array;
}

function AdminLogoutController() {
logout();
}

function logout() {
    session_destroy();
echo '<meta http-equiv="refresh" content="1; url='build_url() .'">';
}

#-------------------------------------------------------------------------------
#---------- Admin TPL Functions ------------------------------------------------
#-------------------------------------------------------------------------------

function AdminMenu() {
$array exec_ext('admin_menu', array());
return $array;
}

?>

<!DOCTYPE html>
<html>
<body>
<div id="header">Admin Template</div>
<div class="hmenu">
<?php
if( ADMIN ) {
echo '<ul>';
foreach( AdminMenu() as $k => $v ) {
if( isset($v['url']) && isset($v['title']) ) {
echo '<li><a href="'$v['url'] .'">'$v['title'] .'</a></li>';
}
}
echo '</ul>';
}
?>

</div>
<div id="center">
<?php center(); ?>
</div>
</body>
</html>


tpl/Default/template.ini
Needed to register the template
Code: [Select]
[template.information]
name = "Default Template"
description = "The default template"
author = "Me"
website = ""
version = ""
screenshot = ""

tpl/Default/index.php
Needed to register the template
Code: [Select]
<?php 

require(
'template-functions.php'); 

function view_home() {
$page get_page();
if( !$page ) return;
?>

<h2><?php echo $page['name']; ?></h2>
<p><?php echo $page['text']; ?></p>
<?php if( ADMIN ) { ?>
<p>
<a href="<?php echo $page['edit_link']; ?>">
<?php echo __('Edit'); ?>
</a>
</p>
<?php ?>
<?php
}

function view_page() {
$page get_page();
if( !$page ) return;
?>

<h2><?php echo $page['name']; ?></h2>
<p><?php echo $page['text']; ?></p>
<?php if( ADMIN ) { ?>
<p>
<a href="<?php echo $page['edit_link']; ?>">
<?php echo __('Edit'); ?>
</a>
</p>
<?php ?>
<?php
}

?>

<!DOCTYPE html>
<html>
<body>
<div id="main">
<?php center(); ?>
</div>

<div id="sidebar">
<ul id="page-menu">
<?php foreach( list_pages() as $p ) { ?>
<li>
<a href="<?php echo $p['url']; ?>">
<?php echo $p['title']; ?>
</a>
</li>
<?php ?>
</ul>
</div>
<div id="footer">
<p>
<?php 
echo ADMIN 
'<a href="'build_url('admin''logout') .'">'__('Logout') .'</a>'
'<a href="'build_url('admin''login') .'">'__('Login') .'</a>';
?>

</p>
</div>
</body>
</html>

Logged

nukpana

  • Hero Member
  • *****
  • Karma: 71
  • Posts: 663
Re: Discussions on ideas for a core framework
« Reply #18 on: June 18, 2012, 03:51:24 AM »

An update to the OP - http://snewscms.com/forum/index.php/topic,10292.msg68334.html#msg68334

I would like to revisit the outline I posted here, with the updated code - more in depth. I have also added some commentary after each block - about the problems,solutions, & other issues this code should solve/cause.
Quote
A small framework core with the basics:
 - database
 - settings (no view)
 - plugin API, plugins (no view)
 - template (no view)
 - form/validation class
 - controller function - to hook different url methods
 - center function - a central view function to hook to the main column

Again, this is still concept/alpha code - bugs, mistakes, things just not working period is expected.

1) Database Functions
The database function hasn't changed too much. The config information is in an config.ini file like so:
Code: [Select]
; Database

; DSN: mysql:host=localhost;dbname=dbName
database.dsn = "mysql:host=localhost;dbname=testCMS"

; Database User
database.user = "root"

; Database Password
database.pass = "root"

Then the core code looks like so:
Code: [Select]
<?php

function 
get_ini$key$file 'config.ini' ) {
$array parse_ini_file($fileTRUE);
if( isset($array[$key]) ) return $array[$key];
}

function db() {
$db_conn FALSE;
try {
$db_conn = new PDO(
get_ini('database.dsn'),
get_ini('database.user'),
get_ini('database.pass')
);
} catch( PDOException $e ) {
die( $e->getMessage() );
}
return $db_conn;
}

?>
Again, the db() function is textbook PDO construct - http://php.net/manual/en/pdo.construct.php

Quote
Q. What issue does this solve?
A. PHP noted they would begin depreciating the mysql driver soon.  In addition, PDO is multi database compatible, so moving to SQLite or PostgreSQL shouldn't have issue.

Q. What issues does this bring?
A. PDO is OOP, whereas the mysql driver was procedural.  I believe once the basics/limitations are known (no num_rows in PDO), this shouldn't be an issue anymore.

Q. Is there anything else needed?
A. None at the moment.


1a) Database iteself
So I went back on my database design and removed the 1/2 main table design for the content and removed the add on table:
Code: [Select]
CREATE TABLE plugins (
name VARCHAR(255) NOT NULL,
UNIQUE (name)
) ENGINE = InnoDB;

CREATE TABLE settings (
name VARCHAR(255) NOT NULL,
value VARCHAR(255) NOT NULL,
INDEX (name),
UNIQUE (name)
) ENGINE = InnoDB;

CREATE TABLE users (
id INT(8) NOT NULL AUTO_INCREMENT,
email VARCHAR(255) NOT NULL,
password VARCHAR(255) NOT NULL,

PRIMARY KEY (id),
UNIQUE (email)
) ENGINE = InnoDB;

CREATE TABLE pages (
id INT(11) AUTO_INCREMENT,
name VARCHAR(255) NOT NULL,
uri VARCHAR(255) NOT NULL,
status INT(1) NOT NULL DEFAULT '1',
seq INT(5) NOT NULL DEFAULT '1',
text LONGTEXT NOT NULL,

PRIMARY KEY (id),
INDEX (
uri,
status,
seq
),
UNIQUE (uri)
) ENGINE = InnoDB;

Quote
Q. What issue does this solve?
A. Each table is it's own entity.

Q. What issues does this bring?
A. User table uses the email as the login - this may not be wanted. This was put in place as it would be easier to remember an email than another username.

Q. Is there anything else needed?
A. Perhaps a date column in the Pages table. I left it out as I didn't see why it was needed.

2) Settings
Only change is using PDO, prepared statements in the queries:
Code: [Select]
<?php

final class 
Settings {
private static $_data = array(),
   $_db;

static function init$db ) {
self::$_db $db;
$sql 'SELECT name, value FROM settings';
foreach ( self::$_db->query($sql) as $r ) {
self::$_data[$r['name']] = $r['value'];
}
}

static function get$key ) {
if( self::exists($key) ) {
return self::$_data[$key];
}
}

static function set$key$value ) {
if( self::exists($key) ) {
$sql "UPDATE settings 
SET value = :value 
WHERE name = :key"
;
} else {
$sql "INSERT INTO settings 
VALUES(:key, :value)
LIMIT 1"
;
}
$sth self::$_db->prepare($sql);
$sth->bindParam(':key'$keyPDO::PARAM_STR);
$sth->bindParam(':value'$valuePDO::PARAM_STR);
$sth->execute();
}

static function delete$key ) {
if( self::exists($key) ) {
$sth self::$_db->query("
DELETE 
FROM settings 
WHERE name = :key
"
);
$sth->bindParam(':key'$keyPDO::PARAM_STR);
$sth->execute();
}
}

static function exists$key ) {
return array_key_exists($keyself::$_data);
}
}
// initialize settings
Settings::init(db());

?>
This class is a static class

Usage:
Code: [Select]
<?php

Settings
::set('website_title''My cool website!');
Settings::get('website_title');
Settings::delete('website_title');

/// put it in a wrapper function if you want:
function s($var) {
  return 
Settings::get($var); 
}
echo 
s('website_title');

?>


Quote
Q. What issue does this solve?
A. Each module handles it own processing and utilizing this base function, the module would not have to worry about handling this task.

Q. What issues does this bring?
A. Should have none. The static call is shown in the example above, so this shouldn't be foreign.

Q. Is there anything else needed?
A. None.

3a) Registry
The registry has not changed since the OP
Code: [Select]
<?php

final class 
Registry {
private static $_data = array();

static function get$key ) {
if( isset(self::$_data[$key]) ) {
return self::$_data[$key];
}
}

static function set$key$value '' ) {
self::$_data[$key] = $value;
}
}

?>
The Registry is a static class, where one can set & get data very similar to a key/value in an array
Code: [Select]
<?php

Registry::set('foo''bar');
Registry::get('foo'# bar

?>

Quote
Q. What issue does this solve?
A. It removes global variable usage.

Q. What issues does this bring?
A. Should have none.

Q. Is there anything else needed?
A. None.

3b) Observer/Observable
http://en.wikipedia.org/wiki/Observer_pattern
Code: [Select]
<?php

class 
Observable {
private $_event,
$_observers = array();

final function createEvent$event ) {
$this->_event = (string) $event;
$this->_notify();
}

final function getEvent() {
return $this->_event;
}

final function attachObserver $observer ) {
$i array_search($observer$this->_observers);
if ($i === false) {
$this->_observers[] = $observer;
}
}

final private function _notify() {
foreach($this->_observers as $observer) {
$observer->update$this );
}
}
}

interface Observer {
function updateObservable $subject );
}

?>

The observer/observable is used for the install/uninstall method for plugins, but can be used for any class that extends this or the AddOn class...

Please note, this uses type hinting in some of the methods

Quick example - What is happening here is that the main Plugin class Extension is being observed for the set/delete method, where a event is set.  The plugin API class Ext is listening for that event to be triggered so it can run the callback based on the event.
Code: [Select]
<?php

final class 
Extension extends Observable {
protected $_active;

function __construct() {
$this->_active = array(
'TestOne',
'TestTwo'
);
}

final function load() {
foreach( $this->_active as $p ) {
if( class_exists($p) ) {
$i = new $p;
$i->commit();
$this->attach($i);  #from Observable
}
}


final protected function set$addon ) {
echo '<br>setting ' $addon;
$this->createEvent('installed_' $addon); #from Observable
}

final protected function delete$addon ) {
echo '<br>deleting' $addon;
$this->createEvent('uninstalled_' $addon); #from Observable
}

final function process$str ) {
switch (true) {
case (strpos($str'activate') === ):
$this->set(substr($str'9'));
break;
case (strpos($str'deactivate') === ):
$this->delete(substr($str'11'));
break;
}
}
}

abstract class Ext implements Observer {
private $_name;

final function __construct() {
$this->_name get_class($this);
}

abstract function main();

final function commit() {
$this->main();
}

final function updateObservable $subject ) {
switch( $subject->getEvent() ) { #from Observable
case( 'installed_' $this->_name ):
if( method_exists($this'install') ) {
$this->install();
}
break;
case( 'uninstalled_' $this->_name  ):
if( method_exists($this'uninstall') ) {
$this->uninstall();
}
break;
}
}
}

class TestOne extends Ext {
function main() {}
function install() {
echo '<br>TestOne installing';
}
function uninstall() {
echo '<br>TestOne uninstalling';
}
}

class TestTwo extends Ext {
function main() {}
function install() {
echo '<br>TestTwo installing';
}
function uninstall() {
echo '<br>TestTwo uninstalling';
}
}

?>

Quote
Q. What issue does this solve?
A. Shown in the example above.

Q. What issues does this bring?
A. None at the moment, but may bring complexity to the child classes if overused/abused.

Q. Is there anything else needed?
A. This code may not be needed for this example.  It may be possible to just call a procedural function if exists removing this class.


3c) AddOn Class
The AddOn class went through quite a transformation since the OP:
Code: [Select]
<?php

class 
AddOns {
private static $_data = array();

static function init() {
$sql 'SELECT type, name FROM addons';
foreach ( db()->query($sql) as $r ) {
self::$_data[$r['type']][] = $r['name'];
}
}

static function get$type ) {
if( array_key_exists($typeself::$_data) ) {
return self::$_data[$type];
}
}

static function add$name$type ) {
if( !self::exists($name$type) ) {
db()->query("INSERT 
INTO addons 
VALUES('"
.$name."', '".$type."')
LIMIT 1"
);
}
}

static function delete$name$type ) {
if( self::exists($name$type) ) {
db()->query("DELETE 
FROM addons 
WHERE name = '"
.$name."' 
AND type = '"
.$type."'"
);
}
}

static function exists$name$type ) {
return array_search($nameself::get($type)) === FALSE
FALSE
TRUE
}


AddOns::init();

?>

First, the database table got dropped, so the entire class was repurposed to do the main work of the add-on such as get/set, load, process. 

The AddOn class also extends the Observable class above in the event an event is needed.

Another addition is the 3 procedural helpers for loading, getting, and processing the addon. Please note, this uses type hinting.
Code: [Select]
<?php 

abstract class 
AddOn extends Observable {
protected $_active,
  $_list = array();

abstract function load();
abstract function get();
abstract function process($str);

abstract protected function set($addon);
}

function addon_init(AddOn $addon) {
$addon->load();
}

function addon_get(AddOn $addon) {
return $addon->get();
}

function addon_process(AddOn $addon$str) {
$addon->process($str);
}

?>

Quote
Q. What issue does this solve?
A. Similar to Settings, this helps by defining tasks for the child classes that will assist later on in the application

Q. What issues does this bring?
A. Should have none - the procedural code helps interface the OOP code as long as the developer remembers to do "new ClassName" in the parameter.

Q. Is there anything else needed?
A. None.

3) Plugins
This function has become more defined since the posting here: http://snewscms.com/forum/index.php/topic,9975.0.html

Code: [Select]
<?php

define'EXT_PATH'get_ini('path.extensions') );

Registry::set('ext'
array(
'ext' => array(),
'hook'=> array()
)
);

function ext() {
return Registry::get('ext');
}

final class Extension {
private static $_data = array();
private static $_db;

static function init$db ) {
self::$_db $db;
$sql 'SELECT name FROM plugins';
foreach ( self::$_db->query($sql) as $r ) {
self::$_data[] = $r['name'];
}
}

static function get() {
return self::$_data;
}

static function add$name ) {
if( !self::exists($name) ) {
$sth self::$_db->query("
INSERT INTO plugins 
VALUES(:name)
LIMIT 1
"
);
$sth->bindParam(':name'$namePDO::PARAM_STR);
$sth->execute();
}
}

static function delete$name  ) {
if( self::exists($name) ) {
$sth self::$_db->query("
DELETE 
FROM plugins
WHERE name = :name 
"
);
$sth->bindParam(':name'$namePDO::PARAM_STR);
$sth->execute();
}
}

static function exists$name ) {
return in_array($nameself::$_data); 
}
}

abstract class Ext implements Observer {
protected $_name;
protected $_data = array();
private $_hook = array();
private $_ext;

final function __construct() {
$this->_ext  ext();
$this->_name get_class($this);
$this->_data value(
$this->_name,
addon_get(new Extensions)
);
}

abstract function main();

final function add$hook$callback$priority 10 ) {
$this->_hook[$hook][$priority][] = $callback;
}

final private function _check_requirements() {
if( isset($this->_data['dependencies']['requires']) ) {
$requirement $this->_data['dependencies']['requires'];
foreach( $requirement as $dep ) {
if( !isset($this->_ext['ext'][$dep]) ) {
$this->_data['req_error'] = TRUE;
}
}
}
}

final function commit() {

$this->_check_requirements();
$this->main();

if(    !isset($this->_data['req_error']) 
|| $this->_data['req_error'] === FALSE 
) {

$this->_ext['ext'][$this->_name] = $this->_data;

if( isset($this->_data['hooks']) ) {
foreach( $this->_data['hooks'] as $hook => $calls ) {
if( is_array($calls) ) {
foreach( $calls as $k => $func ) {
$this->_ext['hook'][$hook][10][] = $func;
}
} else {
$this->_ext['hook'][$hook][10][] = $calls;
}
}
}

foreach ($this->_hook as $hook => $calls) {
foreach( $calls as $k => $call ) {
foreach( $call as $func ) {
$this->_ext['hook'][$hook][$k][] = $func;
}
}
}
ksort_recursive($this->_ext['hook']);
}
Registry::set('ext'$this->_ext);
}

final function updateObservable $subject ) {
switch( $subject->getEvent() ) {
case( 'activated_' $this->_name ):
if( method_exists($this'install') ) {
$this->install();
}
break;
case( 'deactivated_' $this->_name  ):
if( method_exists($this'uninstall') ) {
$this->uninstall();
}
break;
}
}
}

function ext_commit(Ext $ext) {
$ext->commit();

// Log this transaction
$e ext();
$e['ext'][get_class($ext)]['internal_commit'] = TRUE
Registry::set('ext'$e);
}

final class Extensions extends AddOn {

function __construct() {
$this->_active Extension::get();
}

final function load() {
foreach( $this->_active as $p ) {

$file EXT_PATH'/' .$p'/index.php';

if( file_exists$file ) ) {
require( $file );

if( class_exists($p) ) {

$i = new $p;
$i->commit();
// Attach the observer
$this->attach($i);
}
}
}


final function get() {
$dir opendir(EXT_PATH);
if( $dir ) {
while( false !== ($file readdir($dir)) ) {
if( 
   $file != '.' 
&& $file != '..' 
&& file_exists(EXT_PATH'/' .$file'/index.php')
&& file_exists(EXT_PATH'/' .$file'/plugin.ini')
) {

$this->_list[$file] = $this->data(
EXT_PATH'/' .$file'/plugin.ini'
);

if( in_array($file$this->_active) ) {
$this->_list[$file]['active'] = TRUE;
}
}
}
}
return $this->_list;
}

final protected function data$file ) {
$array = array();
$array['information'] = get_ini'plugin.information', $file );
$array['dependencies']= get_ini'plugin.dependencies', $file );
$array['hooks'   = get_ini'plugin.hooks' $file );
return strip_tags_deep($array);
}

final protected function set$addon ) {
Extension::set$addon );
$this->createEvent('activated_' $addon);
}

final protected function delete$addon ) {
Extension::delete$addon );
$this->createEvent('deactivated_' $addon);
}

final function process$str ) {
switch (true) {
case (strpos($str'activate') === ):
$this->set(substr($str'9'));
break;
case (strpos($str'deactivate') === ):
$this->delete(substr($str'11'));
break;
}
}
}

function exec_ext$hook$var NULL ) {
$ext ext();

if( isset($ext['hook'][$hook]) ) { 
foreach( $ext['hook'][$hook] as $k => $calls ) {
foreach( $calls as $func ) {
$var $func($var);
}
}
}
return $var;
}

?>


Let me get into writing plugins
What is needed is an index.php & a plugin.ini file in a folder with the plugin name to start.

plugin.ini example:
Code: [Select]
; Sample plugin.ini

[plugin.information]
name = ""
description = ""
author = ""
website = ""
version = ""

[plugin.dependencies]
requires[] = ""

[plugin.hooks]
hook = "callback"

Here we are defining basic information about the plugin - data about the plugin/author, if it requires an installed plugin, then the hook/callback

index.php example:
Code: [Select]
<?php

class Test extends Ext {
function main() {}
}

function 
callback() {
echo 'Hello World!';
}

?>
Pretty simple. The class Test, being in folder Test, extends the Ext class and calls an empty main() method.  We need to do this to register the plugin and run it.  If you needed to add hook/callback with a priority, this would be done in the main() method. Also, if a install/uninstall needs to be done, it is done in the class - see the Observer/Observable example.

Afterwards you do your callback and add any other code that is needed for that callback.

You can have the plugin run automatically using the ext_commit function.  This function was created for internal plugins that needed to be part of the ext() array, but it can be used for non-internal usage as well.  Proper external usage for example would be for the template to install/uninstall sql if it has a need - since we have activated the template, no need to activate it again in the plugin routine.  There is an internal logger that notes whenever the ext_commit has been used - you can do a simple print_r(ext()) and see what plugins are registering themselves to run:

Code: [Select]
[Logout] => Array
(
[admin_module] => Array
(
[0] => Logout
)
[internal_commit] => 1
)
 

Quote
Q. What issue does this solve?
A. Simply, a plugin API internally & externally.

Q. What issues does this bring?
A. The extending an empty class, when creating the plugin may be a code smell. The ext_commit function may be vulnerability if used incorrectly. The install/uninstall issue is noted in the Observer/Observable - may be a quicker and smaller fix.

Q. Is there anything else needed?
A. Removal from db if active plugin doesn't exist in the file system.
« Last Edit: June 18, 2012, 03:56:55 AM by nukpana »
Logged

nukpana

  • Hero Member
  • *****
  • Karma: 71
  • Posts: 663
Re: Discussions on ideas for a core framework
« Reply #19 on: June 18, 2012, 03:53:28 AM »

4) Template
I never got into the templates portion of the code, just that is wouldn't be too far off from this code here.
To be honest alot of the code here isn't really that new.  It has been in the works for years, just I haven't fully picked them up to finish the idea....

In any case, the template code:
Code: [Select]
<?php

define'TPL_PATH', get_ini('path.templates') );

final class Templates extends AddOn {
final function __construct() {
$this->_active Settings::get('template');
}

final function load() {
$file TPL_PATH .'/'$this->_active '/index.php';
if( file_exists($file) ) require($file);


final function get() {
$dir opendir(TPL_PATH);
if( $dir ) {
while( false !== ($file readdir($dir)) ) {
if( 
   $file != '.' 
&& $file != '..' 
&& file_exists(TPL_PATH'/' .$file'/index.php')
&& file_exists(TPL_PATH'/' .$file'/template.ini')
) {
$this->_list[$file] = $this->data(
TPL_PATH'/' .$file'/template.ini'
);
if( $file === $this->_active ) {
$this->_list[$file]['active'] = TRUE;
}
}
}
}
return $this->_list;
}

final protected function data$file ) {
$array = array();
$array['information'] = get_ini
'template.information',  
$file 
);
return strip_tags_deep($array);
}

final protected function set$addon ) {
Settings::set'template'$addon );
}

final function process$str ) {
if( strpos($str'activate') === ) {
$this->set(substr($str'9'));
}
}
}

?>

The template location is defined in the config.ini file.  Then the base Template helper extends the AddOn function, which also can utilize the AddOn procedural functions.

For template authors, you need to have an index.php & template.ini file to get the template seen in the admin chooser.

A template.ini example looks like this:
Code: [Select]
[template.information]
name = "Default Template"
description = "The default template"
author = "Me"
website = ""
version = ""
screenshot = ""

The admin chooser can use this functions to help get/parse the template data for example:
Code: [Select]
<?php

function 
template() {
?>

<h2><?php echo __('Template'); ?></h2>
<ul>
<?php
$activate '';
$link '';
foreach( addon_get(new Templates) as $k => $v) {
if( !isset($v['active']) ) { 
$activate 'activate_';
$link build_url('admin''template''process'$activate $k);
echo '<li><a href="'$link .'">'$k .'</a>';
} else {
echo '<li>'$k;

?>

<ul>
<?php 
$info $v['information'];

echo isset($info['author']) 
'<li>'__('Made by') .': '$info['author'] .'</li>'
'';

echo isset($info['description']) 
'<li>'__('Description') .': '$info['description'] .'</li>'
'';
?>

</ul>
</li>
<?php
}
?>

</ul>
<?php
}

function process_template$var ) {
addon_process(new Templates$var['id']);
echo '<meta http-equiv="refresh" content="0; url='build_url('admin''template') .'">';
}

?>

If the template requires a plugin functionality, then it should use the normal plugin routine, then use the ext_commit to call the plugin functionality. A user case would be if the template had a database install/uninstall routine.

Quote
Q. What issue does this solve?
A. Simply, multiple templates.

Q. What issues does this bring?
A. The template will also serve as it's own controller. So the template can be very simple or very complex if desired.

Q. Is there anything else needed?
A. None.

5) Form/Validation
I posted some crappy code that wasn't fully worked on or tested:
Quote
Code: [Select]
<?php

class 
Validation {
private $_form,
$_fields = array(),
$_errors = array();

function __construct$form_name ) {
$this->_form $form_name;
}

function add_validation$field$callback ) {
$this->_fields[] = array(
'field' => $field
'callback' => $callback
);
}

function validate$array ) {
exec_ext$this->_form '_validation_array'$this );

foreach( $this->_fields as $v ) {

if( is_callable($v['callback']) ) {
$fields $v['callback']( $array[$v['field']] );

if( isset($fields['validation']) &&
$fields['validation'] === FALSE
) {
$this->_errors[$v['field']][] = $fields['view'];

}
}
}

function has_errors() {
if( count($this->_errors) > ) {
return TRUE;
}
}

function get_errors() {
return $this->_errors;
}
}

?>

But the code I have now, isn't that too far off:
Code: [Select]
<?php

abstract class 
Validator {
protected $_errorMsg 'undefined';

    function getError() {
     return $this->_errorMsg;
    }

abstract function validate($value);
}

class Validate {
private $_data = array(),
$_errors = array();

function addValidator($fieldValidator $obj) {
$this->_data[$field][] = $obj;
return $this;
}

function isValid($array) {
$valid true;

foreach( $this->_data as $field => $objects ) {
foreach($objects as $i => $obj) {
if( !$obj->validate($array[$field]) ) {

$valid false;
$this->_errors[] = array(
'field' => $field,
'error' => $obj->getError()
);
break;
}
}
}
return $valid;
}

function getErrors() {
return $this->_errors;
}
}

?>
Right away, I am using the Strategy Pattern, influenced by Zend Validate I love the Zend functionality, but it was just too big to use as a library (and at times confusing).

Here we can make validators by extending the abstract Validator class
Code: [Select]
<?php

class 
IsBlank extends Validator {
function __construct() {
$this->_errorMsg __('Sorry, you left this blank');
}

function validate($value) {
return !empty($value) ? true false;
}
}

class IsEmail extends Validator {
function __construct() {
$this->_errorMsg __('Sorry, the email is invalid');
}

function validate($value) {
return filter_var($valueFILTER_VALIDATE_EMAIL);
}
}

?>

Then calling it in the form validation, even using chaining to apply multiple validators:

Code: [Select]
<?php

if( isset($_POST['submit']) ) {
$validation = new Validate;
$validation->addValidator('name', new IsBlank);

$validation->addValidator('email',new IsBlank)
   ->addValidator('email',new IsEmail);

if( !$validation->isValid($_POST) ) {
print_r($validation->getErrors());
} else {
echo 'Ok to go!';
}
}

?>

Quote
Q. What issue does this solve?
A. It allows validation to be shared when processing forms.

Q. What issues does this bring?
A. Validators are needed to be written, using classes - but as shown in the example, it is not difficult.  The form validation utilizes OOP, so it may be difficult at first, but as seen in the examples, can be simple to use.  The output is not complete - as described below.

Q. Is there anything else needed?
A. What I would like to point out is I am not going into how the user will see the error.  I am leaving that up to the template authors to decide, but I feel that using json to encode and  pass the errors via Javascript, leaving the core admin code, relatively untouched....

6a) Url helpers
Should be self explanatory.
Code: [Select]
<?php
// Remove index.php, and duplicate slashes from $_SERVER['REQUEST_URI']
// Based on http://brandonwamboldt.ca/my-php-router-class-825/
function _prepare_uri() {
$uri $_SERVER['REQUEST_URI'];
$uri str_replacedirname($_SERVER['PHP_SELF']), ''$uri );
$uri str_replace('index.php'''$uri);
$uri str_replace('?/'''$uri);
$uri preg_replace'/\/+/''/'$uri );
$uri ltrim$uri'/' );

return $uri;
}

function parse_uri($component null) {
$array = array();

$uri _prepare_uri();
$uri parse_url($uri);

if( isset($uri['path']) ) {
$uri['path'] = trim($uri['path'], '/');
$array['path'] = explode('/'$uri['path']);
}
if( isset($uri['query']) ) {
parse_str($uri['query'], $array['query']);
}

return isset($array[$component])
$array[$component]
$array;
}

function uri_part($num) {
return value($numparse_uri('path'));
}

function uri_qstr($key) {
return value($keyparse_uri('query'));
}

function build_url() {
$str  'http://' $_SERVER['HTTP_HOST'];
$str .= str_replace'index.php'''$_SERVER['SCRIPT_NAME'] );
$qs get_ini('rewrite.url') === TRUE
''
'?/';
$args func_get_args();

if( !empty($args) ) {
$args implode('/'$args);
return $str $qs $args;
} else {
return $str;
}
}
?>

Quote
Q. What issue does this solve?
A. It helps with url parsing and building.

Q. What issues does this bring?
A. build_url only works with pretty urls either with or w/o rewrite - Query Strings are supported somewhat. Removing the Query String code is 5 lines gone...  The idea is to follow the REST formats for urls, classic blog format for blogs

Q. Is there anything else needed?
A. Depends if query strings are needed.

6b) The Router
With permission to use with credit, Brandon Wamboldt allowed me to use his Router class. I removed alot of the code to get a leaner class and I added a procedural function to help with adding routes.  See his site for usage cases.
Code: [Select]
<?php

// Modified from http://brandonwamboldt.ca/my-php-router-class-825/
final class Router {
private $_callback,
$_params = array(),
$_routes = array(),
$_uri;

function __construct$uri ) {
$this->_uri $uri;
}

    function route$route$callback ) {
$route ltrim$route'/' );

// Custom, format: <:var_name|regex>
$route preg_replace'/\<\:(.*?)\|(.*?)\>/''(?P<\1>\2)'$route );

// Alphanumeric, format: <:var_name>
$route preg_replace'/\<\:(.*?)\>/''(?P<\1>[A-Za-z0-9\-\_]+)'$route );

// Numeric, format: <#var_name>
$route preg_replace'/\<\#(.*?)\>/''(?P<\1>[0-9]+)'$route );

// Wildcard (INCLUDING dir separators), format: <*var_name>
$route preg_replace'/\<\*(.*?)\>/''(?P<\1>.+)'$route );

// Wildcard (EXCLUDING dir separators), format: <!var_name>
$route preg_replace'/\<\!(.*?)\>/', '(?P<\1>[^\/]+)'$route );

// Add regex for a full match or no match
$route '#^' $route '$#';

        // Add the route to our routing array
        $this->_routes[$route] = $callback;
}

    function execute() {
foreach ( $this->_routes as $route => $callback ) {
if ( preg_match$route$this->_uri$matches ) ) {
foreach ( $matches as $key => $match ) {
if ( is_string$key ) ) {
$this->_params[$key] = $match;
}
}
$this->_callback $callback;
}
}
    if ( $this->_callback === NULL) return;

    $fn $this->_callback;
    $fn$this->_params );
    }
}

function add_route($route$callback) {
$rtr = new Router(_prepare_uri());
$rtr->route($route$callback);
$rtr->execute();
}

?>

Very basic usage:
Code: [Select]
<?php 

add_route
('admin/login/process''process_login');

# #id is numeric, :action is alpha numeric
add_route('/admin/page/<#id>/<:action>''process_page');

?>

Quote
Q. What issue does this solve?
A. It allows the developer to allow a function to be called when a url is matched.

Q. What issues does this bring?
A. Needing to memorize/refer back to the doc/code what each placeholder does. The priority was taken out - not fully sure if needed.

Q. Is there anything else needed?
A. See the previous question

6) The controller function
Initially I stated:

Quote
This would be the code that would parse any URL and pass the results to the template.  This would be similar to the MainQuery & Globals section of sNews 1.7 - with the exception that this would be driven by plugins ie the whole function could look like:

Code: [Select]
fn controller() {
   return array(exec_ext('controller'));
}

// Usage could be:
$values = controller();
loadTemplate($values);

So doing this wouldn't lock a user into one style of URL, but the values passed would have to be the same for use in the template.

As of today the controller is sort of similar...
Code: [Select]
<?php

switch( 
true ) {
case( uri_part(0) ):
$fn uri_part(0) . 'Controller';
if( function_exists($fn) ) {
$fn();
} else {
PageController();
}
break;

default:
PageController();
break;
}

function AdminController() {
require('admin/index.php');
}

function PageController() {
addon_init(new Templates);
}

?>

What is happening is that we are relying on the first parameter of the url to call the appropriate controller, else call the default controller - PageController.  Like so:

domain.com/?/admin - AdminController
domain.com/?/blog  - BlogController
domain.com/?/forum - ForumController
domain.com/?/store - StoreController
domain.com/?/about - PageController

It doesn't end there either and becomes an hierarchal MVC pattern, where we are sending the script from one controller to another ie:

AdminController -> AdminCenterController -> AdminPageController -> output in the AdminCenter

Here the AdminController calls on the admin template, which also delegates based on the url.  But here, the delegation goes to a further controller. 

This is good because we can keep the code separated for plugins - Each section becomes its own self contained module if you will.
Code: [Select]
<?php

function 
AdminCenterController() {
$modules registered_admin_modules();
if( ADMIN ) {
if( isset($modules[uri_part(1)]) ) {
$fn 'Admin'ucfirst(uri_part(1)) .'Controller';
if( function_exists($fn) ) $fn();
// else 404?
} else {
AdminLoginController();
}
}

# --------------------------------------------------------------- #

function AdminPageController() {
switch( true ) {
# /admin/page/1/edit
case( uri_part(3) ):
add_route(
'/admin/page/<#id>/<:action>',
'process_page'
);
break;

# /admin/page/1
case( uri_part(2) ):
switch( true ) {
case( is_numeric(uri_part(2)) ):
add_route(
'/admin/page/<#id>',
'edit_page'
);
break;
case( uri_part(2) == 'process' ):
add_route(
'/admin/page/process',
'process_page'
);
break;
default:
add_route(
'/admin/page/<:id>',
'get_pages'
);
break;
}
break;

# /admin/page
case( uri_part(1) ):
add_route('/admin/page''new_page');
break;
}
}

?>

Quote
Q. What issue does this solve?
A. It keeps the code modular and directs where the code needs to go.

Q. What issues does this bring?
A. Complexity of the switch statement if the module is big ala a blog module

Q. Is there anything else needed?
A. None at the moment.

7) The center function
I initially stated here:
Quote
Could probably be as simple as the above controller code. Being the only core code, that I think would be needed in the template.   This would be the main content view for private and public viewings so all code could hook up there.

The above controller code looked like this:
Code: [Select]
fn controller() {
   return array(exec_ext('controller'));
}

Which is almost exactly what the center function looks like in the updated code:
Code: [Select]
<?php

function center() {
echo exec_ext('center');
}

?>

The examples here show the Admin & Pages hooking into the center:

Code: (Admin) [Select]
<?php

class Admin extends Ext {
function main() {
$this->add('center''AdminCenterController');
}
}

?>

Code: (Pages) [Select]
<?php

class Page extends Ext {
function main() {
$this->add('center''view_page');
}
}

?>

Quote
Q. What issue does this solve?
A. Reducing the center file to a hook where plugins can register themselves to.

Q. What issues does this bring?
A. None at the moment.

Q. Is there anything else needed?
A. No.

** Additions **

8) Languages
Code: [Select]
<?php

define'LANG_PATH'get_ini('path.languages') );

Registry::set('lang', array());

function lang() {
return Registry::get('lang');
}

final class Languages extends AddOn {

final function __construct() {
$this->_active Settings::get('language');
}

final function load() {
$array = array();
$file LANG_PATH .'/'$this->_active '.php';
if( file_exists($file) ) {
$array = require $file;
}
Registry::set('lang'$array);


final function get() {
$dir opendir(LANG_PATH);
if ($dir) {
while (false !== ($file readdir($dir))) {
if (
$file != '.' && 
$file != '..' && 
file_exists(LANG_PATH .'/'$file)
) {
$filename basename($file'.php');
$this->_list[$filename] = array();

if( $filename === $this->_active ) {
$this->_list[$filename]['active'] = TRUE;
}
}
}
}
return $this->_list;
}

final protected function set$addon ) {
Settings::set'language'$addon );
}

final function process$str ) {
$this->set$str );
}
}
// initialize languages
addon_init(new Languages);

// Function to translate strings 
// Uses http://php.net/manual/en/function.strtr.php
// Do not translate placeholder
function __$string, array $args NULL ) {
$string value($stringlang())
value($stringlang())
$string;

return $args === null
$string
strtr($string$args);
}

?>
How to use?  The main class is used like other classes that extends the AddOn class, but the procedural function is the key here:

Code: [Select]
<?php

#example Basic:
echo __('Hello World'); # Hello World

#example Placeholder:
echo __('Hello @user', array('@user' => 'you')); # Hello you

#example Do not translate placeholder - Spanish translation example
return array('Hello @user' => 'Hola @user'); 

?>

Quote
Q. What issue does this solve?
A. Easier to understand strings. Ability to use placeholders in string.

Q. What issues does this bring?
A. None so far.

Q. Is there anything else needed?
A. None.
« Last Edit: June 18, 2012, 04:02:14 AM by nukpana »
Logged

nukpana

  • Hero Member
  • *****
  • Karma: 71
  • Posts: 663
Re: Discussions on ideas for a core framework
« Reply #20 on: August 12, 2012, 11:05:25 PM »

Just a quick update -
 - For the plugins, I noted it may be bad to have the empty main() call, so to do without we can check if it exists in the commit method as such:

Code: [Select]
<?php 

# Ext class....

final function commit() {
$this->_check_requirements();

if( method_exists($this'main') ) {
$this->main();
}

....

So now, a basic plugin would need:
Code: [Select]
<?php

class TestPlugin extends Ext {}

# Whatever code that makes the plugin run


 - Just a showing of the Validator code in action, very loosely based on the code here: http://snewscms.com/forum/index.php/topic,8818.0.html
Code: [Select]
<?php

error_reporting(-1);

function __$string, array $args NULL ) {
return $args === null
$string
strtr($string$args);
}

abstract class Validator {
protected $_errorMsg 'undefined';

    function getError() {
     return $this->_errorMsg;
    }

abstract function validate($value);
}

class Validate {
private $_data = array(),
$_errors = array();

function addValidator($fieldValidator $obj) {
$this->_data[$field][] = $obj;
return $this;
}

function isValid($array) {
$valid true;

foreach( $this->_data as $field => $objects ) {
foreach($objects as $i => $obj) {
if( isset($array[$field]) ) {
if( !$obj->validate($array[$field]) ) {
$valid false;
$this->_errors[] = array(
'field' => $field,
'error' => $obj->getError()
);
break;
}
}
}
}
return $valid;
}

function getErrors() {
return $this->_errors;
}
}

function get_validation_error($field, array $array) {
$exists false;
foreach( $array as $k => $v ) {
if(  isset($array[$k]['field']) 
&&  $array[$k]['field'] === $field 
) {
$exists true;
}
}
if( $exists ) return $array[$k]['error'];
}


class IsBlank extends Validator {
function __construct() {
$this->_errorMsg __('Sorry, you left this blank');
}

function validate($value) {
return !empty($value) ? true false;
}
}

class IsEmail extends Validator {
function __construct() {
$this->_errorMsg __('Sorry, the email is invalid');
}

function validate($value) {
return filter_var($valueFILTER_VALIDATE_EMAIL);
}
}


function checkform() {
if(
!empty($_SERVER['HTTP_X_REQUESTED_WITH']) 
&& strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest'
) {
$validation = new Validate;

$validation->addValidator('email', new IsBlank)
->addValidator('email', new IsEmail);

$validation->addValidator('password', new IsBlank);

if( !$validation->isValid($_POST) ) {
echo json_encode($validation->getErrors());
} else {
echo 'Ok, we are getting somewhere...';
}
die();
}
}
checkform();

?>

<!DOCTYPE html>
<html>
<head>
<style>
.error { color: red; }
</style>
</head>
<body>
<h2><?php echo __('Login'); ?></h2>
<form id="login-form" method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">
<p>
<?php echo __('Email'); ?>:
<input type="text" name="email" />
</p>
<p>
<?php echo __('Password'); ?>:
<input type="password" name="password" />
</p>
<p>
<input type="submit" name="submit-login" value="<?php echo __('Login'); ?>">
</p>
</form>
<script src="jquery.min.js"></script>
<script>
$('#login-form').submit(function() {
$.post(
"test.php",
$(this).serialize(),
function(data) {
$('.error').remove();
data = jQuery.parseJSON(data);
$.each(data, function(i) {
$('input[name="' + data[i].field +'"]').parent().append('<span class="error">' + data[i].error + '</span>');
});
}
);
return false;
});
</script>
</body>
</html>
Blank Fields:

Incorrect Email:
Logged

Fred K

  • Still trying to learn stuff
  • ULTIMATE member
  • ******
  • Karma: 130
  • Posts: 2728
    • Personal
Re: Discussions on ideas for a core framework
« Reply #21 on: August 16, 2012, 07:01:43 PM »

Jason - I would love to dive in to this ... but.
Here's my problem:

Quote from: post 17 up above
b) OOP
The core code is OOP driven

When we've been discussing sNews development beyond 1.7, the overwhelming view has been "no OOP". Mostly because of the target audience for sNews, but also for me personally. (PHP dunce and all that ;))  I mean, I'm only just now getting to grips with most of the functions in sNews, which seem pretty uncomplicated when comparing to OOP code. If(youknow(whattahmean));

What if we do without the OOP?
Logged

Keyrocks

  • Doug
  • ULTIMATE member
  • ******
  • Karma: 449
  • Posts: 6019
  • Semantically Challenged
    • snews.ca
Re: Discussions on ideas for a core framework
« Reply #22 on: August 16, 2012, 09:50:10 PM »

Jason - I would love to dive in to this ... but. Here's my problem:
When we've been discussing sNews development beyond 1.7, the overwhelming view has been "no OOP". Mostly because of the target audience for sNews, but also for me personally. (PHP dunce and all that ;))  I mean, I'm only just now getting to grips with most of the functions in sNews, which seem pretty uncomplicated when comparing to OOP code. If(youknow(whattahmean));
What if we do without the OOP?

OOPs... good point Fred. previous discussion on OOP.

I can see why Jason is working with OOP because he knows how to work with it (far more than the rest of us) and it makes sense to start with OOP when starting a new CMS from scratch. I know most of us know mothing about OOP but I am not adverse to learning more about it and putting it to use (If I can wrap my head around it).

Larry Ullman has a new book coming out soon (expected in September) titled "PHP Advanced and Object-Oriented Programming: Visual QuickPro Guide". I'm looking forward to picking up a copy (before winter sets in) because I have found his previous books easy to understand and learn from.

I still think our main objective is to create a 2.0 version that basic PHP beginners can learn from and continue to build upon at their own speed without having to take a course before getting started. Of course, we would also need to consider putting a comprehensive Documentation section together on snewscms.com. Documentation is the key to making the package useful to beginners and seasoned developers alike.
Logged
Do it now... later may not come.
-------------------------------------------------------------------------------------------------
sNews 1.6 MESU | sNews 1.6 MEMU

nukpana

  • Hero Member
  • *****
  • Karma: 71
  • Posts: 663
Re: Discussions on ideas for a core framework
« Reply #23 on: August 17, 2012, 01:15:34 AM »

Gotta make this quick....

Jason - I would love to dive in to this ... but.
Here's my problem:
Quote from: post 17 up above
The core code is OOP driven

When we've been discussing sNews development beyond 1.7, the overwhelming view has been "no OOP". Mostly because of the target audience for sNews, but also for me personally.

@Fred.  You missed the rest of the quote, which was directed towards the "sNews audience" - mostly front end developers (HTML/CSS & some JS - Basic PHP).
Quote
...but in all honesty, if you are interested in the template or plugin writing, then very basic OOP is needed, if at all.

Again, this is a core framework to help build a "sNews 2.0" system - code that shouldn't be modified at all.

OOPs... good point Fred. previous discussion on OOP.
Actually that decision is older than that - From the main script author, Luka:

January 2009http://snewscms.com/forum/index.php/topic,7748.msg57928.html#msg57928
Quote
OOP
I don't think making sNews OO will improve performance, but it would lead to a well structured code. If there's a great number of people that code out of a hobby - there's a great chance they'll be having difficulties modifying sNews.

My response, a few days after that response... http://snewscms.com/forum/index.php/topic,7748.msg58077.html#msg58077
Quote
I vote no as well, reasoning being that this community and it's team members aren't OOP fluent (if they are, then they aren't too public about it other than Baker), so OOP may be confusing. BUT if the application calls for a OOP solution and it is simple enough to follow, then I would support such a solution (not the whole script).
I highlighted a few things that I would like to touch on later...

Quote
(The) main objective is to create a 2.0 version that basic PHP beginners can learn from and continue to build upon at their own speed..
I agree, but that doesn't mean the core functionality needs to be coded a certain way - nor does it mean newbies should be altering core application code.

Quote
Documentation is the key to making the package useful to beginners and seasoned developers alike.
Yup. Provide an simple API, with good documentation into the system and "developers" can build using that. It is not any different from what is currently out in the software world today - It is more focused today that it was when this discussion first started 4 years ago.
Logged

Fred K

  • Still trying to learn stuff
  • ULTIMATE member
  • ******
  • Karma: 130
  • Posts: 2728
    • Personal
Re: Discussions on ideas for a core framework
« Reply #24 on: August 17, 2012, 04:17:54 AM »

Quote from: nukpana
@Fred.  You missed the rest of the quote, which was directed towards the "sNews audience" - mostly front end developers (HTML/CSS & some JS - Basic PHP).
Quote
...but in all honesty, if you are interested in the template or plugin writing, then very basic OOP is needed, if at all.

Again, this is a core framework to help build a "sNews 2.0" system - code that shouldn't be modified at all.

I didn't miss it, I just elected to neglect it. Then I started my twentysecond stab at studying the basics of OOP and, sure, I can see that basic OOP can be used in the system alongside the more normal procedural code. My problem—why I elected to neglect the end part of the quote—is that OOP is abstract even in its most basic form and for someone like me, whose mind runs screaming for the hills as soon as sh** goes abstract, even basic OOP is ... well, I gloss over it quite honestly. It doesn't register.

Then again, a) I may not be the yardstick for the average sNews user; and b) if the core indeed is built so that it doesn't need changing (and, yes, I know this is the clear aim), then my bickerings might not be relevant at all.

My question remains though: what if we do without OOP? Is that less good? (The question is honest and direct, no hidden agenda, I wanna learn.)
Logged

nukpana

  • Hero Member
  • *****
  • Karma: 71
  • Posts: 663
Re: Discussions on ideas for a core framework
« Reply #25 on: August 17, 2012, 11:59:51 AM »

Quote
My question remains though: what if we do without OOP? Is that less good? (The question is honest and direct, no hidden agenda, I wanna learn.)

Just to point out - What I still advocate is a procedural environment, with OOP to define major elements. With that being said...

What if we do without OOP?

You can do without OOP and stay procedural. Keep the functions small and re-factor where it makes sense.  Separate responsibilities and push for code reuse. Don't repeat yourself (DRY)!!!

Is that less good?
As long as the application is coded in a way that keeps things separated and allow for code reuse, then you can work either way.

I wanna learn.
OOP is more of a thought process first. Think in objects and tasks, not by function alone. It is not something you can master in a "twentysecond stab"... well maybe without code.

Usual beginning ideas are everyday objects - a car or a dog.

A Dog barks (dog.bark()), walks (dog.walk()), has a certain color coat (dog.color). 
A car drives ($car->drive()), brakes ($car->break()), has a 6 cylinder engine ($car->engine(new GasEngine(6, new Cylinder)).

What about human hands? One hand = 1 palm, 5 fingers (4 + 1 thumb), 5 nails, etc. and can move, point, etc.

Code can then be done in any language - PHP, Javascript, etc, without doing actual OOP syntax. Then when you get comfortable, you can start applying code to actual objects (but with Javascript, everything is an object...). You can start with Javascript since you may be more comfortable with JS than PHP.
Logged

Fred K

  • Still trying to learn stuff
  • ULTIMATE member
  • ******
  • Karma: 130
  • Posts: 2728
    • Personal
Re: Discussions on ideas for a core framework
« Reply #26 on: August 18, 2012, 12:39:01 AM »

Quote
Think in objects and tasks, not by function alone. It is not something you can master in a "twentysecond stab"...

It was [the] twentysecond (22nd) stab. My next stab at understanding the basics of OOP will be my 23rd. Or 51st. I've lost count to be honest. But I wrote unclearly so the misinterpretation is understandable. ;)

I want to learn OOP, but with my mind it's easier to decypher a Caravaggian masterpiece than to get to grips with the basics of scripting. Javascript is for me on the same level. With a Caravaggio painting or a Joyce novel I can tell how it works, how it was built, even if I can't ever replicate it. With OOP, or Javascript, I can't tell. Too abstract. Mind runs for the hills, wailing.
But maybe it's just a thing of experience. My mind used to run for the hills, wailing, from looking at PHP. Now it accepts it, albeit grudgingly. So maybe after a few hundred more stabs at OOP I'll get my mind to accept it. Who knows?
That said, the barking dog thing? It means nothing to me. ;)
Logged

nukpana

  • Hero Member
  • *****
  • Karma: 71
  • Posts: 663
Re: Discussions on ideas for a core framework
« Reply #27 on: August 18, 2012, 01:42:29 PM »

Quote
Think in objects and tasks, not by function alone. It is not something you can master in a "twentysecond stab"...

It was [the] twentysecond (22nd) stab. My next stab at understanding the basics of OOP will be my 23rd. Or 51st. I've lost count to be honest. But I wrote unclearly so the misinterpretation is understandable. ;)

I want to learn OOP, but with my mind it's easier to decypher a Caravaggian masterpiece than to get to grips with the basics of scripting. Javascript is for me on the same level. With a Caravaggio painting or a Joyce novel I can tell how it works, how it was built, even if I can't ever replicate it. With OOP, or Javascript, I can't tell. Too abstract. Mind runs for the hills, wailing.
But maybe it's just a thing of experience. My mind used to run for the hills, wailing, from looking at PHP. Now it accepts it, albeit grudgingly. So maybe after a few hundred more stabs at OOP I'll get my mind to accept it. Who knows?
That said, the barking dog thing? It means nothing to me. ;)

Well, being honest here, why bother trying to learn OOP if you are still having trouble with regular PHP/JS?  ??? ??? ???

http://www.codecademy.com - alot of people are using this to learn how to code with Javascript. My wife can now understand basic JS since she used this. Hell, the Mayor of New York City is learning: http://mashable.com/2012/01/05/bloomberg-codecademy/

Oh, btw, what I was getting at with the dog/car was an analogy to already in use methods you probably use often in Javascript.
// Examples of object methods
Code: [Select]
dog.bark('loudly');
document.write('something');

// Examples of setting an object's properties
Code: [Select]
dog.furColor = 'brown',
element.innerHTML = '<p>My dog\'s color is brown</p>';

//Example of getting an object's properties
Code: [Select]
dog.eyeColor; // Brown
element.id; // An Element's id

If you don't get it, that is ok. I am not trying to convince anyone to learn or use anything...
Logged

Keyrocks

  • Doug
  • ULTIMATE member
  • ******
  • Karma: 449
  • Posts: 6019
  • Semantically Challenged
    • snews.ca
Re: Discussions on ideas for a core framework
« Reply #28 on: August 18, 2012, 03:52:26 PM »

So maybe after a few hundred more stabs at OOP I'll get my mind to accept it. Who knows?
That said, the barking dog thing? It means nothing to me. ;)

Here's one of many good Procedural VS OOP Programming references... this one provides a 'real world' example using cars (instead of barking dogs) that may make the fuzziness a bit more clear.

Or maybe Robert Green's OOP Basics Part 1 with comparisons of achieving the same end results with both procedural and OOP might shed some light on the subject. Mr. Green refers to OOP as a "state of mind".
Logged
Do it now... later may not come.
-------------------------------------------------------------------------------------------------
sNews 1.6 MESU | sNews 1.6 MEMU

Fred K

  • Still trying to learn stuff
  • ULTIMATE member
  • ******
  • Karma: 130
  • Posts: 2728
    • Personal
Re: Discussions on ideas for a core framework
« Reply #29 on: August 18, 2012, 04:01:16 PM »

Quote from: nukpana
why bother trying to learn OOP if you are still having trouble with regular PHP/JS?

Because if OOP is to be used in the nextGen sNews I want to give myself a chance at understanding it.
Logged
Pages: 1 [2] 3