. ☽ _ ﹏__﹏_ک_____ ___ ﹏__﹏_ψ﹏___﹏___﹏﹏﹏____ · · · , · ፧ · . ░ · · , ⋰ ∴ . . · ° · , . ° · , ༶
composer create-project jyoungblood/slime new-project-name
composer update --optimize-autoloader
SLIME is a "full stack" tool kit designed to make the process of developing dynamic server-rendered web applications significantly easier and more enjoyable.
It's built with old boring technology, and will run in any LAMP (shared web hosting) environment with no extra setup required.*
Spend less time fighting with software and more time enjoying life with your family and friends!
[[FIRST PRINCIPLES
NEW SECTION - that briefly outlines the impetus for creating the framework, the need it fills, and the ideals/conventions intended to be used for creating apps/sites w/ the framework
]]
This tool kit was designed to make it easy to develop internet-based applications that operate in perpetuity with minimal technical overhead. Templates are dynamically rendered on the server and delivered as static html. This frameworks provides organization for your project and conventions for making technical decisions.
* NOTE: If you're using Coda, install the handlebars mode for syntax highlighting in your templates.
it's pretty easy to see where everything is and what to do settings (global site vars, db setup, this is a good place to set timezone/debugging/upload/php settings, too) global functions / handlebars helpers controllers / routes [back end code]
[cool to have a image or diagram of the folder tree / application structure]
you can organize the controllers folder however you want, it doesn't matter...just remember to link all the files you add in _routes.php (we want to automatically include all the files in this folder but there's no easy way to do that w/ php so whatev)
FRONT END STUFF (you can easily comment this out if you don't want it, but it's super handy if you're doing stuff from scratch) - tachyons - http://www.tachyons.io/ - jquery (& cookie) - normalize
You can accept any type of http request and do things with them (really cool if you want to make an actual rest api with http verbs) (all current http verbs are supported, so you can get as specific as you want)
$app->get('/whatever/url/you/define', function(){
// your PHP code here
});
$app->post('/whatever/url', function(){
// your PHP code here
});
$app->post('/whatever/url', function(){
// your PHP code here
});
$app->put('/whatever/url', function(){
// your PHP code here
});
$app->delete('/whatever/url', function(){
// your PHP code here
});
$app->patch('/whatever/url', function(){
// your PHP code here
});
$app->copy('/whatever/url', function(){
// your PHP code here
});
$app->head('/whatever/url', function(){
// your PHP code here
});
$app->options('/whatever/url', function(){
// your PHP code here
});
you can do that too (this code will run whenever you try to access this url with any kind of http request)
$app->all('/whatever/url', function(){
// your PHP code here
});
$app->any('/whatever/url', function(){
// your PHP code here
});
also, you can do stuff with regex or whatever to retrieve parameters from the urls. here are a few examples. see the alto router docs for more detailed info (stereo uses alto router, so you can parse the parameters in a lot of ways. here are a few examples. refer to the docs for more) - https://github.com/dannyvankooten/AltoRouter - how to work w/ the router: https://longren.io/basic-routing-in-php-with-altorouter/ CHECK IT OUT!!! http://altorouter.com/usage/mapping-routes.html
With or without the trailing slash:
$app->get('/about/?', function(){
// your PHP code here
});
Using a url parameter as variable:
$app->get('/register/activate/[*:hash]', function($hash){
// url parameter is available to your PHP code as $hash
});
And of course you can access _GET vars like normal PHP docs:
$app->get('/directory/search/?', function(){
// ex url: http://partyphysics.com/directory/search/?fish=betta&dish=espinacas&planet=keppler-452b
echo $_GET['fish']; // betta
echo $_GET['dish']; // espinacas
echo $_GET['planet']; // keppler-452b
});
Render a handlebars template with special STEREO abstraction variables () -- future docs: the passwords part of this requires php >= 5.5
$app->get('/handlebars-stereo', function(){
$GLOBALS['app']->render_template(array(
'template' => 'planets',
'title' => 'Cool Planets',
'layout' => false,
'data' => array(
'righteous_content' => 'for_sure',
'planets' => array(
'Mercury', 'Venus', 'Earth', 'Nibiru'
)
)
));
});
Render an array of data as a JSON string and send with JSON headers (handy for easily making API responses)
$app->post('/json-response', function(){
$GLOBALS['app']->render_json(array(
'righteous_content' => 'for sure',
'planets' => array(
'Mercury', 'Venus', 'Earth', 'Nibiru'
)
));
});
Render a handlebars template using a php array for saturation (note this is not attached to the stereo $app class)
$app->get('/handlebars-normal', function(){
echo $GLOBALS['engine']->render('handlebars-example', array(
'righteous_content' => 'for sure',
'planets' => array(
'Mercury', 'Venus', 'Earth', 'Nibiru'
)
));
});
want to show just a document? do it like this
$app->get('/normal-page', function(){
require __DIR__ . '/pages/whatever.html';
});
send a header. it can be whatever you want...this is nothing special with the framework, just something good to remember
$app->get('/whatever', function(){
header("Location: http://partyphysics.com/");
});
the simplest thing to do. if you use render_template, stereo includes a few by default (year, etc) as well as a few special things (is_admin, auth, user_id, etc) (title [uses the site title by default, so it's kinda optional])
php
$app->get('/variable-example', function(){
$GLOBALS['app']->render_template(array(
'template' => 'demo',
'data' => array(
'fish' => 'salmon',
'dish' => 'paella',
'planet' => 'Nibiru'
)
));
});
hbs (note about literals { { { } } } vs { { } } -- by default hbars doesn't parse html tags, so if you want to have them rendered, do this)
<h2>Simple Variables Example</h2>
<h3>Cool Fish: {{fish}}</h3>
<h3>Cool Dish: {{dish}}</h3>
<h3>Cool Planet: {{planet}}</h3>
it's hella easy, just like a foreach loop. you can even nest the arrays to infinity (and beyond) (sorry) (it can be as simple or complex as you want to make it) (see the demo controller/templates for an example of more complex array iteration)
php (simple & complex example from demo)
$app->get('/array-example', function(){
$GLOBALS['app']->render_template(array(
'template' => 'demo',
'data' => array(
'snacks' => array(
'Carrots',
'Hay',
'Sugar Cubes',
'Oats',
'Apples',
'Weaker Horses'
)
)
));
});
hbs (simple & complex example from demo)
<ul>
{{#each snacks}}
<li>{{this}}</li>
{{/each}}
</ul>
you can do some simple logic to check if a variable exists (or has value). if you would like to do more complex logic, check out [if_either], [in_array], [is]
php
$app->get('/logic-example', function(){
$GLOBALS['app']->render_template(array(
'template' => 'demo',
'data' => array(
'fish' => 'salmon',
'dish' => 'paella',
)
));
});
hbs (if/else, unless, (normal hbars logic, link to hbars docs) maybe is & link to helpers)
{{#if fish}}
Salmon is available
{{else}} // this won't show:
No salmon for you.
{{/if}}
{{#unless snacks}}
No snacks available. We have {{dish}}, though.
{{else}} // this won't show:
Look at all the snack options:
{{#each snacks}}
- {{this}} <br />
{{/each}}
{{/unless}}
You can include templates in other templates! That is neat! all your partials need to be in the _partials directory, but you can organize that however you want!
normal php whatever example
$app->get('/partials-example', function(){
$GLOBALS['app']->render_template(array(
'template' => 'demo',
'data' => array(
'fish' => 'salmon',
'dish' => 'paella',
'planet' => 'Nibiru'
)
));
});
hbs
<h2>Demo page (rendered with partial from separate template)</h2>
<h3>Fish: {{fish}}</h3>
<h3>Dish: {{dish}}</h3>
{{> planets-partial}}
hbs (partial code) (see how it has access to the same data?)
<ul>
{{#each planets}}
<li>{{this}}</li>
{{/each}}
</ul>
if you want to use a global header footer, you can! you can define as many global wrappers/layouts as you want (like express, django, ember, whatever...wow!) if you leave the "layout" parameter blank, STEREO will use the layout in ./pages/_layouts/base.hbs by default. your content will be rendered where the [[outlet]] part is
php example
$app->get('/layouts-example', function(){
$GLOBALS['app']->render_template(array(
'template' => 'demo',
'title' => 'Site Title Whatever',
'layout' => 'admin', // false for nothing, base by default
'data' => array(
'fish' => 'salmon',
'dish' => 'paella',
'planets' => array(
'Mercury', 'Venus', 'Earth', 'Nibiru'
)
)
));
});
hbs (wrapper)
<!DOCTYPE html>
<html>
<head>
<title>{{title}}</title>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge, chrome=1" />
<link rel="stylesheet" href="/css/app.css" />
</head>
<body>
<div class="header"><h1>Site Title Whatever</h1></div>
<div class="container">
[[outlet]] // this is where the content will be rendered
</div>
<div class="footer">(c) {{year}} -- All rights reserved or whatever.</div>
<script src="/js/vendor/jquery.min.js"></script>
<script src="/js/app.js"></script>
</body>
</html>
hbs
<h2>Demo page (rendered with global wrapper)</h2>
<h3>Fish: {{fish}}</h3>
<h3>Dish: {{dish}}</h3>
<ul>
{{#each planets}}
<li>{{this}}</li>
{{/each}}
</ul>
need to make an arbitrary variable/array available to all the templates? use $GLOBALS['locals'] (hold for laugh) but seriously, folks, treat it like an array and whatever you need. and if it's an array is something you can iterate over. and, of course, all of this is available to the application as $GLOBALS['locals']['numbers'] or whatever
php example
$GLOBALS['locals']['eat_this'] = "breakfast";
hbs
Let's have {{locals.eat_this}} for dinner.
php example
$GLOBALS['locals']['colors'] = array('red', 'salmon', 'lilac', 'azul');
hbs
<ul>
{{#each locals.colors}}
<li>{{this}}</li>
{{/each}}
</ul>
transform string to lowercase (link to php docs)
{{lowercase hbar_variable}}
// "Don't Fear The Reaper" ---> "don't fear the reaper"
escape quotes (link to php docs)
{{addshlashes hbar_variable}}
// "Don't Fear The Reaper" ---> "Don\'t Fear The Reaper"
note u gotta use 3 curly braces w/ this because it turns plain text to html just F Y I// nl2br // transform line breaks to "br /" ()link to php docs
{{{nl2br hbar_variable}}}
/*
"Don't Fear
The Reaper" ---> "Don't Fear <br /> The Reaper"
*/
to_fixed - return given number calculated to given number of decimal places (defaults to 2)
{{to_fixed hbar_variable}} // 3.14
{{to_fixed hbar_variable 4}} // 3.1415
{{to_fixed hbar_variable 0}} // 3
parse unix timestamp into human-readable date format (basically php's date()). use "now" for current date/time
{{date hbar_variable "m/d/Y"}} // "1459036800" ---> "3/27/2015"
{{date "now" "m/d/Y"}} // "{{date "now" "m/d/Y"}}"
transform time/date format (same as date, but it turns a string [like a js date object] into unix time first)
{{date_transform hbar_variable "m/d/Y"}} // "Sun Aug 14 2016 00:00:00 +0000" ---> "8/14/2016"
in_array -- return true(/false) if this item is(/is not) in the array -- can be a csv string, too
/*
colors_array = ['red', 'salmon', 'lilac', 'azul']
-- or --
colors_array = "red, salmon, lilac, azul"
*/
{{#in_array "green" colors_array }}
it's in the array!
{{else}}
it's not in :(
{{/in_array}}
if_either - return true if the first thing equals either the second or third thing (they could also be hbar_variables)
{{#if_either hbar_variable "salmon" "azul"}}
it's true :)
{{else}}
it's false :(
{{/if_either}}
this one has a lot of cool options // is // basic comparison operators you can compare either hbars variables or strings (and use arrays, in some cases) acceptable operators: ==, ===, not, !=, <,>, <=,>=, in, typeof
{{#is hbar_variable "==" "paella"}}
yes :)
{{else}}
no :(
{{/is}}
// will also show if the first thing is contained within the second thing (even it's CSV) (2nd thing can be a string, csv list, or an array) // 2nd param can beither array or csv
{{#is hbar_variable_1 "in" hbar_variable_2}}
yes :)
{{else}}
no :(
{{/is}}
// you can also compare variables by types (array, string, integer, etc) (uses php gettype
{{#is hbar_variable_1 "typeof" hbar_variable_2}}
yes :)
{{else}}
no :(
{{/is}}
it's easy, just write a php function and put it in ./controllers/_global.php and then use it in whatever template. look! (you can copy this code as a good starting point). here's a simple example combining a couple simple native php functions. take a look at the handlebars-helpers file to see more examples of how we put together the more complex helpers (we got a lot of these from somewhere, anyone remember where?)
php example
$engine->addHelper('lowercase_slashes', function($template, $context, $args, $source) {
$parsed_args = $template->parseArguments($args);
return lowercase(addslashes($context->get($parsed_args[0])));
});
corresponding hbs (wrapper)
{{lowercase_slashes hbar_variable}}
// "Don't Fear The Reaper" ---> "don\'t fear the reaper"
Make an http request to a given url (using curl), send data, return the raw response.
$data = $GLOBALS['app']->http_request('https://external-api.com/v3/example-response', array(
'user_id' => 581146,
'api_key' => '696719xvckvzxspigh24y1e-b'
));
if you need to make a json/http request a GET request instead of post, do this:
Make an http request to a given url, send data, and return an array of response data (expects response in json format...like the kind sent from render_json). (append _debug to just make an http request and see the raw result)
$data = $GLOBALS['app']->json_request('https://external-api.com/v3/example-response', array(
'user_id' => 581146,
'api_key' => '696719xvckvzxspigh24y1e-b'
));
/* expected response:
{
first_name: "Eddie",
last_name: "Mercury",
favorite_fish: "Salmon"
}
*/
print_r($data);
/*
array(
'first_name' => 'Eddie',
'last_name' => 'Mercury',
'favorite_fish' => 'Salmon'
);
*/
Make a json request to a given url, send hard-coded data from cookies (user_id, auth_token, admin_token, moderator_token). Specialized for use with STEREO patterns/components (coming soon) -- // same as json_request, but in addition to data params, this sends the user_id, auth_token, admin_token, moderator_token set in cookies as those params, uses the $GLOBALS['api_root'] in settings. you can set extra variables to send (like if your api requires a key or whatever...see stereo-core.php, the function called "api_request" obv) (append _debug to just make an http request and see the raw result)
$data = $GLOBALS['app']->api_request('/admin/events/screen', array(
'parameter_1' => 'cool stuff',
'parameter_2' => 'cooler stuff'
));
/* data sent to api would look something like:
{
user_id: "581146",
admin_token: "123123-1230973t2097sdv",
auth_token: "1203920rdvslasphwg",
moderator_token: false,
parameter_1: "cool stuff",
parameter_2: "cooler stuff"
}
*/
/* expected response:
{
first_name: "Eddie",
last_name: "Mercury",
favorite_fish: "Salmon"
}
*/
print_r($data);
/*
array(
'first_name' => 'Eddie',
'last_name' => 'Mercury',
'favorite_fish' => 'Salmon'
);
*/
Set a cookie for a given amount of time.
$GLOBALS['app']->cookie_set(
'user_name',
'Buzz', // can be a string or an array or whatever
1461619625 // optional, in unix time format, default is time() + 31536000000
);
Return the value of a given cookie.
echo $GLOBALS['app']->cookie_get('user_name'); // Buzz
Delete a given cookie.
$GLOBALS['app']->cookie_delete('user_name');
Sanitize parameters and insert array of data into database. Returns the id of the record created.
$new_id = db_insert("celestial_bodies", array(
'name' => 'Luna',
'classification' => 'moon',
'comment' => 'Earth\'s moon, also commonly referred to as "the moon"'
));
echo $new_id;
Sanitize parameters and retrieve data from database. (SELECT *)
Returns an array with the the data and a
total number of results.
$planets = db_find("celestial_bodies", "classification = 'planet' ORDER BY title ASC LIMIT 8");
foreach ($planets['data'] as $p){
echo $p['title'];
echo $p['classification'];
// etc, etc
}
echo $planets['total']; // 8
You can run a raw query (if you need to do joins or anything fancy)
$space_objects = db_find("", "SELECT title, classification FROM celestial_bodies WHERE id IS NOT NULL", array(
'raw' => true
));
If APC is enabled on your system, you can cache your queries
$planets = db_find("celestial_bodies", "classification = 'planet' ORDER BY title ASC", array(
'cache' => true,
'cache_length' => 120 // optional, in seconds, default is 60
));
Sanitize parameters and update a database record.
db_update("celestial_bodies", array(
'name' => 'Mars',
'comment' => 'Research "The Phobos Incident" -- we are not alone'
), "name='Marz'");
Sanitize parameters and delete a given database record.
db_delete("celestial_bodies", "name='venice'");
Send an plain text or html email (with mailgun api, if available, otherwise using php mail).
$GLOBALS['app']->email_send(array(
'to' => 'static@hexgirlfriend.com',
'from' => 'sitemeister@partyphysics.com',
'cc' => 'cc-address@partyphysics.com', // optional
'bcc' => 'bcc-address@partyphysics.com', // optional
'reply-to' => 'reply-address@partyphysics.com', // optional
'subject' => 'Send me an email',
'html' => true, // optional, message will be sent as plain text unless this is true
'message' => 'Right now...<br /><br /><br /><b><u>RIGHT NOW</u></b>'
));
update docs: NOW YOU CAN USE TEMPLATES TO MAKE HTML EMAILS!
$GLOBALS['app']->email_send(array(
'from' => 'static@hexgirlfriend.com',
'to' => 'jonathan.youngblood@gmail.com',
'template' => 'mail/test',
'layout' => 'mail',
// 'preview' => true,
// 'debug' => true,
'data' => array(
'email' => 'jonathan.youngblood@gmail.com'
),
));
Return the address of the computer making the current request.
echo $GLOBALS['app']->client_ip();
fixit disclaimer about ip addresses and accuracy (we use a couple of redundant methods, but you can't really trust them in general because of the nature of how ip addresses work...easily spoofable, etc)
url_slug
echo $GLOBALS['app']->url_slug();
url_strip
echo $GLOBALS['app']->url_strip();
url_validate
echo $GLOBALS['app']->url_validate();
mysql_date
echo $GLOBALS['app']->mysql_date();
video_id
echo $GLOBALS['app']->video_id();
br2nl
echo $GLOBALS['app']->br2nl();
pagination_query
echo $GLOBALS['app']->pagination_query();
pagination_links
echo $GLOBALS['app']->pagination_links();
array_encode
echo $GLOBALS['app']->array_encode();
array_decode
echo $GLOBALS['app']->array_decode();
- how to work w/ nginx link to patterns/components repo - examples of how to do various kinds of things - copy/paste code samples - routing - crud operations - etc - working w/ compose pattern lib reqs [- phmagick (imagemagick) [- s3 upload (what's it called?) [- smoke [- dropzone [- fancybox [- mailgun setting max file size (w/ htaccess / php) upload_max_filesize = 20M post_max_size = 20M