Also see:
docs/documentation.py
docs/structure.py
Architecture
webpage or ajax -> http server | ___________
[todo] api | | |
cron |-> | |
command line | | |
| framework | -> action -> classes, elements, engines, libraries => side effects
| | -> documents/html/my_doc_file.php -> elements/layouts/my_layout.php (for pages) or json wrapper (for ajax)
response <- | |
|___________|Components / Code Types
element, engine, action, email, class, library, function
framework-only
corefile
also static function?, native associative function?, chewitt associative function?
Naming Conventions
files
multi_word_filename.ext
database tables (core)
database tables (subcategory)
gk_ip_addresses
database columns
nonRelationalField
relational_field_id
php and js
variable
multiWordVariable
numeric_multiWordVariable as a kind of hungarian notation when necessary to clarify the data type
function
multiWordFunction
Class
MultiWordClass
html and css
class-variable, js-class-variable, or both-class-variable
id-variable
Syntax / Coding Style Conventions
comments
// comment
//commented-out line of code
/*
multi-line
comment
*/
code blocks
/* check that the parameter definition is complete */ if (true) {
line1;
line2;
}
if statements
if ($singleLineIf) $code = foo();
if (!$multiLineIf) {
$code = foo();
}
if ( (multiCondition($foo)) || (1 === $lineNum) ) {
$code = foo();
}
if ($singleLineIfWithElses) return 0;
else if ($foo) return 1;
else if ($bar) return 20;
else return 'whoops';
if ($multilineIfWithElses) {
} else if { // we could use "else if" or "elseif", but javascript only has "else if" so we use that in php as well to be consistent
} else {
}
foreach statements
foreach ($lines as $lineNumber => $line) {
$code = 'foo';
}
<? foreach ($lines as $lineNumber => $line): ?>
Foo<br>
<? endforeach ?>
function definitions
function foo($message = null) {
/* This is the explanation of this function.
*/
line1;
line2;
return $bar;
}
function calls
$temp = naiveFunction(4, false);
$temp = associativeFunction(array(
'numColumns' => 4,
'disabled' => false,
));data types
<temporal data types>
There is a lot to be said about temporal data types due to the wide variety of representations covering machine readable, human readable, dates, times, and contextualized types (isDuring = true, 'Later Today')
The following is a partial list of the kinds of data fragments we might need to represent:
isToday
isDuring
'Right Now'
'All Day'
'Later On'
'2:39pm'
'7p'
'Midnight'
'6am-11:30p'
1430
14.5
'Friday 8/15/14'
'Sunday August 17'
'Today'
'Tomorrow'
'Every Monday 7-9pm'
'Every April 15th'
2014-08-19
'Tomorrow at 6pm'
'6pm Tomorrow'
a chart of all the temporal data types, and collections of temporal data types:
single collection
instant instant
time time
day date dayO
range timeo timeoDefinition
other weekDay
monthDay
date - specifies a calendar date
represented interchangeably by any of these data types:
text date (e.g. text_startDate)
2014-07-04
numeric date (e.g. numeric_startDate) - specifies midnight on a certain day
0
1404532800 (2014-07-05 16:30:00)
// TODO: change to numeric day, as in number of days since jan 1 1970
human date (e.g. human_startDate) - human-readable date. there are multiple values for a single date - see /engines/temporal/dateHumanToText
Friday September 19 2015
9/11/15
Sept. 19 2015
dayO - also known as a Day Definition object. describes a date or multiple dates - the set of all dates in which this event occurs (technically, the dates which the event starts)
represented interchangeably by any of these data types:
component
array(
recursWeekly
startDate
startWeekday
[endWeekday]
)
TODO: develop complete data type
text
w7 ("weekly on day 7" aka every Sunday)
o2014-10-03 ("once on 2014-10-03")
date fragments
weekDay (formerly weekday) - specifies a day of the week
represented interchangeably by any of these data types:
numeric weekday (e.g. numeric_startWeekday) - specifies a day of the week
1 (monday)
5 (friday)
7 (sunday)
human weekday (e.g. human_nowWeekday)
Mon
Monday
Tues
Sunday
monthDay (formerly day) - specifies a day of the month
numeric day (e.g. numeric_day)
1
14
31
time - specifies a specific instant within a day. beware, some days may have two of the same time - for instance, on daylight savings 1:00am may occur twice
and
time interval - specifies an interval of time. can also be thought of as the amount of time passed since midnight to represent the time of day
represented interchangeably by any of these data types:
numeric hour (e.g. numeric_startHour, num_duration) - specifies a certain interval or the time since midnight (time of day). like military time but without leading zeros
30 (12:30am)
500 (5am)
530 (5:30am)
1700 (5pm)
1730 (5:30pm)
decimal hour (e.g. decimal_startHour) - specifies a certain time of day (any decimal but .5 is rejected)
0 (midnight)
17 (5pm)
23.5 (11:30pm)
24?
numeric interval - time interval in seconds
0 (midnight)
43200 (noon)
time pair
array('hours', 'minutes')
array(23, 30)
human time (e.g. human_startTime) - human-readable time. there are multiple values for a single time - see /engines/temporal/hourNumberToString
5pm
5:00pm
Noon
12p
7:30pm
instant (formerly known as dateTime) - specifies one single instant in eternity.
represented interchangeably by any of these data types:
numeric instant (aka dateTime, timestamp, epoch)
0
1404505800 (2014-07-04 16:30:00)
text dateTime aka SQL time (e.g. text_startDateTime] - a specific instant represented in SQL format. possibly beware, some days may have two of the same time - for instance, on daylight savings 1:00am may occur twice
2014-07-04 16:30:00
pair instant
array(
'text_date' => '2014-08-15',
'hour' => 1800,
)
human - human readable description of one instant in time
'2:30pm 4/15/2016'
'11am tomorrow (Friday March 11)'
timeo - also known as a Time Object or a Time Range Object. Contains all temporal info needed to describe one instance of an event, from beginning instant to end instant
represented interchangeably by any of these data types:
components
array(
startDate as text_date
startHour as numeric_hour
[endDate] as text_date
endHour as numeric_hour
allDay as bool <-- eventually obsolete
)
text
array(
start => text_startInstant
end => text_endInstant
)
numeric
array(
start => numeric_startInstant
end => numeric_endInstant
)
human - human readable description of one range in time
'6p-8p Tomorrow'
'All Day Friday November 28th'
timeoDefinition - also known as Timeo Definition Object or Time Range Definition Object. Describes all necessary temporal info to describe EVERY instance of an event.
represented interchangeably by any of these data types:
component
array(
recursWeekly as bool
startDate as text_date
startWeekday as ?
startHour as numeric_hour
[endWeekday] as ?
endHour as numeric_hour
allDay as bool <-- eventually obsolete
)
TODO: develop complete data type
human - human readable description of one or more ranges in time
'6p-8p Tomorrow'
'Noon-4pm every Friday'
'All day every Wednesday'
'8p-11p this Friday and Saturday'
other time & event related types
timeTarget - all the data needed to describe which part of eternity we're targeting, whether it be an instant or a range (specified when we want to return a set of event results)
array(
'text_date' => '2014-08-19',
'isNow' => false, // the date we're looking for is not the current day
)
or
array(
'text_date' => '2014-08-19',
'num_hour' => 1000,
'isNow' => false,
)
or
array(
'text_date' => '2014-08-15',
'num_hour' => 1700,
'isNow' => true, // the date and time we're looking for happens to be the current date and time
)
timeContext - additional context about a given date, time, or instant. given a timeo and a timeTarget, you can calculate the timeContext
works like this:
event event
other data other data
timeo then get a timeo
event timeTarget.... timeContext
other data event
timeo other data
. timeo
. timeContext
array(
isToday => true
isDuring => true
isNow => true
text_time => 'Right Now'
text_date => 'Today'
)
FORMERLY: contextualized timeo - all the fundamentally necessary timeo data, PLUS extra info for logic and rendering
array(
startDate
startHour
[endDate]
endHour
allDay <-- eventually obsolete
context => array(
isToday => true
isDuring => true
isNow => true
text_time => 'Right Now'
text_date => 'Today'
)
)
TODO: eliminate this data type, and have a Time Context or Instant Context type instead. then to contextualize an event we already have the timeo and we add the contextualized data type alongside it
eventContext - a work in progress.
beforeTarget
duringTarget
afterTarget
timeSolution - a set describing all events found during a search. this one is still a little sloppy.
array(
'empty' => array('Today', 'Friday 8/15/14' ),
'2014-08-16' => array('Tomorrow', 'Saturday 8/16/14' ),
'2014-08-17' => array('Sunday August 17', '' ),
'2014-08-18' => array('Monday August 18', '' ),
)
or
array(
'2014-08-19' => array('Tuesday August 19', '' ),
'2014-08-20' => array('Wednesday August 20', '' ),
'2014-08-22' => array('Friday August 22', '' ),
)
or
array(
'during' => array('Tuesday August 19 at 5pm', '' ),
'2014-08-19' => array('', 'Later On' ),
'2014-08-20' => array('Wednesday August 20', '' ),
'2014-08-21' => array('Thursday August 21', '' ),
)
potentially ambiguous
phrase
today
tomorrow
next tuesday
Thursday July 31
2014-08-15
2014-08-15 1930
2014-08-15 at 7:30pm
time range - limited usefulness because it can't describe any interval spanning past midnight without being ambiguous
human time range
'6-8pm'
'all day'
'11:30am to 3:00 pm'
<location data types>
locationTarget
array(
'type', // city, region, device, point, or text
'text',
'numeric' => array(
'lat' => $lat,
'lng' => $lng,
),
'radius' => array(
'miles',
'text',
),
);
city region device text point
is this an actual locatable place on the earth? (GPS coords, street address, or intersection - as opposed to a city, a neighborhood, etc.) n n y y or n y
is this location associated with a defined boundary of any kind? y y n y or n n
is this location the user's current location that follows them around, either on a desktop or handheld device? (as opposed to something the user typed in) n n y n n
locationSolution
array(
)
<file data types>
filePNE - Stands for Path + Name + Extension(s), e.g. /var/www/versions/xx/app/cron/daily.php
fileo - a file object. contains a filename and an optional relative path
array(
'filename' => 'something.php',
'path' => array(
'action',
'pages',
'mod',
),
)
TODO: change to array('path', 'name', 'extension')
? - e.g. /sites/chewitt/actions/pages/full/event/edit
? - edit
<stats object>
an array of chewitt.com statistics in the following format:
144 => array( // 144 is the number of days since launch
'venues' => array(
'current' => array(
2 => 120, //2 is the city id
3 => 409,
'old' => array(
2 => 4,
3 => 22,
)
),
'users' => array(
'current' => array(
2 => 120,
3 => 409,
'invited' => array(
2 => 123,
3 => 356,
),
),
'events' => array(
'currentUnique' => array(
2 => 120,
3 => 409,
),
'currentRecurring' => array(
2 => 120,
3 => 409,
),
'stale' => array( // recurring events that have been automatically flagged
2 => 20,
3 => 49,
),
'deleted' => array( // recurring events that were confirmed to no longer apply, and (occasionally) unique events that were cancelled before they happened
2 => 12,
3 => 130,
),
'past' => array( // unique events that have already occurred
2 => 430,
3 => 1187,
),
),
)
<code stats object>
an array of app and site code statistics in the following format:
24 => array( // 24 is the number of days since launch
'code' => array(
'totalLines' => 39750,
'programLines' => array(
'app' => 12000,
'chewitt' => 10000,
'wsih' => 4000,
),
'testLines' => array(
'app' => 3000
'chewitt' => 1000,
'wsih' => 200,
),
'files' => array(
'app' => 160
'chewitt' => 110,
'wsih' => 16,
),
),
'actions' => array(
'pages' => array(
'chewitt' => 60,
'wsih' => 4,
),
'ajax' => array(
'chewitt' => 40,
'wsih' => 3,
),
),
),
<other data types>
website address
string
google.com
http://www.cjecksphilly.com/specials.php?day=Wednesday
array - the most precise way to describe a location within our own site
array() (chewitt.com homepage)
array('events', 'search')
array('event', 39)
href segments - an array containing both the most-human-friendly and the most-machine-friendly versions
array('title' => 'google.com', 'url' => 'http://google.com')
array('title' => 'cjecksphilly.com/specials.php?day=Wednesday', 'url' => 'http://www.cjecksphilly.com/specials.php?day=Wednesday')
request object - everything we need to know to generate a response<action>
init object is in the format:
array(
'access' => array('admin', true),
'params' => array(
array('name' => 'id', 'type' => 'non-negative int', 'source' => 'path', 'required' => true, 'default' => null)
),
'render' => array(
'title' => 'User Agent Details',
'layout' => 'minor',
'subTitle' => 'User Agent Details',
),
);<engine>
[description]
aka:
function
pure
pure function
definition
translator
transformer
converter
scope
lambda
mapper
computation
self-contained
standalone
autonomous
enclosed
independent
discrete
deterministic
...
advantages of engines over functions:
- named parameters
- only way to do this in native PHP is by passing an associative array, but then we lose type hinting, "required" validation, & default values
- advanced parameter validation ('type' => 'positive int', 'type' => 'city id', ...)
- test data is stored in the same place as the code being tested
- easy to wrap with other code for benchmarking, debugging, etc.
- [TODO maybe someday] return value validation
advantages over OO:
- output is predictable based solely on input, not dependent on external state ("referential transparency")
- cacheable ("memoization")
- doesn't change external state (no "side effects")
disadvantages:
- engine name is not included in stack traces, we must remember to add that to the error message manually.
- engine.php makes a lot of appearances in the call stack
- (solved by opcode caching) the code for an engine must be re-opened and re-parsed every time it's called, instead of just once for the request
- engines are invisible to IDEs
Four standard methods:
Create / add (REST: post, SQL: insert)
Read / get / retrieve (REST: get, SQL: select)
Update / edit / modify (REST: ?, SQL: update)
Delete / remove / destroy (REST: delete, SQL: delete)
> Create or update > (REST: put, SQL: ?)
> Create if doesn't exist > (REST: ?, SQL: ?)
Plus:
Validate - "is this likely to work when I do it for real?"
Not proper:
Search - really just objectList->get<task>
Loading a site from an existing repository
Steps:
...
Creating a new site from scratch
Steps:
- add a folder in <framework root>/sites
- add an entry to sites.php (current sites: chewitt, enhance, pack, plate, and sandwich)
- add a paths.php file in the new folder
- add an index file actions/pages/_index_.php in the new folder
- add other pages in the form actions/pages/<category>/<name>.php
- read the documentation
- add database objects as needed
- enhance with ajax actions, elements, engines, functions, classes, css, & js as needed
- ???