PHPFUI

PHP Wrapper for the Foundation CSS Framework
PHPFUI, PHP Foundation User Interface, is a 7.1 PHP library that produces HTML formated for Foundation. It does everything you need for a fully functional Foundation page, with the power of an OO language. It currently uses Foundation 6.6 and PHP 7.1 or higher.
"I was surprised that people were prepared to write HTML. In my initial requirements for this thing, I had assumed, as an absolute pre-condition, that nobody would have to do HTML or deal with URLs. If you use the original World Wide Web program, you never see a URL or have to deal with HTML. You're presented with the raw information. You then input more information. So you are linking information to information--like using a word processor. That was a surprise to me--that people were prepared to painstakingly write HTML."
Sir Tim Berners-Lee, inventor of the World Wide Web
Using PHPFUI for view output will produce 100% valid HTML and insulate you from future changes to Foundation, your custom HMTL layouts, CSS and JS library changes. You write to an abstract concept (I want a checkbox here), and the library will output a checkbox formatted for Foundation. You can inherit from CheckBox and add your own take on a checkbox, and when the graphic designer decides they have the most awesome checkbox ever, you simply change your CheckBox class, and it is changed on every page system wide.
Don't write HTML by hand!
Usage
namespace PHPFUI;
$page = new Page();
$form = new Form($page);
$fieldset = new FieldSet('A basic input form');
$time = new Input\Time($page, 'time', 'Enter A Time in 15 minute increments');
$time->setRequired();
$date = new Input\Date($page, 'date', 'Pick A Date');
$fieldset->add(new MultiColumn($time, $date));
$fieldset->add(new Input\TextArea('text', 'Enter some text'));
$fieldset->add(new Submit());
$form->add($fieldset);
$page->add($form);
$page->addStyleSheet('/css/styles.css');
echo $page;
Installation Instructions
composer require phpfui/phpfui
Then run update.php from the vendor/phpfui/phpfui directory and supply the path to your public directory / the directory for the various JS and CSS files PHPFUI uses. This will copy all required public files into your public directory. For example:
php vendor/phpfui/phpfui/update.php public/PHPFUI
The PHPFUI library defaults to your-public-directory/PHPFUI, it can be overridden, but it is suggested to use PHPFUI to keep everything in one place. update.php should be run when ever you update PHPFUI.
Versioning
Versioning will match the Foundation versions for Major semantic versions. PHPUI will always support the most recent version of Foundation possible for the Major version. PHPFUI Minor version will include breaking changes and may incorporate changes for the latest version of Foundation. The PHPFUI Patch version will include non breaking changes or additions. So PHPFUI Version 6.0.0 would be the first version of the library, 6.0.1 would be the first patch of PHPFUI. Both should work with any Foundation 6.x version. PHPFUI 6.1.0 would be a breaking change to PHPFUI, but still track Foundation 6.x. PHPFUI 7.0.0 would track Foundation 7.x series.
Depreciation and Foundation changes
Since major versions of Foundation have in the past depreciated and obsoleted things, PHPFUI will track the latest version of Foundation for class names and functionality. However, when Foundation makes a breaking change or removes something, PHPFUI will continue to support the old functionality as best as possible in the new Foundation framework. Depreciated classes will be put in the \PHPFUI\Vx namespace (where x would be the prior Major Foundation version containing that feature). So if something gets depreciated in a newer version of Foundation, you simply will need to change your code from \PHPFUI\Example to \PHPFUI\V6\Example. The depreciated namespace will only be supported for one Major version of PHPFUI, so it is recommended you migrate off of it in a timely manor.
Documentation
Via PHPFUI/InstaDoc
Live Examples
Via PHPFUI/Examples
Unit Testing
Full unit testing using phpfui/html-unit-tester
License
PHPFUI is distributed under the MIT License.
PHPFUI\InstaDoc Library

