Manipulate every part of an HTML Page at any time.
A framework agnostic HTML framework that allows you to manipulate every part of an HTML Page at any time.
A Dependency Injection Pimple\Container instance. We don't automatically create this for you, until and unless you access it here. If you don't want a Pimple object, then you can set the static Page::$global
to whatever suits your fancy.
Either the Symfony\Component\HttpFoundation\Request object you gave us at Page::html()
, or the one we made for you.
A lazy BootPress\Page\Session instance. This object will not call session_start()
until and unless you set a $_SESSION
value, or if the session $_COOKIE
is set and you want to get a value.
A static confirmation that the session has been started, and the flash vars managed.
Ensure a session has been started, and get the session_id()
.
Set the $value of a $_SESSION[$key].
$_SESSION key(s) inarray()
or dot '.' notation.
Any value except null
.
$page->session->set(array('key', 'custom), 'value');
$page->session->set('user.id', 100);
Merge $values into a $_SESSION[$key]. If it wasn't an array before, it will be now.
$_SESSION key(s) inarray()
or dot '.' notation.
To overwrite or add.
$page->session->add('user', array('name' => 'Joe Bloggs'));
Retrieve the value of a $_SESSION[$key].
$_SESSION key(s) in array()
or dot '.' notation.
The value you want to return if the value does not exist.
Either $default if the value does not exist, or the value if it does.
echo $page->session->get(array('key', 'custom)); // value
print_r($page->session->get('user')); // array('id' => 100, 'name' => 'Joe Bloggs')
Unset the $_SESSION $key(s). Every param you pass will be removed.
$_SESSION key(s) in array()
or dot '.' notation.
$page->session->remove('user');
Set a flash value that will only be available on the next page request.
$_SESSION flash key(s) inarray()
or dot '.' notation.
Any value except null
.
$page->session->setFlash('message', 'Hello world!');
Get a flash value that was set on the previous page request.
$_SESSION flash key(s) in array()
or dot '.' notation.
The value you want to return if the value does not exist.
Either $default if the value does not exist, or the value if it does.
$page->session->getFlash('message'); // Hello world!
Keep the flash values in the current request, and add them to the next page request. This is not necessary for XML Http Requests, as we only forward the flash vars on HTML page requests.
An array of directory names for reference purposes:
$url['dir']
when you first accessed the Page::html()
.$name = $page->dirname(__CLASS__)
directory.$page->dirname()
ed.Information about your url's that may come in handy:
$url['base']
when you first accessed the Page::html()
, including a trailing slash '/'.$url['suffix']
when you first accessed the Page::html()
.preg_quote()
ed, and ready to go.$url['chars']
when you first accessed the Page::html()
, preg_quote()
ed, but with the dot ('.'), slashes ('/'), question mark ('?'), and hash tag ('#') removed, so that we can include them as desired.$url['suffix']
's that correspond with html pages.'/'.$page->url['path']
.array($name => $url, ...)
of the $page->url('set', $name, $url)
's you (and we) have set.The property from which all others are set and retrieved. The ones we use to $page->display()
your page are:
<!doctype html>
' that goes at the top of your HTML page.<html lang="...">
value. The default is 'en'. If your page no speaka any english, then you can change it to $page->language = 'sp'
, or any other two-letter language abbreviation.<meta charset="...">
value. The default is 'utf-8'.<head>
section within <title>
tags (empty or not). The default is empty.<meta name="description" content="...">
value (if any). The default is empty.<meta name="keywords" content="...">
value (if any). The default is empty.false
, then we'll tell the search engines <meta name="robots" content="noindex, nofollow">
: "Don't add this page to your index" (noindex), and "Don't follow any links that may be here" (nofollow) either. If you want one or the other, then just leave this property alone and you can spell it all out for them in $page->meta('name="robots" content="noindex"')
.<body>
tag.Get a singleton instance of the Page class, so that your code can always be on the same "Page". Passing parameters will only make a difference when calling it for the first time, unless you $overthrow it.
You can override any of the following default options:
$page->send()
will not exit
. This enables us to unit test responses without halting the script.A Symfony\Component\HttpFoundation\Request object.
If anything but false
, then the parameters you pass will overthrow the previous ones submitted. This is mainly useful for unit testing.
A singleton Page instance.
$page = \BootPress\Page\Component::html();
Get an isolated instance of the Page class, so that you can use it for whatever.
The 'base' url is not enforced here.
Set Page properties that can be accessed directly via $page->$name
. This is a convenience method as you can also set them directly eg. $page->name = 'value'
. All of these values are stored (and can be accessed) at the $page->html
array.
The property you would like to set. You can do this one at a time, or make this an array to set multiple values at once.
Used if the $name is a string.
$page->set(array(
'title' => 'Sample Page',
'description' => 'Snippet of information',
'keywords' => 'Comma, Spearated, Tags',
));
Send your visitor packing to another $url eg. after a form has been submitted.
Either the full url, or just the path.
The status code.
$page->eject('users');
Ensure that the $url path you want to enforce matches the current path.
Either the full url, or just the path.
The status code.
echo $page->url['path']; // 'details/former-title-1'
$page->enforce('details/current-title-1');
echo $page->url['path']; // 'details/current-title-1'
Determine the directory your $class resides in, so that you can refer to it in $page->dir()
and $page->url()
.
The __CLASS__
you want to reference.
A slightly modified $class name.
$name = $page->dirname(__CLASS__);
echo $page->dir($name); // The directory your __CLASS__ resides in
Get the absolute path to a directory, including the trailing slash '/'.
The folder path(s) after $page->dir['page']
. Every arg you include in the method will be another folder path. If you want the directory to be relative to $name = $page->dirname(__CLASS__)
, then set the first parameter to $name
, and the subsequent arguments (folders) relative to it. Any empty args will be ignored.
$page->dir(); // returns $page->dir['page'] - the one where your website resides
$page->dir('folder', 'path'); // $page->dir['page'].'folder/path/'
$page->dir('folder', '', 'path'); // $page->dir['page'].'folder/path/'
$page->dir('folder/path'); // $page->dir['page'].'folder/path/'
$page->dir('/folder//path///'); // $page->dir['page'].'folder/path/'
$page->dir($page->dir['page'].'folder/path'); // $page->dir['page'].'folder/path/'
$page->dir($page->dir['page'], '/folder/path/'); // $page->dir['page'].'folder/path/'
$page->dir('page', '/folder', '/path/'); // $page->dir['page'].'folder/path/'
$page->dir('base', 'folder/path'); // $page->dir['page'].'folder/path/' - 'base' is an alias for 'page'
$name = $page->dirname(__CLASS__); // $page->dir[$name] is now the directory where the __CLASS__ resides
$page->dir($name, 'folder', 'path'); // $page->dir[$name].'folder/path/'
Get the absolute path to a file. This method works exactly the same as $page->dir(...)
, but doesn't include the trailing slash as it should be pointing to a file.
Of the folder(s) and file. Can span multiple arguments.
$page->file('image.jpg'); // $page->dir['page'].'image.jpg'
$page->file('files', 'suffixless'); // $page->dir['page'].'files/suffixless'
$name = $page->dirname(__CLASS__); // $page->dir[$name] is now the directory where the __CLASS__ resides
$page->file($name, 'folder/file.php'); // $page->dir[$name].'folder/file.php'
Get a url path (with trailing slash '/') that you can add to and work with, as opposed to $page->url()
that always returns the $page->url['suffix']
with it.
Every argument given becomes part of the path, the same as $page->dir()
only with a url. The first argument can include the $page->url['base']
, be a $page->dirname()
, a reference that you $page->url('set', ...)
ed, or just be relative to the $page->url['base']
.
$page->path('folder'); // $page->url['base'].'folder/'
$page->path('base', 'folder'); // $page->url['base'].'folder/'
$page->path('page', 'folder'); // $page->url['base'].'page/folder/'
$page->path($page->url['base'], 'folder'); // $page->url['base'].'folder/'
Create a url, and/or manipulate it's query string and fragment.
What you want this method to do. The options are:
$page->url['full']
.$page->url['set'][$url] = $key
that can be referred to here, and in $page->path($url)
.$page->path()
, only with the $page->url['suffix']
included.If left empty then the $page->url['full']
will be used, otherwise we will htmlspecialchars_decode()
whatever you do give us. If $action == 'set'
then this is the shortcut name used to reference the url $key.
Either the url you are 'set'ing for future reference, or the paramter(s) you want to 'add' or 'delete' from the $url.
If $action == 'add' && !is_array($key)
, then this is the $key's value. Otherwise this argument means nothing.
The htmlspecialchars($url)
string with the $page->url['suffix']
included for local html pages:
$action == 'delete'
and:
$key == '#'
the fragment will be removed.$key == '?'
the entire query string will be removed.is_string($key)
it will be removed from the query string.is_array($key)
then every value will be removed from the query string.$action == 'add'
and:
is_string($key)
it's $value will be added to the query string.is_array($key)
then every key and value will be added to the query string.Except for:
$action == 'params'
then the $url query string is returned as an associative array.// Get the current url
$page->url(); // $page->url['full']
// 'base' is a reference to the ``$page->url['base']`` url
$page->url('base', 'path'); // http://example.com/path.html
// 'page' is a reference to the ``$page->dir['page']`` directory
$page->url('page', 'path'); // http://example.com/page/path.html
// You can include the base url
$page->url($page->url['base'], 'path'); // http://example.com/path.html
// Or just skip it entirely
$page->url('path'); // http://example.com/path.html
// The $page->url['suffix'] is enforced for local urls
$page->url('path.php'); // http://example.com/path.html
// The suffix stays for non-html pages
$page->url('page', 'styles.css'); // http://example.com/page/styles.css
// Any suffix goes for external urls
$page->url('http://another.com', 'path.php'); // http://another.com/path.php
// The top level index page is removed
$page->url('index.html'); // http://example.com/
// For other levels it is not
$page->url('page', 'index.php'); // http://example.com/page/index.html
// Set a url shortcut
$page->url('set', 'folder', 'http://example.com/path/to/folder');
$page->url('folder'); // http://example.com/path/to/folder.html
$page->url('folder', '//hierarchy.php/'); // http://example.com/path/to/folder/hierarchy.html
// Get the query params
$page->url('params', 'http://example.com/?foo=bar'); // array('foo' => 'bar')
// Add to the query params
$url = $page->url('add', 'http://example.com', array('key' => 'value', 'test' => 'string')); // http://example.com/?key=value&test=string
$page->url('add', $url, 'one', 'more'); // http://example.com/?key=value&test=string&one=more
// Delete from the query params
$page->url('delete', $url, 'key'); // http://example.com/?test=string
$page->url('delete', $url, '?'); // http://example.com/
// Manipulate fragments
$fragment = $page->url('add', 'http://example.com', '#', 'fragment'); // http://example.com/#fragment
$page->url('delete', $fragment, '#'); // http://example.com/
A shortcut for $page->request->query->get($key, $default)
.
The $_GET[$key]
.
The default value to return if the $_GET[$key]
doesn't exits.
A shortcut for $page->request->request->get($key, $default)
.
The $_POST[$key]
.
The default value to return if the $_POST[$key]
doesn't exits.
Map the current $route to the paths you provide using the AltoRouter.
An array($route => $target, ...)
or just array($route, ...)
, or any combination thereof. The $target could be a php file, a method name, or whatever you want that will help you to determine what comes next. A $route is what you are expecting the url path to look like, and mapping them to variables that you can actually work with:
$params['action'] = 'sign_in'
.$params['id'] = 12
.Notice that the 'i' in '[i:id]' will match an integer and assign the paramter 'id' to the value of 'i'. You can set or override these shortcuts in the $types below. The defaults are:
A few more examples for the road:
If you don't want to use the $page->url['route']
, then set this value to the path you want to match against.
If you want to add to (or override) the shortcut regex's, then you can add them here. The defaults are:
$types = array(
'i' => '[0-9]++', // integer
'a' => '[0-9A-Za-z]++', // alphanumeric
'h' => '[0-9A-Fa-f]++', // hexadecimal
'*' => '.+?', // anything (lazy)
'**' => '.++', // anything (possessive)
'' => '[^/\.]++', // not a slash (/) or period (.)
);
Either false
if nothing matches, or an array of information with the following keys:
if ($route = $page->routes(array(
'' => 'index.php',
'listings' => 'listings.php',
'details/[*:title]-[i:id]' => 'details.php',
))) {
include $route['target'];
} else {
$page->send(404);
}
Generate an HTML tag programatically.
The tag's name eg. 'div'.
An array($key => $value, ...)
of attributes.
null
, we ignore the attribute entirely.All args supplied after the $attributes are stripped of any empty values, and implode(' ', ...)
ed.
An opening HTML $tag with it's $attributes. If $content is supplied then we add that, and a closing html tag too.
echo $page->tag('meta', array('name'=>'description', 'content'=>'')); // <meta name="description">
echo $page->tag('p', array('class'=>'lead'), 'Body', 'copy'); // <p class="lead">Body copy</p>
Place a <meta>
tag in your <head>
.
Either an array of attributes, or a string that gets inserted as is.
$page->meta('name="author" content="name"'); // or ...
$page->meta(array('name'=>'author', 'content'=>'name'));
Add <link>
(s) to your <head>
.
A single string, or an array of '.ico', '.css', and '.js' files. You can also include <meta>
, <link>
, <style>
, and <script>
tags here, and they will be placed appropriately.
If anything but false
(I like to use 'prepend'), then everything you just included will be prepended to the stack, as opposed to being inserted after all of the other links that have gone before.
$page->link(array(
$page->url('images/favicon.ico'),
$page->url('css/stylesheet.css'),
$page->url('js/functions.js'),
));
Enclose $css within <style>
tags and place it in the <head>
of your page.
$page->style('body { background-color:red; color:black; }');
$page->style(array('body { background-color:red; color:black; }'));
$page->style(array('body' => 'background-color:red; color:black;'));
$page->style(array('body' => array('background-color:red;', 'color:black;')));
Enclose $javascript within <script>
tags and place it at the bottom of your page.
$page->script('alert("Hello World");');
Places all of your jQuery $code into one $(document).ready(function(){...})
at the end of your page.
$page->jquery('$("button.continue").html("Next Step...");');
We use this in the Form component to avoid input name collisions. We use it in the Bootstrap component for accordions, carousels, and the like. The problem with just incrementing a number and adding it onto something else is that css and jQuery don't like numbered id's. So we use roman numerals instead, and that solves the problem for us.
What you would like to come before the roman numeral. This is not really needed, but when you are looking at your source code, it helps to know what you are looking at.
A unique id.
// Assuming this method has not been called before:
echo $page->id('name'); // nameI
echo $page->id('unique'); // uniqueII
echo $page->id('unique'); // uniqueIII
Map a $path to a folder and $file in $dir so that you can $page->load()
it. This will essentially make your $file a controller, if you subscribe to the MVC pattern.
The base directory whose folders you want to map to a $path.
The $page->url['path']
, or whatever else you want to use.
The filename that must be in the folder to make a match.
If we have a match then we will return an array with the following info:
// Assuming ``$dir = $page->dir('folders')``, and you have a $dir.'users/index.php' file:
if ($params = $page->folder($dir, 'users/sign_in')) {
$html = $page->load($params['file'], $params);
// $params = array(
// 'file' => $dir.'users/index.php',
// 'dir' => $dir.'users/',
// 'assets' => $page->url['base'].'page/folders/users/',
// 'url' => $page->url['base'].'folders/users/',
// 'folder' => 'users/',
// 'route' => '/sign_in',
// );
}
Passes $params to a $file, and returns the output.
The file you want to include
.
Variables you would like your file to receive.
Whatever you $export
ed (could be anything), or a string of all that you echo
ed.
$file = $page->file('folders/users/index.php');
// Assuming $file has the following code:
<?php
extract($params);
$export = $action.' Users';
// Loading it like this would return 'Sign In Users'
echo $page->load($file, array('action'=>'Sign In'));
Enables you to modify just about anything throughout the creation process of your page.
Must be one of:
<title>
and <meta>
data that we include right after the <head>
tag.<link>
's and <style>
's that we include just before the </head>
tag.$page->display($content)
that comes right after the <body>
tag, and just before the javascript we include.<script>
's and jQuery code that we include just before the </body>
tag.<head>
... </head>
tags.<body>
... </body>
tags.$page->send()
it.If filtering the 'response' then we'll pass the $page
(this class instance), $response
(what you are filtering), and $type
('html', 'json', 'redirect', or $page->url['format']
) of content that you are dealing with.
$section == 'response'
The level of importance (or priority) that this filter should receive. The default is 10. All filters are called in the order specified here.
$page->filter('response', function ($page, $response, $type) {
return $response->setContent($type);
}, array('html', 200));
$page->filter('response', function ($page, $response) {
return $response->setContent('json');
}, array('json'));
$page->filter('response', function ($page, $response) {
return $response->setContent(404);
}, array(404));
$page->filter('body', function ($prepend, $html, $append) {
return implode(' ', array($prepend, $html, $append));
}, array('facebook_like_button', 'this', 'tracking_code');
Piece together the HTML Page from top to bottom.
Sends a Symfony Response object, and allows you to further process and $page->filter()
it.
Either a Symfony Response object, the content of your response, or just a quick status code eg. $page->send(404)
.
The status code if your $response
is a content string.
A headers array if your response
is a content string.
If you set Page::html(array('testing'=>true))
then we will return the Symfony Response object so that it doesn't halt your script, otherwise it will send the Response and exit the page.
if ($html = $page->load($page->file('index.php'))) {
$page->send($page->display($html));
} else {
$page->send(404);
}
Creates and sends a Symfony JsonResponse object.
The response data.
The response status code.
Add the following to your composer.json
file.
{
"require": {
"bootpress/page": "^1.0"
}
}
<?php
use BootPress\Page\Component as Page;
$page = Page::html();
The Page class implements the Singleton design pattern so that you can call it from anywhere, and still be on the same "Page". You don't have to, but if you would like to enforce a desired url scheme (recommended), then do this:
$page = Page::html(array(
'dir' => '../', // a root folder where you can keep everything safe and sound
'base' => 'https://example.com/', // this will be enforced now
'suffix' => '.html', // goes at the end of your urls
));
Now you can manipulate every part of your HTML Page at any time:
// The .ico and .css files will go to your <head>
// The .js file will be at the bottom of your <body>
$page->link(array(
$page->url('images/favicon.ico'),
$page->url('css/stylesheet.css'),
$page->url('js/functions.js'),
));
// To put a <link> before all the others you have set
$page->link('https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css', 'prepend');
// Meta tags are placed at the top of the <head>
$page->meta('name="author" content="name"'); // or ...
$page->meta(array('name'=>'author', 'content'=>'name')); // or ...
$page->link('<meta name="author" content="name">'); // You can spell all these tags out with the link method
// <style> tags are placed right after the <link>'s
$page->style('body { background-color:red; color:black; }'); // or ...
$page->style(array('body { background-color:red; color:black; }')); // or ...
$page->style(array('body' => 'background-color:red; color:black;')); // or ...
$page->style(array('body' => array('background-color:red;', 'color:black;'))); // or ...
$page->link('<style>body { background-color:red; color:black; }</style>');
// <script> tags come immediately after the .js files
$page->script('alert("Hello World");'); // or
$page->link('<script>alert("Hello World");</script>');
// All of these will go into one $(document).ready(function(){...}); at the bottom of your page
$page->jquery('$("button.continue").html("Next Step...");');
Of course, none of that does any good if you don't give us the final HTML to work with:
echo $page->display('<p>Content</p>');
That will return you a nice:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<title></title>
<meta name="author" content="name">
<link rel="shortcut icon" href="https://example.com/images/favicon.ico">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="https://example.com/css/stylesheet.css">
<style>body { background-color:red; color:black; }</style>
</head>
<body>
<p>Content</p>
<script src="https://example.com/js/functions.js"></script>
<script>alert("Hello World");</script>
$(document).ready(function(){
$("button.continue").html("Next Step...");
});
</body>
</html>
To change (or access) the default values that have been set, you can:
$page->title = 'Page Title';
$page->description = 'Page description.';
$page->charset = 'UTF-8';
$page->language = 'en-us';
echo '<h1>'.$page->title.'</h1>'; // <h1>Page Title</h1>
Above, you just gave us your <p>Content</p>
, and we created the HTML Page around it. You can also give us the entire page, and we'll still put things where they belong:
$page->display(<<<'EOT'
< !doctype html>
<html >
<HEad>< title>Broken</tit
<META content=" name " name="author">
</ head> <body style="color:#333;">
I'm in the body!</body>
< /html>
EOT;
);
That will give you:
< !doctype html>
<html >
<HEad>
<meta charset="UTF-8">
<meta name="description" content="Page description.">
< title>Broken</tit
<META content=" name " name="author">
<link rel="shortcut icon" href="https://example.com/images/favicon.ico">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.7/css/bootstrap.min.css">
<link rel="stylesheet" href="https://example.com/css/stylesheet.css">
<style>body { background-color:red; color:black; }</style>
</head>
<body style="color:#333;">
I'm in the body!
<script src="https://example.com/js/functions.js"></script>
<script>alert("Hello World");</script>
$(document).ready(function(){
$("button.continue").html("Next Step...");
});
</body>
</html>
It's a bit screwed up still, but that's how you wanted it. We took nothing out, and only added the parts that were missing with the information you gave us. This class can do as little, or as much as you like. It's all the same to us. Even if you use none of the above, it's still nice to have a central location where an application can create, and work with urls established according to your specs.
$page->enforce('seo-path'); // If the current url was not https://example.com/seo-path.html, it is now.
echo $page->url['path']; // seo-path
if ($page->get('form') == 'submitted') { // https://example.com/seo-path.html?form=submitted
$eject = $page->url('delete', '', 'form'); // https://example.com/seo-path.html
$page->eject($page->url('add', $eject, 'payment', 'received')); // go now to https://example.com/seo-path.html?payment=received
} elseif ($page->get('payment') == 'received') {
mail('user@example.com', 'Thank you for your encouragement!');
}