A quick and easy way to add documentation to your PHP project
We all document our code with PHP DocBlocks but we never seem to actually generate the documentation and add it to our project. Why? It simply takes too much time (over a minute), so we put it off till later, and later never comes.
But with PHPFUI\InstaDoc, you can document your site in about a minute (OK, maybe 2). The steps involved:
- Install PHPFUI\InstaDoc via Composer (30 seconds)
- Run installation script (30 seconds)
- Create document page (1 minute, 6 lines of code)
Two minutes to usable documentation with the following features:
PHPFUI\InstaDoc Features
- Always up to date, even with code that is not yet checked in
- Send constructor information including parameters and default values to clipboard
- Child and Parent class hierarchy clearly displayed and accessable
- Quick access to highlighted PHP source with user selectable highlighting
- Quick access to the file's git history for the local repo
- Full support for @inheritDoc tag so child method docs are displayed correctly
- Documents all projects loaded via Composer automatically
- Tabbed documentation so you are not looking at irrelevant methods
- Alphabetized everything, no more searching unalphabetized pages!
- Support for markdown and custom markdown pages
- Ability to generate static html files for high volume sites
- Add any local repo directories
- Remove any Composer project you don't care about
- 5+ line config compatible with all PHP frameworks, or standalone
- Uses Foundation CSS framework for a great experience on mobile
Install PHPFUI\InstaDoc
composer require phpfui/InstaDoc
Run Installation Script
Once installed, you need to run an installation script to copy static files to your public directory. From your project root, run the following:
php vendor/phpfui/instadoc/install.php yourPublicDirectory/subDirectory
Example: php vendor/phpfui/instadoc/install.php public/PHPFUI will add all needed files to public/PHPFUI, which will avoid any conflicts with your current files. You can specify any directory by using \PHPFUI\Page::setResourcePath, but PHPFUI is recomended to keep things simple.
Create Document Page
PHPFUI\InstaDoc does not reply on any framework and can run on a standalone page. It is recommended that you do not make your documentation public, as PHPFUI\InstaDoc will display PHP source files. How you restrict access to the page is up to you. The following does not restrict access and is simply an example:
<?php
include 'yourAutoLoader.php';
// pass the directory containing your composer.json file
$fileManager = new \PHPFUI\InstaDoc\FileManager('../');
// add your App class tree in, pass true as the last parameter if this namespace is in your local git repo.
$fileManager->addNamespace('App', '../App', true);
// load your cached files
$fileManager->load();
// load child classes if you want to display them, if you don't do this step, docs will not show classes that extend the displayed class
\PHPFUI\InstaDoc\ChildClasses::load();
// get the controller
$controller = new \PHPFUI\InstaDoc\Controller($fileManager);
// display will return a fully formed page
echo $controller->display();
That is it. You are done!
Adding New Classes
PHPFUI\InstaDoc saves the classes to display in PHP serialized files. Delete those files (.serial extension) when you want to display new classes. PHPFUI\InstaDoc will regenerate automatically if the files are missing.
Removing a Namespace
\PHPFUI\InstaDoc\NamespaceTree::deleteNameSpace('cebe\markdown\tests');
Add git Repository Page
The git repo path defaults to the composer directory, but you can change the path by calling:
$controller->setGitRoot(getcwd() . '/../');
Add Documents To Your Docs Home Page
$controller->addHomePageMarkdown('../PHPFUI/InstaDoc/README.md');
Set Your Home Page
You may want users to get back into your system easily. Clicking on the top left menu bar will take them here:
$controller->setHomeUrl('/');
Breakup Your Documentation Into Sections
If you have a lot of source code, you might want to break it into sections, so you will need a separate file to store the index in per section:
$fileManager->setBaseFile('SubProject');
Generate Static Files
Just the doc and file pages, no git!
$controller->generate('static/file/path', [\PHPFUI\InstaDoc\Controller::DOC_PAGE, \PHPFUI\InstaDoc\Controller::FILE_PAGE, ]));
Example and Full Documentation
Package Documentation
- \cebe\markdown Readme
A super fast, highly extensible markdown parser for PHP
What is this?
A set of PHP classes, each representing a Markdown flavor, and a command line tool
for converting markdown files to HTML files.The implementation focus is to be fast (see benchmark) and extensible.
Parsing Markdown to HTML is as simple as calling a single method (see Usage) providing a solid implementation
that gives most expected results even in non-trivial edge cases.Extending the Markdown language with new elements is as simple as adding a new method to the class that converts the
markdown text to the expected output in HTML. This is possible without dealing with complex and error prone regular expressions.
It is also possible to hook into the markdown structure and add elements or read meta information using the internal representation
of the Markdown text as an abstract syntax tree (see Extending the language).Currently the following markdown flavors are supported:
- Traditional Markdown according to http://daringfireball.net/projects/markdown/syntax (try it!).
- Github flavored Markdown according to https://help.github.com/articles/github-flavored-markdown (try it!).
- Markdown Extra according to http://michelf.ca/projects/php-markdown/extra/ (currently not fully supported WIP see #25, try it!)
- Any mixed Markdown flavor you like because of its highly extensible structure (See documentation below).
Future plans are to support:
- Smarty Pants http://daringfireball.net/projects/smartypants/
- ... (Feel free to suggest further additions!)
Who is using it?
- It powers the API-docs and the definitive guide for the Yii Framework 2.0.
Installation
PHP 5.4 or higher is required to use it.
It will also run on facebook's hhvm.The library uses PHPDoc annotations to determine the markdown elements that should be parsed.
So in case you are using PHPopcache
, make sure
it does not strip comments.Installation is recommended to be done via composer by running:
composer require cebe/markdown "~1.2.0"
Alternatively you can add the following to the
require
section in yourcomposer.json
manually:"cebe/markdown": "~1.2.0"
Run
composer update
afterwards.Note: If you have configured PHP with opcache you need to enable the
opcache.save_comments option because inline element parsing relies on PHPdoc annotations to find declared elements.Usage
In your PHP project
To parse your markdown you need only two lines of code. The first one is to choose the markdown flavor as
one of the following:- Traditional Markdown:
$parser = new \cebe\markdown\Markdown();
- Github Flavored Markdown:
$parser = new \cebe\markdown\GithubMarkdown();
- Markdown Extra:
$parser = new \cebe\markdown\MarkdownExtra();
The next step is to call the
parse()
-method for parsing the text using the full markdown language
or calling theparseParagraph()
-method to parse only inline elements.Here are some examples:
// traditional markdown and parse full text $parser = new \cebe\markdown\Markdown(); echo $parser->parse($markdown); // use github markdown $parser = new \cebe\markdown\GithubMarkdown(); echo $parser->parse($markdown); // use markdown extra $parser = new \cebe\markdown\MarkdownExtra(); echo $parser->parse($markdown); // parse only inline elements (useful for one-line descriptions) $parser = new \cebe\markdown\GithubMarkdown(); echo $parser->parseParagraph($markdown);
You may optionally set one of the following options on the parser object:
For all Markdown Flavors:
$parser->html5 = true
to enable HTML5 output instead of HTML4.$parser->keepListStartNumber = true
to enable keeping the numbers of ordered lists as specified in the markdown.
The default behavior is to always start from 1 and increment by one regardless of the number in markdown.
For GithubMarkdown:
$parser->enableNewlines = true
to convert all newlines to<br/>
-tags. By default only newlines with two preceding spaces are converted to<br/>
-tags.
It is recommended to use UTF-8 encoding for the input strings. Other encodings may work, but are currently untested.
The command line script
You can use it to render this readme:
bin/markdown README.md > README.html
Using github flavored markdown:
bin/markdown --flavor=gfm README.md > README.html
or convert the original markdown description to html using the unix pipe:
curl http://daringfireball.net/projects/markdown/syntax.text | bin/markdown > md.html
Here is the full Help output you will see when running
bin/markdown --help
:PHP Markdown to HTML converter ------------------------------ by Carsten Brandt <mail@cebe.cc> Usage: bin/markdown [--flavor=<flavor>] [--full] [file.md] --flavor specifies the markdown flavor to use. If omitted the original markdown by John Gruber [1] will be used. Available flavors: gfm - Github flavored markdown [2] extra - Markdown Extra [3] --full ouput a full HTML page with head and body. If not given, only the parsed markdown will be output. --help shows this usage information. If no file is specified input will be read from STDIN. Examples: Render a file with original markdown: bin/markdown README.md > README.html Render a file using gihtub flavored markdown: bin/markdown --flavor=gfm README.md > README.html Convert the original markdown description to html using STDIN: curl http://daringfireball.net/projects/markdown/syntax.text | bin/markdown > md.html [1] http://daringfireball.net/projects/markdown/syntax [2] https://help.github.com/articles/github-flavored-markdown [3] http://michelf.ca/projects/php-markdown/extra/
Extensions
Here are some extensions to this library:
- Bogardo/markdown-codepen - shortcode to embed codepens from http://codepen.io/ in markdown.
- kartik-v/yii2-markdown - Advanced Markdown editing and conversion utilities for Yii Framework 2.0.
- cebe/markdown-latex - Convert Markdown to LaTeX and PDF
- softark/creole - A creole markup parser
- hyn/frontmatter - Frontmatter Metadata Support (JSON, TOML, YAML)
- ... add yours!
Extending the language
Markdown consists of two types of language elements, I'll call them block and inline elements simlar to what you have in
HTML with<div>
and<span>
. Block elements are normally spreads over several lines and are separated by blank lines.
The most basic block element is a paragraph (<p>
).
Inline elements are elements that are added inside of block elements i.e. inside of text.This markdown parser allows you to extend the markdown language by changing existing elements behavior and also adding
new block and inline elements. You do this by extending from the parser class and adding/overriding class methods and
properties. For the different element types there are different ways to extend them as you will see in the following sections.Adding block elements
The markdown is parsed line by line to identify each non-empty line as one of the block element types.
To identify a line as the beginning of a block element it calls all protected class methods who's name begins withidentify
.
An identify function returns true if it has identified the block element it is responsible for or false if not.
In the following example we will implement support for fenced code blocks which are part of the github flavored markdown.<?php class MyMarkdown extends \cebe\markdown\Markdown { protected function identifyFencedCode($line, $lines, $current) { // if a line starts with at least 3 backticks it is identified as a fenced code block if (strncmp($line, '```', 3) === 0) { return true; } return false; } // ... }
In the above,
$line
is a string containing the content of the current line and is equal to$lines[$current]
.
You may use$lines
and$current
to check other lines than the current line. In most cases you can ignore these parameters.Parsing of a block element is done in two steps:
Consuming all the lines belonging to it. In most cases this is iterating over the lines starting from the identified
line until a blank line occurs. This step is implemented by a method namedconsume{blockName}()
where{blockName}
is the same name as used for the identify function above. The consume method also takes the lines array
and the number of the current line. It will return two arguments: an array representing the block element in the abstract syntax tree
of the markdown document and the line number to parse next. In the abstract syntax array the first element refers to the name of
the element, all other array elements can be freely defined by yourself.
In our example we will implement it like this:protected function consumeFencedCode($lines, $current) { // create block array $block = [ 'fencedCode', 'content' => [], ]; $line = rtrim($lines[$current]); // detect language and fence length (can be more than 3 backticks) $fence = substr($line, 0, $pos = strrpos($line, '`') + 1); $language = substr($line, $pos); if (!empty($language)) { $block['language'] = $language; } // consume all lines until ``` for($i = $current + 1, $count = count($lines); $i < $count; $i++) { if (rtrim($line = $lines[$i]) !== $fence) { $block['content'][] = $line; } else { // stop consuming when code block is over break; } } return [$block, $i]; }
Rendering the element. After all blocks have been consumed, they are being rendered using the
render{elementName}()
-method whereelementName
refers to the name of the element in the abstract syntax tree:protected function renderFencedCode($block) { $class = isset($block['language']) ? ' class="language-' . $block['language'] . '"' : ''; return "<pre><code$class>" . htmlspecialchars(implode("\n", $block['content']) . "\n", ENT_NOQUOTES, 'UTF-8') . '</code></pre>'; }
You may also add code highlighting here. In general it would also be possible to render ouput in a different language than
HTML for example LaTeX.
Adding inline elements
Adding inline elements is different from block elements as they are parsed using markers in the text.
An inline element is identified by a marker that marks the beginning of an inline element (e.g.[
will mark a possible
beginning of a link or`
will mark inline code).Parsing methods for inline elements are also protected and identified by the prefix
parse
. Additionally a@marker
annotation
in PHPDoc is needed to register the parse function for one or multiple markers.
The method will then be called when a marker is found in the text. As an argument it takes the text starting at the position of the marker.
The parser method will return an array containing the element of the abstract sytnax tree and an offset of text it has
parsed from the input markdown. All text up to this offset will be removed from the markdown before the next marker will be searched.As an example, we will add support for the strikethrough feature of github flavored markdown:
<?php class MyMarkdown extends \cebe\markdown\Markdown { /** * @marker ~~ */ protected function parseStrike($markdown) { // check whether the marker really represents a strikethrough (i.e. there is a closing ~~) if (preg_match('/^~~(.+?)~~/', $markdown, $matches)) { return [ // return the parsed tag as an element of the abstract syntax tree and call `parseInline()` to allow // other inline markdown elements inside this tag ['strike', $this->parseInline($matches[1])], // return the offset of the parsed text strlen($matches[0]) ]; } // in case we did not find a closing ~~ we just return the marker and skip 2 characters return [['text', '~~'], 2]; } // rendering is the same as for block elements, we turn the abstract syntax array into a string. protected function renderStrike($element) { return '<del>' . $this->renderAbsy($element[1]) . '</del>'; } }
Composing your own Markdown flavor
This markdown library is composed of traits so it is very easy to create your own markdown flavor by adding and/or removing
the single feature traits.Designing your Markdown flavor consists of four steps:
- Select a base class
- Select language feature traits
- Define escapeable characters
- Optionally add custom rendering behavior
Select a base class
If you want to extend from a flavor and only add features you can use one of the existing classes
(Markdown
,GithubMarkdown
orMarkdownExtra
) as your flavors base class.If you want to define a subset of the markdown language, i.e. remove some of the features, you have to
extend your class fromParser
.Select language feature traits
The following shows the trait selection for traditional Markdown.
class MyMarkdown extends Parser { // include block element parsing using traits use block\CodeTrait; use block\HeadlineTrait; use block\HtmlTrait { parseInlineHtml as private; } use block\ListTrait { // Check Ul List before headline identifyUl as protected identifyBUl; consumeUl as protected consumeBUl; } use block\QuoteTrait; use block\RuleTrait { // Check Hr before checking lists identifyHr as protected identifyAHr; consumeHr as protected consumeAHr; } // include inline element parsing using traits use inline\CodeTrait; use inline\EmphStrongTrait; use inline\LinkTrait; /** * @var boolean whether to format markup according to HTML5 spec. * Defaults to `false` which means that markup is formatted as HTML4. */ public $html5 = false; protected function prepare() { // reset references $this->references = []; } // ... }
In general, just adding the trait with
use
is enough, however in some cases some fine tuning is desired
to get most expected parsing results. Elements are detected in alphabetical order of their identification
function. This means that if a line starting with-
could be a list or a horizontal rule, the preference has to be set
by renaming the identification function. This is what is done with renamingidentifyHr
toidentifyAHr
andidentifyBUl
toidentifyBUl
. The consume function always has to have the same name as the identification function
so this has to be renamed too.There is also a conflict for parsing of the
<
character. This could either be a link/email enclosed in<
and>
or an inline HTML tag. In order to resolve this conflict when adding theLinkTrait
, we need to hide theparseInlineHtml
method of theHtmlTrait
.If you use any trait that uses the
$html5
property to adjust its output you also need to define this property.If you use the link trait it may be useful to implement
prepare()
as shown above to reset references before
parsing to ensure you get a reusable object.Define escapeable characters
Depending on the language features you have chosen there is a different set of characters that can be escaped
using\
. The following is the set of escapeable characters for traditional markdown, you can copy it to your class
as is./** * @var array these are "escapeable" characters. When using one of these prefixed with a * backslash, the character will be outputted without the backslash and is not interpreted * as markdown. */ protected $escapeCharacters = [ '\\', // backslash '`', // backtick '*', // asterisk '_', // underscore '{', '}', // curly braces '[', ']', // square brackets '(', ')', // parentheses '#', // hash mark '+', // plus sign '-', // minus sign (hyphen) '.', // dot '!', // exclamation mark '<', '>', ];
Add custom rendering behavior
Optionally you may also want to adjust rendering behavior by overriding some methods.
You may refer to theconsumeParagraph()
method of theMarkdown
andGithubMarkdown
classes for some inspiration
which define different rules for which elements are allowed to interrupt a paragraph.Acknowledgements
I'd like to thank @erusev for creating Parsedown which heavily influenced this work and provided
the idea of the line based parsing approach.FAQ
Why another markdown parser?
While reviewing PHP markdown parsers for choosing one to use bundled with the Yii framework 2.0
I found that most of the implementations use regex to replace patterns instead
of doing real parsing. This way extending them with new language elements is quite hard
as you have to come up with a complex regex, that matches your addition but does not mess
with other elements. Such additions are very common as you see on github which supports referencing
issues, users and commits in the comments.
A real parser should use context aware methods that walk trough the text and
parse the tokens as they find them. The only implentation that I have found that uses
this approach is Parsedown which also shows that this implementation is much faster
than the regex way. Parsedown however is an implementation that focuses on speed and implements
its own flavor (mainly github flavored markdown) in one class and at the time of this writing was
not easily extensible.Given the situation above I decided to start my own implementation using the parsing approach
from Parsedown and making it extensible creating a class for each markdown flavor that extend each
other in the way that also the markdown languages extend each other.
This allows you to choose between markdown language flavors and also provides a way to compose your
own flavor picking the best things from all.
I chose this approach as it is easier to implement and also more intuitive approach compared
to using callbacks to inject functionallity into the parser.Where do I report bugs or rendering issues?
Just open an issue on github, post your markdown code and describe the problem. You may also attach screenshots of the rendered HTML result to describe your problem.
How can I contribute to this library?
Check the CONTRIBUTING.md file for more info.
Am I free to use this?
This library is open source and licensed under the MIT License. This means that you can do whatever you want
with it as long as you mention my name and include the license file. Check the license for details.Contact
- \DeepCopy Readme
DeepCopy
DeepCopy helps you create deep copies (clones) of your objects. It is designed to handle cycles in the association graph.
Table of Contents
How?
Install with Composer:
composer require myclabs/deep-copy
Use simply:
use DeepCopy\DeepCopy; $copier = new DeepCopy(); $myCopy = $copier->copy($myObject);
Why?
- How do you create copies of your objects?
$myCopy = clone $myObject;
- How do you create deep copies of your objects (i.e. copying also all the objects referenced in the properties)?
You use
__clone()
and implement the behavior
yourself.- But how do you handle cycles in the association graph?
Now you're in for a big mess :(
Using simply
clone
Overridding
__clone()
With
DeepCopy
How it works
DeepCopy recursively traverses all the object's properties and clones them. To avoid cloning the same object twice it
keeps a hash map of all instances and thus preserves the object graph.To use it:
use function DeepCopy\deep_copy; $copy = deep_copy($var);
Alternatively, you can create your own
DeepCopy
instance to configure it differently for example:use DeepCopy\DeepCopy; $copier = new DeepCopy(true); $copy = $copier->copy($var);
You may want to roll your own deep copy function:
namespace Acme; use DeepCopy\DeepCopy; function deep_copy($var) { static $copier = null; if (null === $copier) { $copier = new DeepCopy(true); } return $copier->copy($var); }
Going further
You can add filters to customize the copy process.
The method to add a filter is
DeepCopy\DeepCopy::addFilter($filter, $matcher)
,
with$filter
implementingDeepCopy\Filter\Filter
and$matcher
implementingDeepCopy\Matcher\Matcher
.We provide some generic filters and matchers.
Matchers
DeepCopy\Matcher
applies on a object attribute.DeepCopy\TypeMatcher
applies on any element found in graph, including array elements.
Property name
The
PropertyNameMatcher
will match a property by its name:use DeepCopy\Matcher\PropertyNameMatcher; // Will apply a filter to any property of any objects named "id" $matcher = new PropertyNameMatcher('id');
Specific property
The
PropertyMatcher
will match a specific property of a specific class:use DeepCopy\Matcher\PropertyMatcher; // Will apply a filter to the property "id" of any objects of the class "MyClass" $matcher = new PropertyMatcher('MyClass', 'id');
Type
The
TypeMatcher
will match any element by its type (instance of a class or any value that could be parameter of
gettype() function):use DeepCopy\TypeMatcher\TypeMatcher; // Will apply a filter to any object that is an instance of Doctrine\Common\Collections\Collection $matcher = new TypeMatcher('Doctrine\Common\Collections\Collection');
Filters
DeepCopy\Filter
applies a transformation to the object attribute matched byDeepCopy\Matcher
DeepCopy\TypeFilter
applies a transformation to any element matched byDeepCopy\TypeMatcher
SetNullFilter
(filter)Let's say for example that you are copying a database record (or a Doctrine entity), so you want the copy not to have
any ID:use DeepCopy\DeepCopy; use DeepCopy\Filter\SetNullFilter; use DeepCopy\Matcher\PropertyNameMatcher; $object = MyClass::load(123); echo $object->id; // 123 $copier = new DeepCopy(); $copier->addFilter(new SetNullFilter(), new PropertyNameMatcher('id')); $copy = $copier->copy($object); echo $copy->id; // null
KeepFilter
(filter)If you want a property to remain untouched (for example, an association to an object):
use DeepCopy\DeepCopy; use DeepCopy\Filter\KeepFilter; use DeepCopy\Matcher\PropertyMatcher; $copier = new DeepCopy(); $copier->addFilter(new KeepFilter(), new PropertyMatcher('MyClass', 'category')); $copy = $copier->copy($object); // $copy->category has not been touched
DoctrineCollectionFilter
(filter)If you use Doctrine and want to copy an entity, you will need to use the
DoctrineCollectionFilter
:use DeepCopy\DeepCopy; use DeepCopy\Filter\Doctrine\DoctrineCollectionFilter; use DeepCopy\Matcher\PropertyTypeMatcher; $copier = new DeepCopy(); $copier->addFilter(new DoctrineCollectionFilter(), new PropertyTypeMatcher('Doctrine\Common\Collections\Collection')); $copy = $copier->copy($object);
DoctrineEmptyCollectionFilter
(filter)If you use Doctrine and want to copy an entity who contains a
Collection
that you want to be reset, you can use the
DoctrineEmptyCollectionFilter
use DeepCopy\DeepCopy; use DeepCopy\Filter\Doctrine\DoctrineEmptyCollectionFilter; use DeepCopy\Matcher\PropertyMatcher; $copier = new DeepCopy(); $copier->addFilter(new DoctrineEmptyCollectionFilter(), new PropertyMatcher('MyClass', 'myProperty')); $copy = $copier->copy($object); // $copy->myProperty will return an empty collection
DoctrineProxyFilter
(filter)If you use Doctrine and use cloning on lazy loaded entities, you might encounter errors mentioning missing fields on a
Doctrine proxy class (...\__CG__\Proxy).
You can use theDoctrineProxyFilter
to load the actual entity behind the Doctrine proxy class.
Make sure, though, to put this as one of your very first filters in the filter chain so that the entity is loaded
before other filters are applied!use DeepCopy\DeepCopy; use DeepCopy\Filter\Doctrine\DoctrineProxyFilter; use DeepCopy\Matcher\Doctrine\DoctrineProxyMatcher; $copier = new DeepCopy(); $copier->addFilter(new DoctrineProxyFilter(), new DoctrineProxyMatcher()); $copy = $copier->copy($object); // $copy should now contain a clone of all entities, including those that were not yet fully loaded.
ReplaceFilter
(type filter)- If you want to replace the value of a property:
use DeepCopy\DeepCopy; use DeepCopy\Filter\ReplaceFilter; use DeepCopy\Matcher\PropertyMatcher; $copier = new DeepCopy(); $callback = function ($currentValue) { return $currentValue . ' (copy)' }; $copier->addFilter(new ReplaceFilter($callback), new PropertyMatcher('MyClass', 'title')); $copy = $copier->copy($object); // $copy->title will contain the data returned by the callback, e.g. 'The title (copy)'
- If you want to replace whole element:
use DeepCopy\DeepCopy; use DeepCopy\TypeFilter\ReplaceFilter; use DeepCopy\TypeMatcher\TypeMatcher; $copier = new DeepCopy(); $callback = function (MyClass $myClass) { return get_class($myClass); }; $copier->addTypeFilter(new ReplaceFilter($callback), new TypeMatcher('MyClass')); $copy = $copier->copy([new MyClass, 'some string', new MyClass]); // $copy will contain ['MyClass', 'some string', 'MyClass']
The
$callback
parameter of theReplaceFilter
constructor accepts any PHP callable.ShallowCopyFilter
(type filter)Stop DeepCopy from recursively copying element, using standard
clone
instead:use DeepCopy\DeepCopy; use DeepCopy\TypeFilter\ShallowCopyFilter; use DeepCopy\TypeMatcher\TypeMatcher; use Mockery as m; $this->deepCopy = new DeepCopy(); $this->deepCopy->addTypeFilter( new ShallowCopyFilter, new TypeMatcher(m\MockInterface::class) ); $myServiceWithMocks = new MyService(m::mock(MyDependency1::class), m::mock(MyDependency2::class)); // All mocks will be just cloned, not deep copied
Edge cases
The following structures cannot be deep-copied with PHP Reflection. As a result they are shallow cloned and filters are
not applied. There is two ways for you to handle them:- Implement your own
__clone()
method - Use a filter with a type matcher
Contributing
DeepCopy is distributed under the MIT license.
Tests
Running the tests is simple:
vendor/bin/phpunit
Support
Get professional support via the Tidelift Subscription.
- \Highlight Readme
highlight.php
highlight.php is a server-side syntax highlighter written in PHP that currently supports 185 languages. It's a port of highlight.js by Ivan Sagalaev that makes full use of the language and style definitions of the original JavaScript project.
Table of Contents
Installation + Setup
The recommended approach is to install the project through Composer.
composer require scrivo/highlight.php
If you're not using Composer, ensure that the classes defined in the
Highlight
namespace can be found either by inclusion or by an autoloader. A trivial autoloader for this purpose is included in this project asHighlight\Autoloader.php
Composer Version Constraints
When requiring this project in your
composer.json
, it is recommended you use the caret version range and use only the major and minor values; i.e.^9.14
.It's come to our attention that a lot of tutorials and projects out there are locking themselves into highly specific versions of this project; e.g.
"scrivo/highlight.php": "v9.12.0.1"
. Please do not do this or encourage it. We promise a reliable backward compatibility policy so there's no reason to lock yourself to such a specific version. By doing this, you are preventing yourself or your users from receiving updates to language definitions and bug fixes.Usage
The
\Highlight\Highlighter
class contains the syntax highlighting functionality. You can choose between two highlighting modes:- explicit mode
- automatic language detection mode
Explicit Mode
In explicit mode, you must define which language you will be highlighting as.
// Instantiate the Highlighter. $hl = new \Highlight\Highlighter(); $code = file_get_contents('some_ruby_script.rb'); try { // Highlight some code. $highlighted = $hl->highlight('ruby', $code); echo "<pre><code class=\"hljs {$highlighted->language}\">"; echo $highlighted->value; echo "</code></pre>"; } catch (DomainException $e) { // This is thrown if the specified language does not exist echo "<pre><code>"; echo htmlentities($code); echo "</code></pre>"; }
Automatic Language Detection Mode
Alternatively you can use the automatic detection mode, which highlights your code with the language the library thinks is best. It is highly recommended you explicitly choose the language or limit the number of languages to automatically detect to reduce the number of inaccuracies.
Warning: Auto-detection occurs in a brute force fashion and the language with the most accurate result will be selected. This is extremely inefficient as you supply more languages and may not always be 100% accurate if similar languages are configured.
$hl = new \Highlight\Highlighter(); $hl->setAutodetectLanguages(array('ruby', 'python', 'perl')); $highlighted = $hl->highlightAuto(file_get_contents('some_ruby_script.rb')); echo "<pre><code class=\"hljs {$highlighted->language}\">"; echo $highlighted->value; echo "</code></pre>";
Default Languages
In version 9.x of this project, the following languages are the default auto-detected languages:
- XML
- JSON
- JavaScript
- CSS
- PHP
- HTTP
These default languages are considered "legacy behavior" and will be removed in version 10.x of this library to match highlight.js behavior; the new default behavior in 10.x will be to use every language.
Stylesheets
The same stylesheets available in the highlight.js project are available in the
styles
directory of this project and may be included in your own CSS or made accessible to your web server.Highlighter Utilities
The core of the project is loyal port of highlight.js and is available under the main
Highlight
namespace. A series of convenience functions are provided under theHighlightUtilities
namespace to introduce additional functionality without the need for another dependency.Available functions:
getAvailableStyleSheets(bool $filePaths = false): string[]
getLanguagesFolder(): string
getLanguageDefinitionPath(string $name): string
getStyleSheet(string $name): false|string
getStyleSheetFolder(): string
getStyleSheetPath(string $name): string
getThemeBackgroundColor(string $name): float[]
splitCodeIntoArray(string $html): false|string[]
Versioning
This project will follow the same version numbers as the highlight.js project with regards to languages, meaning that a language definition available in highlight.js 9.12.0 will be available in highlight.php 9.12.0. However, there are times where bugs may arise in this project or its translated definition files, so there'll be one more number appended to the version number. For example, version 9.12.0.1 will contain all of the same languages as highlight.js 9.12.0 but also contain fixes solely to this project. This is done so this project can have version bumps without conflicts should highlight.js release version 9.12.1.
Backward Compatibility Promise
Despite the fact that the semantic versioning used in this project mirrors that of highlight.js, this project will adhere to Symfony's Backward Compatibility Promise. You can rest assured that there will be no breaking changes during
9.x
and any deprecations will be marked with@deprecated
and won't be removed until the next major release.Some History
Geert Bergman
Sep 30, 2013JavaScript code highlighting is very convenient and in many cases just what you want to use. Especially for programming blogs I would not advice you to use otherwise. But there are occasions where you're better off with a more 'static' approach, for instance if you want to send highlighted code in an email or for API documents. For this I needed a code highlighting program preferably written in PHP.
I couldn't found any satisfactory PHP solution so I decided to port one from JavaScript. After some comparison of different highlighting programs based on license, technology, language support highlight.js came out most favorable in my opinion.
It was my decision not to make a PHP highlighter but to do a port of highlight.js, these are different things. The goal was to make it work exactly as highlight.js to make as much use as possible of the language definitions and CSS files of the original program.
Happy coding!
License
- \NXP Readme
MathExecutor
A simple and extensible math expressions calculator
Features:
- Built in support for +, -, *, / and power (^) operators plus ()
- Logical operators (==, !=, <, <, >=, <=, &&, ||)
- Built in support for most PHP math functions
- Conditional If logic
- Support for user defined operators
- Support for user defined functions
- Dynamic variable resolution (delayed computation)
- Unlimited variable name lengths
- String support, as function parameters or as evaluated as a number by PHP
- Exceptions on divide by zero, or treat as zero
- Unary Minus (e.g. -3)
- Pi ($pi) and Euler's number ($e) support to 11 decimal places
- Easily extensible
Install via Composer:
composer require nxp/math-executor
Sample usage:
use NXP\MathExecutor; $executor = new MathExecutor(); echo $executor->execute('1 + 2 * (2 - (4+10))^2 + sin(10)');
Functions:
Default functions:
- abs
- acos
- acosh
- asin
- atan (atn)
- atan2
- atanh
- avg
- bindec
- ceil
- cos
- cosh
- decbin
- dechex
- decoct
- deg2rad
- exp
- expm1
- floor
- fmod
- hexdec
- hypot
- if
- intdiv
- log
- log10
- log1p
- max
- min
- octdec
- pi
- pow
- rad2deg
- round
- sin
- sinh
- sqrt
- tan (tn)
- tanh
Add custom function to executor:
$executor->addFunction('abs', function($arg) {return abs($arg);});
Function default parameters are not supported at this time.
Operators:
Default operators:
+ - * / ^
Add custom operator to executor:
use NXP\Classes\Operator; $executor->addOperator(new Operator( '%', // Operator sign false, // Is right associated operator 170, // Operator priority function (&$stack) { $op2 = array_pop($stack); $op1 = array_pop($stack); $result = $op1->getValue() % $op2->getValue(); return $result; } ));
Logical operators:
Logical operators (==, !=, <, <, >=, <=, &&, ||) are supported, but logically they can only return true (1) or false (0). In order to leverage them, use the built in if function:
if($a > $b, $a - $b, $b - $a)
You can think of the if function as prototyped like:
function if($condition, $returnIfTrue, $returnIfFalse)
Variables:
Variables can be prefixed with the dollar sign ($) for PHP compatibility, but is not required.
Default variables:
$pi = 3.14159265359 $e = 2.71828182846
You can add your own variables to executor:
$executor->setVar('var1', 0.15)->setVar('var2', 0.22); echo $executor->execute("$var1 + var2");
You can dynamically define variables at run time. If a variable has a high computation cost, but might not be used, then you can define an undefined variable handler. It will only get called when the variable is used, rather than having to always set it initially.
$calculator = new MathExecutor(); $calculator->setVarNotFoundHandler( function ($varName) { if ($varName == 'trans') { return transmogrify(); } return null; } );
Division By Zero Support:
Division by zero throws a
\NXP\Exception\DivisionByZeroException
by defaulttry { echo $executor->execute('1/0'); } catch (DivisionByZeroException $e) { echo $e->getMessage(); }
Or call setDivisionByZeroIsZero
echo $executor->setDivisionByZeroIsZero()->execute('1/0');
If you want another behavior, you can override division operator:
$executor->addOperator("/", false, 180, function($a, $b) { if ($b == 0) { return null; } return $a / $b; }); echo $executor->execute('1/0');
Unary Minus Operator:
Negative numbers are supported via the unary minus operator. Positive numbers are not explicitly supported as unsigned numbers are assumed positive.
String Support:
Expressions can contain double or single quoted strings that are evaluated the same way as PHP evalutes strings as numbers. You can also pass strings to functions.
echo $executor->execute("1 + '2.5' * '.5' + myFunction('category')");
Extending MathExecutor
You can add operators, functions and variables with the public methods in MathExecutor, but if you need to do more serious modifications to base behaviours, the easiest way to extend MathExecutor is to redefine the following methods in your derived class:
- defaultOperators
- defaultFunctions
- defaultVars
This will allow you to remove functions and operators if needed, or implement different types more simply.
Also note that you can replace an existing default operator by adding a new operator with the same regular expression string. For example if you just need to redefine TokenPlus, you can just add a new operator with the same regex string, in this case '\+'.
Documentation
Full class documentation via PHPFUI/InstaDoc
Future Enhancements
This package will continue to track currently supported versions of PHP. PHP 7.1 and earlier support will be dropped when PHP 8 is released.
- \PHPFUI Readme
PHPFUI
PHP Wrapper for the Foundation CSS Framework
PHPFUI, PHP Foundation User Interface, is a 7.1 PHP library that produces HTML formated for Foundation. It does everything you need for a fully functional Foundation page, with the power of an OO language. It currently uses Foundation 6.6 and PHP 7.1 or higher.
"I was surprised that people were prepared to write HTML. In my initial requirements for this thing, I had assumed, as an absolute pre-condition, that nobody would have to do HTML or deal with URLs. If you use the original World Wide Web program, you never see a URL or have to deal with HTML. You're presented with the raw information. You then input more information. So you are linking information to information--like using a word processor. That was a surprise to me--that people were prepared to painstakingly write HTML."
Sir Tim Berners-Lee, inventor of the World Wide Web
Using PHPFUI for view output will produce 100% valid HTML and insulate you from future changes to Foundation, your custom HMTL layouts, CSS and JS library changes. You write to an abstract concept (I want a checkbox here), and the library will output a checkbox formatted for Foundation. You can inherit from CheckBox and add your own take on a checkbox, and when the graphic designer decides they have the most awesome checkbox ever, you simply change your CheckBox class, and it is changed on every page system wide.
Don't write HTML by hand!
Usage
namespace PHPFUI; $page = new Page(); $form = new Form($page); $fieldset = new FieldSet('A basic input form'); $time = new Input\Time($page, 'time', 'Enter A Time in 15 minute increments'); $time->setRequired(); $date = new Input\Date($page, 'date', 'Pick A Date'); $fieldset->add(new MultiColumn($time, $date)); $fieldset->add(new Input\TextArea('text', 'Enter some text')); $fieldset->add(new Submit()); $form->add($fieldset); $page->add($form); $page->addStyleSheet('/css/styles.css'); echo $page;
Installation Instructions
composer require phpfui/phpfui
Then run update.php from the vendor/phpfui/phpfui directory and supply the path to your public directory / the directory for the various JS and CSS files PHPFUI uses. This will copy all required public files into your public directory. For example:
php vendor/phpfui/phpfui/update.php public/PHPFUI
The PHPFUI library defaults to your-public-directory/PHPFUI, it can be overridden, but it is suggested to use PHPFUI to keep everything in one place. update.php should be run when ever you update PHPFUI.
Versioning
Versioning will match the Foundation versions for Major semantic versions. PHPUI will always support the most recent version of Foundation possible for the Major version. PHPFUI Minor version will include breaking changes and may incorporate changes for the latest version of Foundation. The PHPFUI Patch version will include non breaking changes or additions. So PHPFUI Version 6.0.0 would be the first version of the library, 6.0.1 would be the first patch of PHPFUI. Both should work with any Foundation 6.x version. PHPFUI 6.1.0 would be a breaking change to PHPFUI, but still track Foundation 6.x. PHPFUI 7.0.0 would track Foundation 7.x series.
Depreciation and Foundation changes
Since major versions of Foundation have in the past depreciated and obsoleted things, PHPFUI will track the latest version of Foundation for class names and functionality. However, when Foundation makes a breaking change or removes something, PHPFUI will continue to support the old functionality as best as possible in the new Foundation framework. Depreciated classes will be put in the \PHPFUI\Vx namespace (where x would be the prior Major Foundation version containing that feature). So if something gets depreciated in a newer version of Foundation, you simply will need to change your code from \PHPFUI\Example to \PHPFUI\V6\Example. The depreciated namespace will only be supported for one Major version of PHPFUI, so it is recommended you migrate off of it in a timely manor.
Documentation
Via PHPFUI/InstaDoc
Live Examples
Via PHPFUI/Examples
Unit Testing
Full unit testing using phpfui/html-unit-tester
License
PHPFUI is distributed under the MIT License.
- \PHPFUI\HTMLUnitTester Readme
PHPFUI\HTMLUnitTester
PHPUnit Testing extensions for HMTL and CSS. PHPFUI\HTMLUnitTester allows you to unit test HTML and CSS for errors and warnings. Often simple errors in HTML or CSS create hard to debug issues where a simple check will reveal bad code.
This package will check detect errors and warnings in HTML and CSS in stand alone strings, files, entire directories or urls.
Requirements
- PHP 7.1 or higher
- PHPUnit 7 or higher
For the best performanance, a local install of https://github.com/validator/validator is recommended.
Installation
composer require phpfui/html-unit-tester
Configuration
It is recommended you run https://github.com/validator/validator locally. Install Java and download the .jar file. Run with the following command:
java -Xss1024k -cp vnu.jar nu.validator.servlet.Main 8888
If you are not using a local server, you will need to add the following lines to your phpunit.xml config in the phpunit element:
<php> <env name="PHPFUI\HTMLUnitTester\Extensions_url" value="http://validator.w3.org/nu"/> <env name="PHPFUI\HTMLUnitTester\Extensions_delay" value="500000"/> </php>
Usage
Extend your unit tests from \PHPFUI\HTMLUnitTester\Extensions
class UnitTest extends \PHPFUI\HTMLUnitTester\Extensions { public function testValidHtml() { $this->assertValidHtml('<h1>Header</h1>'); $this->assertValidHtmlPage('<!DOCTYPE html><html><head><meta charset="utf-8"/><title>Title</title></head><body><div>This is a test</div></body></html>'); } }
You can use any of the following asserts:
- assertNotWarningCss
- assertNotWarningCssFile
- assertNotWarningCssUrl
- assertNotWarningFile
- assertNotWarningHtml
- assertNotWarningHtmlPage
- assertNotWarningUrl
- assertValidCss
- assertValidCssFile
- assertValidCssUrl
- assertValidFile
- assertValidHtml
- assertValidHtmlPage
- assertValidUrl
Directory Testing
Instead of file by file testing, use assertDirectory to test an entire directory. Any files added to the directory will be automatically tested.
$this->assertDirectory('ValidCSS', 'cssDirectory', 'Invalid CSS'); $this->assertDirectory('NotWarningCSS', 'cssDirectory', 'CSS has warnings');
The error message will include the offending file name.
Examples
See examples
Documentation
Full documentation at PHPFUI\HTMLUnitTester
- \PHPFUI\InstaDoc Readme
PHPFUI\InstaDoc Library
A quick and easy way to add documentation to your PHP project
We all document our code with PHP DocBlocks but we never seem to actually generate the documentation and add it to our project. Why? It simply takes too much time (over a minute), so we put it off till later, and later never comes.
But with PHPFUI\InstaDoc, you can document your site in about a minute (OK, maybe 2). The steps involved:
- Install PHPFUI\InstaDoc via Composer (30 seconds)
- Run installation script (30 seconds)
- Create document page (1 minute, 6 lines of code)
Two minutes to usable documentation with the following features:
PHPFUI\InstaDoc Features
- Always up to date, even with code that is not yet checked in
- Send constructor information including parameters and default values to clipboard
- Child and Parent class hierarchy clearly displayed and accessable
- Quick access to highlighted PHP source with user selectable highlighting
- Quick access to the file's git history for the local repo
- Full support for @inheritDoc tag so child method docs are displayed correctly
- Documents all projects loaded via Composer automatically
- Tabbed documentation so you are not looking at irrelevant methods
- Alphabetized everything, no more searching unalphabetized pages!
- Support for markdown and custom markdown pages
- Ability to generate static html files for high volume sites
- Add any local repo directories
- Remove any Composer project you don't care about
- 5+ line config compatible with all PHP frameworks, or standalone
- Uses Foundation CSS framework for a great experience on mobile
Install PHPFUI\InstaDoc
composer require phpfui/InstaDoc
Run Installation Script
Once installed, you need to run an installation script to copy static files to your public directory. From your project root, run the following:
php vendor/phpfui/instadoc/install.php yourPublicDirectory/subDirectory
Example: php vendor/phpfui/instadoc/install.php public/PHPFUI will add all needed files to public/PHPFUI, which will avoid any conflicts with your current files. You can specify any directory by using \PHPFUI\Page::setResourcePath, but PHPFUI is recomended to keep things simple.
Create Document Page
PHPFUI\InstaDoc does not reply on any framework and can run on a standalone page. It is recommended that you do not make your documentation public, as PHPFUI\InstaDoc will display PHP source files. How you restrict access to the page is up to you. The following does not restrict access and is simply an example:
<?php include 'yourAutoLoader.php'; // pass the directory containing your composer.json file $fileManager = new \PHPFUI\InstaDoc\FileManager('../'); // add your App class tree in, pass true as the last parameter if this namespace is in your local git repo. $fileManager->addNamespace('App', '../App', true); // load your cached files $fileManager->load(); // load child classes if you want to display them, if you don't do this step, docs will not show classes that extend the displayed class \PHPFUI\InstaDoc\ChildClasses::load(); // get the controller $controller = new \PHPFUI\InstaDoc\Controller($fileManager); // display will return a fully formed page echo $controller->display();
That is it. You are done!
Adding New Classes
PHPFUI\InstaDoc saves the classes to display in PHP serialized files. Delete those files (.serial extension) when you want to display new classes. PHPFUI\InstaDoc will regenerate automatically if the files are missing.
Removing a Namespace
\PHPFUI\InstaDoc\NamespaceTree::deleteNameSpace('cebe\markdown\tests');
Add git Repository Page
The git repo path defaults to the composer directory, but you can change the path by calling:
$controller->setGitRoot(getcwd() . '/../');
Add Documents To Your Docs Home Page
$controller->addHomePageMarkdown('../PHPFUI/InstaDoc/README.md');
Set Your Home Page
You may want users to get back into your system easily. Clicking on the top left menu bar will take them here:
$controller->setHomeUrl('/');
Breakup Your Documentation Into Sections
If you have a lot of source code, you might want to break it into sections, so you will need a separate file to store the index in per section:
$fileManager->setBaseFile('SubProject');
Generate Static Files
Just the doc and file pages, no git!
$controller->generate('static/file/path', [\PHPFUI\InstaDoc\Controller::DOC_PAGE, \PHPFUI\InstaDoc\Controller::FILE_PAGE, ]));
Example and Full Documentation
- \PHPFUI\MySQLSlowQuery Readme
PHPFUI\MySQLSlowLog\Parser
PHP Parser for MySQL Slow Query Logs featuring sortable results
Requirements
- PHP 7.1 or higher
- MySQL 5.7 or higher
Usage
$parser = new \PHPFUI\MySQLSlowQuery\Parser($logFilePath); // Return the sessions in the file as array $sessions = $parser->getSessions(); // Return all entries in file as array, or pass session number (0 based) $entries = $parser->getEntries(); if (count($entries)) { // Get the worst offender $entry = $parser->sortEntries()->getEntries()[0]; echo 'Query ' . implode(' ', $entry->Query) . " took {$entry->Query_time} seconds at {$entry->Time}\n"; // Get the most rows examined $entry = $parser->sortEntries('Rows_examined', 'desc')->getEntries()[0]; echo 'Query ' . implode(' ', $entry->Query) . " looked at {$entry->Rows_examined} rows\n"; }
Entries
\PHPFUI\MySQLSlowQuery\Entry provides details on each query.
Supported fields:- Time
- User
- Host
- Id
- Query_time
- Lock_time
- Rows_sent
- Rows_examined
- Query (array)
- Session (zero based)
Sessions
\PHPFUI\MySQLSlowQuery\Session contains MySQL server information and are created on server restarts and log flushes. Pass the zero based session number to getEntries for only that Session's entries.
Supported fields:- Server
- Port
- Transport
Sort Entries
By default, entries are returned in log order, but call sortEntries on the Parser to sort by any valid field (parameter 1). Sort defaults to 'desc', anything else will sort ascending.
Full Class Documentation
Via PHPFUI/InstaDoc
License
Distributed under the MIT License.
- \PHPFUI\PHPUnitSyntaxCoverage Readme
PHPUnitSyntaxCoverage
PHPUnit Extension for complete PHP Syntax Code Coverage
This package will checks for easy to miss syntax errors in all your PHP code. It will also check all your classes to see if they are loadable, but without actually instantiating the class.
Often we accidently check in code with easily detectable syntax errors, but unless the file or class is actually loaded by PHP, we might not see the error. Often the file or class is syntaxically correct, but a method signature may not match an updated class or vendor library. Normally this would only be detectable at run time, but with PHPUnitSyntaxCoverage, you can make sure all files and classes are checked.
PHPUnitSyntaxCoverage uses PhpParser to check for basic syntax errors. It then uses ReflectionClass to load any classes that are found in the source without instantiating them. This will find additional errors (such as missing or changed base classes from a package update).
Requirements
- PHP 7.1 or higher
- PHPUnit 7 or higher
- Correctly configured autoloading
Installation
composer require phpfui/phpunit-syntax-coverage
Usage
Extend your unit tests from \PHPFUI\PHPUnitSyntaxCoverage\Extensions
class UnitTest extends \PHPFUI\PHPUnitSyntaxCoverage\Extensions { public function testProjectSyntax() { $this->addSkipDirectory(__DIR__ . '/../App/Examples'); $this->assertValidPHPDirectory(__DIR__ . '/../App', 'App directory has an error'); $this->assertValidPHPFile(__FILE__, 'Unit Test file not valid'); $this->assertValidPHP('<?php echo "hi";'); } }
You can use any of the following asserts:
- assertValidPHP(string $code, string $message = '')
- assertValidPHPDirectory(string $directory, string $message = '', bool $recurseSubdirectories = true, array $extensions = ['.php'])
- assertValidPHPFile(string $fileName, string $message = '')
Directory Testing
Instead of file by file testing, use assertValidPHPDirectory to test an entire directory. Any files added to the directory will be automatically tested.
$this->assertValidPHPDirectory(__DIR__ . '/../App', 'App directory error');
The error message will include the offending file name and line number.
Use addSkipDirectory to add simple case insensitive file matching to skip specific directories / files.
Autoloading
You must make sure autoloading is correctly configured for all classes. This means you can't pass references to classes that will not resolve correctly in your source. Use addSkipDirectory if you have test code that may not validate correctly.
PHP Version
While this library only supports PHP 7.1 or higher, you can create a project and point it to PHP 5.2 or higher. The default is to prefer PHP 7 code, but to prefer or only parse PHP 5, configure phpunit.xml(.dist) with
<php> <env name="PHPFUI\PHPUnitSyntaxCoverage\Extensions_parser_type" value="X"/> </php>
Where X is one of the following numbers:
- Prefer PHP 7
- Prefer PHP 5
- Only PHP 7
- Only PHP 5
Examples
See examples
Documentation
Full documentation at PHPFUI\PHPUnitSyntaxCoverage
- \Symfony\Component\Process Readme
Process Component
The Process component executes commands in sub-processes.
Resources
- \Webmozart\Assert Readme
Webmozart Assert
This library contains efficient assertions to test the input and output of
your methods. With these assertions, you can greatly reduce the amount of coding
needed to write a safe implementation.All assertions in the
Assert
class throw an\InvalidArgumentException
if
they fail.FAQ
What's the difference to beberlei/assert?
This library is heavily inspired by Benjamin Eberlei's wonderful assert package,
but fixes a usability issue with error messages that can't be fixed there without
breaking backwards compatibility.This package features usable error messages by default. However, you can also
easily write custom error messages:Assert::string($path, 'The path is expected to be a string. Got: %s');
In beberlei/assert, the ordering of the
%s
placeholders is different for
every assertion. This package, on the contrary, provides consistent placeholder
ordering for all assertions:%s
: The tested value as string, e.g."/foo/bar"
.%2$s
,%3$s
, ...: Additional assertion-specific values, e.g. the
minimum/maximum length, allowed values, etc.
Check the source code of the assertions to find out details about the additional
available placeholders.Installation
Use Composer to install the package:
$ composer require webmozart/assert
Example
use Webmozart\Assert\Assert; class Employee { public function __construct($id) { Assert::integer($id, 'The employee ID must be an integer. Got: %s'); Assert::greaterThan($id, 0, 'The employee ID must be a positive integer. Got: %s'); } }
If you create an employee with an invalid ID, an exception is thrown:
new Employee('foobar'); // => InvalidArgumentException: // The employee ID must be an integer. Got: string new Employee(-10); // => InvalidArgumentException: // The employee ID must be a positive integer. Got: -10
Assertions
The
Assert
class provides the following assertions:Type Assertions
Method Description string($value, $message = '')
Check that a value is a string stringNotEmpty($value, $message = '')
Check that a value is a non-empty string integer($value, $message = '')
Check that a value is an integer integerish($value, $message = '')
Check that a value casts to an integer float($value, $message = '')
Check that a value is a float numeric($value, $message = '')
Check that a value is numeric natural($value, $message= ''')
Check that a value is a non-negative integer boolean($value, $message = '')
Check that a value is a boolean scalar($value, $message = '')
Check that a value is a scalar object($value, $message = '')
Check that a value is an object resource($value, $type = null, $message = '')
Check that a value is a resource isCallable($value, $message = '')
Check that a value is a callable isArray($value, $message = '')
Check that a value is an array isTraversable($value, $message = '')
(deprecated)Check that a value is an array or a \Traversable
isIterable($value, $message = '')
Check that a value is an array or a \Traversable
isCountable($value, $message = '')
Check that a value is an array or a \Countable
isInstanceOf($value, $class, $message = '')
Check that a value is an instanceof
a classisInstanceOfAny($value, array $classes, $message = '')
Check that a value is an instanceof
a at least one class on the array of classesnotInstanceOf($value, $class, $message = '')
Check that a value is not an instanceof
a classisArrayAccessible($value, $message = '')
Check that a value can be accessed as an array uniqueValues($values, $message = '')
Check that the given array contains unique values Comparison Assertions
Method Description true($value, $message = '')
Check that a value is true
false($value, $message = '')
Check that a value is false
null($value, $message = '')
Check that a value is null
notNull($value, $message = '')
Check that a value is not null
isEmpty($value, $message = '')
Check that a value is empty()
notEmpty($value, $message = '')
Check that a value is not empty()
eq($value, $value2, $message = '')
Check that a value equals another ( ==
)notEq($value, $value2, $message = '')
Check that a value does not equal another ( !=
)same($value, $value2, $message = '')
Check that a value is identical to another ( ===
)notSame($value, $value2, $message = '')
Check that a value is not identical to another ( !==
)greaterThan($value, $value2, $message = '')
Check that a value is greater than another greaterThanEq($value, $value2, $message = '')
Check that a value is greater than or equal to another lessThan($value, $value2, $message = '')
Check that a value is less than another lessThanEq($value, $value2, $message = '')
Check that a value is less than or equal to another range($value, $min, $max, $message = '')
Check that a value is within a range oneOf($value, array $values, $message = '')
Check that a value is one of a list of values String Assertions
You should check that a value is a string with
Assert::string()
before making
any of the following assertions.Method Description contains($value, $subString, $message = '')
Check that a string contains a substring notContains($value, $subString, $message = '')
Check that a string does not contains a substring startsWith($value, $prefix, $message = '')
Check that a string has a prefix startsWithLetter($value, $message = '')
Check that a string starts with a letter endsWith($value, $suffix, $message = '')
Check that a string has a suffix regex($value, $pattern, $message = '')
Check that a string matches a regular expression notRegex($value, $pattern, $message = '')
Check that a string does not match a regular expression unicodeLetters($value, $message = '')
Check that a string contains Unicode letters only alpha($value, $message = '')
Check that a string contains letters only digits($value, $message = '')
Check that a string contains digits only alnum($value, $message = '')
Check that a string contains letters and digits only lower($value, $message = '')
Check that a string contains lowercase characters only upper($value, $message = '')
Check that a string contains uppercase characters only length($value, $length, $message = '')
Check that a string has a certain number of characters minLength($value, $min, $message = '')
Check that a string has at least a certain number of characters maxLength($value, $max, $message = '')
Check that a string has at most a certain number of characters lengthBetween($value, $min, $max, $message = '')
Check that a string has a length in the given range uuid($value, $message = '')
Check that a string is a valid UUID ip($value, $message = '')
Check that a string is a valid IP (either IPv4 or IPv6) ipv4($value, $message = '')
Check that a string is a valid IPv4 ipv6($value, $message = '')
Check that a string is a valid IPv6 email($value, $message = '')
Check that a string is a valid e-mail address notWhitespaceOnly($value, $message = '')
Check that a string contains at least one non-whitespace character File Assertions
Method Description fileExists($value, $message = '')
Check that a value is an existing path file($value, $message = '')
Check that a value is an existing file directory($value, $message = '')
Check that a value is an existing directory readable($value, $message = '')
Check that a value is a readable path writable($value, $message = '')
Check that a value is a writable path Object Assertions
Method Description classExists($value, $message = '')
Check that a value is an existing class name subclassOf($value, $class, $message = '')
Check that a class is a subclass of another interfaceExists($value, $message = '')
Check that a value is an existing interface name implementsInterface($value, $class, $message = '')
Check that a class implements an interface propertyExists($value, $property, $message = '')
Check that a property exists in a class/object propertyNotExists($value, $property, $message = '')
Check that a property does not exist in a class/object methodExists($value, $method, $message = '')
Check that a method exists in a class/object methodNotExists($value, $method, $message = '')
Check that a method does not exist in a class/object Array Assertions
Method Description keyExists($array, $key, $message = '')
Check that a key exists in an array keyNotExists($array, $key, $message = '')
Check that a key does not exist in an array validArrayKey($key, $message = '')
Check that a value is a valid array key (int or string) count($array, $number, $message = '')
Check that an array contains a specific number of elements minCount($array, $min, $message = '')
Check that an array contains at least a certain number of elements maxCount($array, $max, $message = '')
Check that an array contains at most a certain number of elements countBetween($array, $min, $max, $message = '')
Check that an array has a count in the given range isList($array, $message = '')
Check that an array is a non-associative list isNonEmptyList($array, $message = '')
Check that an array is a non-associative list, and not empty isMap($array, $message = '')
Check that an array is associative and has strings as keys isNonEmptyMap($array, $message = '')
Check that an array is associative and has strings as keys, and is not empty Function Assertions
Method Description throws($closure, $class, $message = '')
Check that a function throws a certain exception. Subclasses of the exception class will be accepted. Collection Assertions
All of the above assertions can be prefixed with
all*()
to test the contents
of an array or a\Traversable
:Assert::allIsInstanceOf($employees, 'Acme\Employee');
Nullable Assertions
All of the above assertions can be prefixed with
nullOr*()
to run the
assertion only if it the value is notnull
:Assert::nullOrString($middleName, 'The middle name must be a string or null. Got: %s');
Extending Assert
The
Assert
class comes with a few methods, which can be overridden to change the class behaviour. You can also extend it to
add your own assertions.Overriding methods
Overriding the following methods in your assertion class allows you to change the behaviour of the assertions:
public static function __callStatic($name, $arguments)
- This method is used to 'create' the
nullOr
andall
versions of the assertions.
- This method is used to 'create' the
protected static function valueToString($value)
- This method is used for error messages, to convert the value to a string value for displaying. You could use this for representing a value object with a
__toString
method for example.
- This method is used for error messages, to convert the value to a string value for displaying. You could use this for representing a value object with a
protected static function typeToString($value)
- This method is used for error messages, to convert the a value to a string representing its type.
protected static function strlen($value)
- This method is used to calculate string lenght for relevant methods, using the
mb_strlen
if available and usefull.
- This method is used to calculate string lenght for relevant methods, using the
protected static function reportInvalidArgument($message)
- This method is called when an assertion fails, with the specified error message. Here you can throw your own exception, or log something.
Authors
Contribute
Contributions to the package are always welcome!
- Report any bugs or issues you find on the issue tracker.
- You can grab the source code at the package's Git repository.
License
All contents of this package are licensed under the MIT license.