commit
12f81bea4e
|
@ -1,7 +1,18 @@
|
|||
resume/_*.md
|
||||
output/*.html
|
||||
output/*.pdf
|
||||
vendor
|
||||
examples/resume/_*.md
|
||||
examples/output/*.html
|
||||
examples/output/*.pdf
|
||||
.tmp_pdf_source.html
|
||||
|
||||
resume/sample_long.md
|
||||
# OSX files
|
||||
.DS_Store
|
||||
.AppleDouble
|
||||
.LSOverride
|
||||
Icon
|
||||
|
||||
/vendor/
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
# Files that might appear on external disk
|
||||
.Spotlight-V100
|
||||
.Trashes
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
language: php
|
||||
|
||||
before_script:
|
||||
- curl -s http://getcomposer.org/installer | php
|
||||
- php composer.phar install --dev
|
||||
|
||||
php:
|
||||
- 5.3
|
||||
- 5.4
|
90
README.md
90
README.md
|
@ -6,55 +6,104 @@ at the [blog post for the project][blog].
|
|||
|
||||
## Features
|
||||
|
||||
* Three styles to choose from: modern, blockish, unstyled
|
||||
* PDF generation via `wkhtmltopdf`
|
||||
* Three styles to choose from: modern, blockish, unstyled (Fork and add more!)
|
||||
* PDF generation via [wkhtmltopdf][wkhtmltopdf]
|
||||
* Responsive design for multiple device viewport sizes
|
||||
* Simple Markdown formatting
|
||||
* Single file deployment
|
||||
* Single file deployment (no external stylesheets)
|
||||
* You can now version control and branch your resume.
|
||||
|
||||
## Quickstart
|
||||
|
||||
php ./bin/resume.php --source resume/sample.md
|
||||
php ./bin/resume.php --source resume/sample.md --pdf
|
||||
There is no installation or need to run composer. Just run the phar file:
|
||||
|
||||
## Options
|
||||
./bin/md2resume html examples/source/sample.md examples/output/
|
||||
./bin/md2resume pdf examples/source/sample.md examples/output/
|
||||
|
||||
## Help
|
||||
|
||||
Markdown Resume Generator version 2.0.0 by Craig Davis
|
||||
|
||||
Usage:
|
||||
[options] command [arguments]
|
||||
|
||||
Options:
|
||||
--help -h Display this help message.
|
||||
--quiet -q Do not output any message.
|
||||
--verbose -v|vv|vvv Increase the verbosity of messages: 1 for normal output, 2 for more verbose output and 3 for debug
|
||||
--version -V Display this application version.
|
||||
--ansi Force ANSI output.
|
||||
--no-ansi Disable ANSI output.
|
||||
--no-interaction -n Do not ask any interactive question.
|
||||
|
||||
Available commands:
|
||||
help Displays help for a command
|
||||
html Generate an HTML resume from a markdown file
|
||||
list Lists commands
|
||||
pdf Generate a PDF from a markdown file
|
||||
selfupdate Updates md2resume.phar to the latest version.
|
||||
templates List available templates
|
||||
version Show current version information
|
||||
|
||||
## Examples
|
||||
|
||||
Choose a template with the -t option.
|
||||
|
||||
php ./bin/resume.php --source resume/sample.md -t blockish
|
||||
./bin/md2resume html --template blockish examples/source/sample.md examples/output/
|
||||
|
||||
If you want to edit your markdown resume in your editor while watching it
|
||||
update in your browser, run this command:
|
||||
|
||||
watch php ./bin/resume.php -s resume/sample.md -r
|
||||
watch ./bin/md2resume html --refresh examples/source/sample.md examples/output/
|
||||
|
||||
This makes the build script run periodically, and html document will refresh
|
||||
every two seconds via a meta tag. Open the `./ouput/sample.html` file in
|
||||
your browser, and then just save your markdown document when you want to see
|
||||
every two seconds via a meta tag. Open the `./examples/ouput/sample.html` file
|
||||
in your browser, and then just save your markdown document when you want to see
|
||||
a fresh preview.
|
||||
|
||||
## Development
|
||||
## Authoring Your Resume
|
||||
|
||||
Markdown is limited to basic html markup. Follow the `resume/sample.md` file
|
||||
as a guideline. This file includes various headers and several nested elements.
|
||||
This allows us to construct a semantic HTML document for the resume, and then
|
||||
use a CSS rules to display a very nice resume. Note that because we have very
|
||||
few ways to nest or identify elements that many of the css rules are based
|
||||
on descendant and adjacent selectors.
|
||||
Markdown is limited to basic html markup. Follow the `examples/source/sample.md`
|
||||
file as a guideline. This file includes various headers and several nested
|
||||
elements. This allows us to construct a semantic HTML document for the resume,
|
||||
and then use a CSS rules to display a very nice resume. Note that because we
|
||||
have very few ways to nest or identify elements that many of the css rules are
|
||||
based on descendant and adjacent selectors.
|
||||
|
||||
__PLEASE NOTE__: The templates are compiled into the phar archive in the `./bin`
|
||||
folder. If you intend to edit the templates or add new ones, you'll need to run
|
||||
this application in the dev mode. See below for more information about doing
|
||||
this.
|
||||
|
||||
## Feature Development
|
||||
|
||||
The application is deployed as a compiled phar file. In order to add new
|
||||
commands, you'll need to first install the dependencies:
|
||||
|
||||
* `composer install`
|
||||
* `pear install PHP_CodeSniffer`
|
||||
* [install pake][pake]
|
||||
|
||||
After that, you can run the `md2resume_dev.php` file from the command line.
|
||||
Check out the pake tooling for more information about the build.
|
||||
|
||||
## TODO
|
||||
|
||||
* Google Analytics include
|
||||
* CDN for fonts
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
The initial inspiration is from the [Sample Resume Template][srt].
|
||||
However, no HTML from that project has been used in this. General layout has been reused, and media queries
|
||||
have been added. It's a nice template, and if you are a more comfortable with html than markdown, you should use it.
|
||||
However, no HTML from that project has been used in this. General layout has
|
||||
been reused, and media queries have been added. It's a nice template, and if you
|
||||
are a more comfortable with html than markdown, you should use it.
|
||||
|
||||
## Changelog
|
||||
|
||||
* __2.0.0__ : Complete rewrite with the [symfony console component][console].
|
||||
Deployment is no done with a compiled phar file, and development dependencies
|
||||
are managed with composer.
|
||||
* __0.9.0__ : Add composer and update README with new changelog
|
||||
* __0.8.8__ : Add Chinese text example (@ishitcno1)
|
||||
* __0.8.7__ : Update pdf formatting of the modern template (@roleary)
|
||||
|
@ -67,3 +116,6 @@ have been added. It's a nice template, and if you are a more comfortable with ht
|
|||
|
||||
[srt]: http://sampleresumetemplate.net/ "A great starting point"
|
||||
[blog]: http://there4development.com/blog/2012/12/31/markdown-resume-builder/
|
||||
[pake]: https://github.com/indeyets/pake/wiki/Installing-Pake
|
||||
[wkhtmltopdf]: https://github.com/pdfkit/pdfkit/wiki/Installing-WKHTMLTOPDF
|
||||
[console]: http://symfony.com/doc/current/components/console/introduction.html
|
||||
|
|
Binary file not shown.
129
bin/resume.php
129
bin/resume.php
|
@ -1,129 +0,0 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
define('APPLICATION_BASE_PATH', realpath(__DIR__ . '/..'));
|
||||
|
||||
require APPLICATION_BASE_PATH . '/vendor/autoload.php';
|
||||
require APPLICATION_BASE_PATH . '/vendor/Mustache/Mustache.php';
|
||||
require APPLICATION_BASE_PATH . '/vendor/smartypants/smartypants.php';
|
||||
require APPLICATION_BASE_PATH . '/vendor/markdown-extra/markdown.php';
|
||||
require APPLICATION_BASE_PATH . '/vendor/lessphp/lessc.inc.php';
|
||||
require APPLICATION_BASE_PATH . '/vendor/simpledom/simple_html_dom.php';
|
||||
|
||||
use Assetic\Asset\AssetCollection;
|
||||
use Assetic\Asset\FileAsset;
|
||||
use Assetic\Asset\GlobAsset;
|
||||
use Assetic\Filter;
|
||||
|
||||
// Application defaults
|
||||
$config = (object) array(
|
||||
"source" => "",
|
||||
"output" => "./output",
|
||||
"template" => "modern",
|
||||
"refresh" => false,
|
||||
"pdf" => false
|
||||
);
|
||||
|
||||
// Command line arguments to populate the config
|
||||
$opts = array(
|
||||
"s:" => "source:", // source
|
||||
"o:" => "output:", // output
|
||||
"t:" => "template:", // template
|
||||
"r" => "refresh", // refresh
|
||||
"p" => "pdf" // pdf output
|
||||
);
|
||||
|
||||
// Fetch the options from the command line arguments
|
||||
$options = getopt(implode("", array_keys($opts)), array_values($opts));
|
||||
|
||||
// Consolidate the short and long options into the config array
|
||||
// Make sure that boolean options are set appropriately.
|
||||
foreach ($opts as $short => $long) {
|
||||
$isBool = (substr($short, -1, 1) !== ":");
|
||||
$short = trim($short, ":");
|
||||
$long = trim($long, ":");
|
||||
|
||||
if (isset($options[$short])) {
|
||||
$config->$long = $isBool ? true : $options[$short];
|
||||
}
|
||||
else if (isset($options[$long])) {
|
||||
$config->$long = $isBool ? true : $options[$long];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($config->source)) {
|
||||
exit("Please specify a source document: bin/resume.php -s resume/resume.pdf\n");
|
||||
}
|
||||
|
||||
$basename = pathinfo($config->source, PATHINFO_FILENAME);
|
||||
$template_path = realpath(__DIR__ . '/../templates/' . $config->template);
|
||||
$pdf_source = $config->output . '/' . $basename . '-pdf.html';
|
||||
$output = $config->output . '/' . $basename . '.html';
|
||||
$pdf_output = $config->output . '/' . $basename . '.pdf';
|
||||
|
||||
if (!file_exists($config->source)) {
|
||||
exit("Please specify a valid source file.\n");
|
||||
}
|
||||
|
||||
if (!file_exists($template_path)) {
|
||||
// TODO: List templates
|
||||
exit("Please specify a valid template.\n");
|
||||
}
|
||||
|
||||
// We build these into a single string so that we can deploy this resume as a
|
||||
// single file.
|
||||
$css = new AssetCollection(
|
||||
array(new GlobAsset($template_path . '/css/*.css')),
|
||||
array(new Filter\LessphpFilter())
|
||||
);
|
||||
$style = $css->dump();
|
||||
|
||||
$template = file_get_contents($template_path . '/index.html');
|
||||
$resume = file_get_contents($config->source);
|
||||
|
||||
// Process with Markdown, and then use SmartyPants to clean up punctuation.
|
||||
$resume = SmartyPants(Markdown($resume));
|
||||
|
||||
// We'll construct the title for the html document from the h1 and h2 tags
|
||||
$html = str_get_html($resume);
|
||||
$title = sprintf(
|
||||
'%s | %s',
|
||||
$html->find('h1', 0)->innertext,
|
||||
$html->find('h2', 0)->innertext
|
||||
);
|
||||
|
||||
// We'll now render the Markdown into an html file with Mustache Templates
|
||||
$m = new Mustache;
|
||||
$rendered = $m->render(
|
||||
$template,
|
||||
array(
|
||||
'title' => $title,
|
||||
'style' => $style,
|
||||
'resume' => $resume,
|
||||
'reload' => $config->refresh
|
||||
)
|
||||
);
|
||||
|
||||
// Save the fully rendered html to the final destination
|
||||
file_put_contents($output, $rendered);
|
||||
echo "Wrote html to $output\n";
|
||||
|
||||
// If the user wants to make a pdf file, we'll use wkhtmltopdf to convert
|
||||
// the html document into a nice looking pdf.
|
||||
if ($config->pdf) {
|
||||
|
||||
// The pdf needs some extra css rules, and so we'll add them here
|
||||
// to our html document
|
||||
$pdf_classed = str_replace('body class=""', 'body class="pdf"', $rendered);
|
||||
|
||||
// Save the new pdf-ready html to a temp destination
|
||||
file_put_contents($pdf_source, $pdf_classed );
|
||||
|
||||
// Process the document with wkhtmltopdf
|
||||
exec('wkhtmltopdf ' . $pdf_source .' ' . $pdf_output);
|
||||
|
||||
// Unlink the temporary file
|
||||
unlink($pdf_source);
|
||||
echo "Wrote pdf to $pdf_output\n";
|
||||
}
|
||||
|
||||
/* End of file resume.php */
|
|
@ -0,0 +1,496 @@
|
|||
#!/usr/bin/env php
|
||||
<?php
|
||||
/*
|
||||
* Empir
|
||||
*
|
||||
Copyright (c) 2010 Jeremy Perret <j.perret.27@gmail.com>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
*/
|
||||
|
||||
//if colors make any damages on your terminal deactivate them by setting to false this option
|
||||
define('ACTIVATE_COLORS', true);
|
||||
|
||||
//only run Empir automatically when this file is called directly from the command line
|
||||
if (isset($argv[0])) {
|
||||
if (version_compare(phpversion(), '5.3.0', '<')) {
|
||||
echo "ERROR: Empir require php >= 5.3.0 (Your PHP version: ".phpversion().")\n";
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$empir = new Empir($argv);
|
||||
exit($empir->run());
|
||||
}
|
||||
|
||||
/**
|
||||
* Command line interface Helper.
|
||||
*
|
||||
* @package Empir
|
||||
* @author Jeremy Perret <j.perret.27@gmail.com>
|
||||
*/
|
||||
class CLI_Interface
|
||||
{
|
||||
protected function execCommand()
|
||||
{
|
||||
if (isset($this->commands[$this->command])) {
|
||||
$method = $this->commands[$this->command];
|
||||
$rcode = $this->$method();
|
||||
}else
|
||||
$rcode = $this->error("Command <$this->command> doesn't exist. Try <help>");
|
||||
|
||||
return ($rcode == null) ? 0 : $rcode;
|
||||
}
|
||||
|
||||
protected function gopt($no)
|
||||
{
|
||||
if(isset($this->options[$no]))
|
||||
|
||||
return $this->options[$no];
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function glopt($opt)
|
||||
{
|
||||
foreach ($this->options as $option) {
|
||||
if(strpos($option, "--$opt=") !== false)
|
||||
|
||||
return trim(end(explode('=', $option)), '"');
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
protected function reqopt($no, $name)
|
||||
{
|
||||
if($this->gopt($no) == null)
|
||||
exit($this->error("Param $name is required. Try <help>"));
|
||||
|
||||
return $this->gopt($no);
|
||||
}
|
||||
|
||||
protected function error($message = '', $errno = 1)
|
||||
{
|
||||
if($message != '')
|
||||
echo Color::str("ERROR: $message\n", Empir::ERR_COLOR);
|
||||
|
||||
return $errno;
|
||||
}
|
||||
|
||||
protected function success($message)
|
||||
{
|
||||
echo Color::str("$message\n", Empir::SUCCESS_COLOR);
|
||||
}
|
||||
|
||||
protected function makeAbsolut($path='')
|
||||
{
|
||||
$current = getcwd().'/';
|
||||
if($path == "" || $path == false)
|
||||
$absolut_path = $current;
|
||||
elseif(substr($path, 0, 2) == './')
|
||||
$absolut_path = $current.substr($path,2);
|
||||
elseif(strpos($path, ':') !== false || substr($path, 0, 2) == '\\\\' || substr($path, 0, 1) == '/')
|
||||
$absolut_path = $path;
|
||||
else
|
||||
$absolut_path = $current.$path;
|
||||
|
||||
$absolut_path = str_replace('\\', '/', $absolut_path);
|
||||
$absolut_path = rtrim($absolut_path, '/');
|
||||
|
||||
return $absolut_path;
|
||||
}
|
||||
|
||||
private function find_opt($opt)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Manage phar
|
||||
*
|
||||
* @package Empir
|
||||
* @author Jeremy Perret <j.perret.27@gmail.com>
|
||||
*/
|
||||
class Empir extends CLI_Interface
|
||||
{
|
||||
const VERSION = '1.0.0';
|
||||
const ERR_COLOR = 'red';
|
||||
const HELP_COLOR = 'green';
|
||||
const PARAM_COLOR = 'purple';
|
||||
const SUCCESS_COLOR = 'green';
|
||||
|
||||
public $options = array();
|
||||
public $command;
|
||||
public $commands = array(
|
||||
'help' => 'help',
|
||||
'?' => 'help',
|
||||
'-h' => 'help',
|
||||
'make' => 'make',
|
||||
'convert' => 'convert',
|
||||
'extract' => 'extract'
|
||||
);
|
||||
public $compression_types = array('gz', 'bz2', 'no');
|
||||
public $format_types = array('phar', 'tar', 'zip');
|
||||
|
||||
public function __construct($argv)
|
||||
{
|
||||
$this->options = array_slice($argv, 1);
|
||||
|
||||
$vars = array(
|
||||
'gz' => array(
|
||||
'name' => 'gz',
|
||||
'extension' => 'zlib',
|
||||
'mime' => '.gz',
|
||||
'int_value' => Phar::GZ,
|
||||
),
|
||||
'bz2' => array(
|
||||
'name' => 'bz2',
|
||||
'extension' => 'bzip2',
|
||||
'mime' => '.bz2',
|
||||
'int_value' => Phar::BZ2,
|
||||
),
|
||||
'no' => array(
|
||||
'name' => 'no',
|
||||
'extension' => 'not',
|
||||
'mime' => '',
|
||||
'int_value' => Phar::NONE,
|
||||
),
|
||||
'phar' => array(
|
||||
'name' => 'phar',
|
||||
'mime' => '.phar',
|
||||
'int_value' => Phar::PHAR,
|
||||
'compression' => true
|
||||
),
|
||||
'tar' => array(
|
||||
'name' => 'tar',
|
||||
'mime' => '.tar',
|
||||
'int_value' => Phar::TAR,
|
||||
'compression' => true
|
||||
),
|
||||
'zip' => array(
|
||||
'name' => 'zip',
|
||||
'mime' => '.zip',
|
||||
'int_value' => Phar::ZIP,
|
||||
'compression' => false
|
||||
)
|
||||
);
|
||||
foreach($vars as $name => $attrs)
|
||||
$this->$name = $this->array_to_object($attrs);
|
||||
}
|
||||
|
||||
public function run()
|
||||
{
|
||||
$this->command = ($this->gopt(0) != null) ? $this->gopt(0) : 'help';
|
||||
$this->options = array_slice($this->options, 1);
|
||||
|
||||
return $this->execCommand();
|
||||
}
|
||||
|
||||
public function make()
|
||||
{
|
||||
$this->_is_phar_writable();
|
||||
$phar = $this->makeAbsolut($this->reqopt(0, 'phar filename'));
|
||||
$phar_name = end(explode('/', $phar));
|
||||
$stub_file = trim($this->reqopt(1, 'stub file'), '/');
|
||||
$root_app = $this->makeAbsolut($this->reqopt(2, 'root dir of your app'));
|
||||
$_compression = $this->glopt('compress') ?: 'no';
|
||||
$_format = $this->glopt('format') ?: 'phar';
|
||||
$_exclude = $this->glopt('exclude');
|
||||
$_fexclude = $this->glopt('fexclude');
|
||||
|
||||
if(!file_exists($root_app)) return $this->error("Root dir of your app doesn't exist.");
|
||||
|
||||
if(!empty($_compression) && !in_array($_compression, $this->compression_types)) return $this->error("Unrecognized compression: $_compression");
|
||||
if(!empty($_format) && !in_array($_format, $this->format_types)) return $this->error("Unrecognized format: $_format");
|
||||
|
||||
if (!empty($_fexclude)) {
|
||||
$_fexclude = $this->makeAbsolut($_fexclude);
|
||||
if(!file_exists($_fexclude)) return $this->error("Exclude file: $_fexclude not found.");
|
||||
$_fexclude = file_get_contents($_fexclude);
|
||||
}
|
||||
|
||||
$shell_masks = explode('|', $_exclude);
|
||||
$shell_masks = array_merge($shell_masks, explode("\n", $_fexclude));
|
||||
|
||||
$c = $this->get_var($_compression);
|
||||
$f = $this->get_var($_format);
|
||||
|
||||
if (file_exists($phar)) {
|
||||
unlink($phar);
|
||||
}
|
||||
|
||||
try {
|
||||
$p = new Phar($phar, Phar::CURRENT_AS_FILEINFO | Phar::KEY_AS_FILENAME, $phar_name);
|
||||
|
||||
echo "Make $phar_name : \n===================\n";
|
||||
$project = json_decode(file_get_contents('composer.json'));
|
||||
$p->setStub(
|
||||
"#!/usr/bin/env php \n"
|
||||
. "<?php\n"
|
||||
. 'define("IN_PHAR", true);' . "\n"
|
||||
. '$project = (object) array(' . "\n"
|
||||
. " 'description' => '$project->description', " . "\n"
|
||||
. " 'version' => '$project->version'," . "\n"
|
||||
. " 'selfupdatepath' => '$project->selfupdatepath'," . "\n"
|
||||
. " 'selfupdateversion' => '$project->selfupdateversion'," . "\n"
|
||||
. ");" . "\n"
|
||||
. "Phar::mapPhar(); " . "\n"
|
||||
. "include 'phar://".$phar_name."/".$stub_file."'; " . "\n"
|
||||
. "__HALT_COMPILER(); " . "\n"
|
||||
. "?>" . "\n"
|
||||
);
|
||||
|
||||
$files = $this->_scandir($root_app);
|
||||
|
||||
$i=0;
|
||||
foreach ($files as $file) {
|
||||
$file_buff = $file;
|
||||
$file = str_replace('\\', '/', $file);
|
||||
$file = str_replace($root_app.'/', '', $file);
|
||||
|
||||
if (!$this->_exclude($file, $shell_masks) && !$this->_exclude($file, array('*/'.$phar_name, $phar_name))) {
|
||||
echo "add $file\n";
|
||||
//$p[$file] = php_strip_whitespace($file_buff);
|
||||
$p[$file] = file_get_contents($file_buff);
|
||||
$i++;
|
||||
}
|
||||
}
|
||||
|
||||
echo "\nTotal: $i files added\n";
|
||||
|
||||
if ($f->name == 'phar' && $c->name='no') {
|
||||
$this->success("CREATE $phar");
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if(!Phar::canCompress($c->int_value)) return $this->error("Unable to compress the phar with $c->name, extension $c->extension not found. But $phar is created.");
|
||||
|
||||
if(!$f->compression) $c->int_value = Phar::NONE;
|
||||
|
||||
$phar_copy = $phar.$f->mime.$c->mime;
|
||||
@unlink($phar_copy);
|
||||
$p = $p->convertToExecutable($f->int_value, $c->int_value);
|
||||
$this->success("CREATE $phar_copy");
|
||||
@unlink($phar);
|
||||
} catch (Exception $e) {
|
||||
return $this->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public function help()
|
||||
{
|
||||
$help = new Help();
|
||||
$command = $this->gopt(0);
|
||||
if(empty($command)) return $help->main();
|
||||
|
||||
switch ($command) {
|
||||
case 'make': $help->make(); break;
|
||||
default: return $this->error("Command: $command doesn't exist."); break;
|
||||
}
|
||||
}
|
||||
|
||||
private function _is_phar_writable()
|
||||
{
|
||||
if(!Phar::canWrite()) exit($this->error("Unable to write phar, phar.readonly must be set to zero in your php.ini otherwise use: $ php -dphar.readonly=0 empir <command> ..."));
|
||||
}
|
||||
|
||||
private function get_var($var)
|
||||
{
|
||||
if (is_string($var)) {
|
||||
if(isset($this->$var))
|
||||
|
||||
return $this->$var;
|
||||
} else {
|
||||
foreach (array_merge($this->compression_types, $this->format_types) as $v) {
|
||||
if($this->$v->int_value == $var)
|
||||
|
||||
return $this->$v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function _exclude($file, $shell_masks)
|
||||
{
|
||||
if (!empty($shell_masks)) {
|
||||
foreach ($shell_masks as $mask) {
|
||||
if(fnmatch(trim($mask), $file))
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private function _scandir($path)
|
||||
{
|
||||
$items = array();
|
||||
$path = rtrim($path, '/');
|
||||
if (!$current_dir = opendir($path))
|
||||
return $items;
|
||||
|
||||
while (false !== ($filename = readdir($current_dir))) {
|
||||
if ($filename != "." && $filename != "..") {
|
||||
if (is_dir($path.'/'.$filename)) {
|
||||
$items = array_merge($items, $this->_scandir($path.'/'.$filename));
|
||||
} else
|
||||
$items[] = $path.'/'.$filename;
|
||||
}
|
||||
}
|
||||
closedir($current_dir);
|
||||
|
||||
return $items;
|
||||
}
|
||||
|
||||
private function array_to_object($array)
|
||||
{
|
||||
$object = new stdClass();
|
||||
foreach ($array as $name => $value) {
|
||||
$name = strtolower(trim($name));
|
||||
if (!empty($name))
|
||||
$object->$name = $value;
|
||||
}
|
||||
|
||||
return $object;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Colorizer
|
||||
*
|
||||
* @package Empir
|
||||
* @author Jeremy Perret <j.perret.27@gmail.com>
|
||||
*/
|
||||
class Color
|
||||
{
|
||||
public static $foreground_colors = array(
|
||||
'black' => '0;30',
|
||||
'dark_gray' => '1;30',
|
||||
'blue' => '0;34',
|
||||
'light_blue' => '1;34',
|
||||
'green' => '0;32',
|
||||
'light_green' => '1;32',
|
||||
'cyan' => '0;36',
|
||||
'light_cyan' => '1;36',
|
||||
'red' => '0;31',
|
||||
'light_red' => '1;31',
|
||||
'purple' => '0;35',
|
||||
'light_purple' => '1;35',
|
||||
'brown' => '0;33',
|
||||
'yellow' => '1;33',
|
||||
'light_gray' => '0;37',
|
||||
'white' => '1;37'
|
||||
);
|
||||
|
||||
public static $background_colors = array(
|
||||
'black' => '40',
|
||||
'red' => '41',
|
||||
'green' => '42',
|
||||
'yellow' => '43',
|
||||
'blue' => '44',
|
||||
'magenta' => '45',
|
||||
'cyan' => '46',
|
||||
'light_gray' => '47'
|
||||
);
|
||||
|
||||
public static function str($string, $foreground_color = null, $background_color = null)
|
||||
{
|
||||
if(!self::isTermSupportColor()) return $string;
|
||||
|
||||
$colored_string = "";
|
||||
|
||||
if (isset(self::$foreground_colors[$foreground_color])) {
|
||||
$colored_string .= "\033[".self::$foreground_colors[$foreground_color]."m";
|
||||
}
|
||||
|
||||
if (isset(self::$background_colors[$background_color])) {
|
||||
$colored_string .= "\033[".self::$background_colors[$background_color]."m";
|
||||
}
|
||||
|
||||
$colored_string .= $string."\033[0m";
|
||||
|
||||
return $colored_string;
|
||||
}
|
||||
|
||||
public static function random($string)
|
||||
{
|
||||
$index_foreground = array_rand(self::$foreground_colors, 1);
|
||||
$index_background= array_rand(self::$background_colors, 1);
|
||||
|
||||
return self::str($string, $index_foreground, $index_background);
|
||||
}
|
||||
|
||||
public static function isTermSupportColor()
|
||||
{
|
||||
$term = getenv('TERM');
|
||||
if($term && ACTIVATE_COLORS) return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* All differents helps.
|
||||
*
|
||||
* @package Empir
|
||||
* @author Jeremy Perret <j.perret.27@gmail.com>
|
||||
*/
|
||||
class Help
|
||||
{
|
||||
public function main()
|
||||
{
|
||||
echo "Empir v".Empir::VERSION." 2010 (c) Jeremy Perret <j.perret.27@gmail.com>
|
||||
Empir is a php tool to manage phar.
|
||||
The setting phar.readonly must be 0 in your php.ini,
|
||||
otherwise use $ php -dphar.readonly=0 empir <command> ...
|
||||
If you use Empir from PEAR installation don't care about this php option,
|
||||
it used directly in the executable file.
|
||||
|
||||
".Color::str('Usage', Empir::HELP_COLOR).":
|
||||
$ php empir <command> <parameters> [options]
|
||||
|
||||
".Color::str('Commands', Empir::HELP_COLOR).":
|
||||
".Color::str('make', Empir::PARAM_COLOR)." Create a phar from an entire php application.
|
||||
|
||||
For more help on a command use 'empir help <command>'
|
||||
";
|
||||
}
|
||||
|
||||
public function make()
|
||||
{
|
||||
echo "Command make allows to create a phar file from an entire php application from its root directory.
|
||||
|
||||
".Color::str('Usage', Empir::HELP_COLOR).":
|
||||
$ php empir make <phar_file> <stub_file> <root_app> [options]
|
||||
|
||||
".Color::str('Parameters', Empir::HELP_COLOR).":
|
||||
".Color::str('phar_file', Empir::PARAM_COLOR)." Phar file that will be created, accept absolute or relative path.
|
||||
".Color::str('stub_file', Empir::PARAM_COLOR)." Bootstrap file of your application, from your root app folder.
|
||||
".Color::str('root_app', Empir::PARAM_COLOR)." Root folder of your application, accept absolute or relative path.
|
||||
|
||||
".Color::str('Options', Empir::HELP_COLOR).":
|
||||
".Color::str('--exclude=PATTERN', Empir::PARAM_COLOR)." Exclude files match PATTERN, seperate several patterns with a pipe.
|
||||
".Color::str('--fexclude=FILE', Empir::PARAM_COLOR)." Exclude patterns listed in FILE. One pattern per line.
|
||||
".Color::str('--format=FORMAT', Empir::PARAM_COLOR)." Special phar format, FORMAT can be tar or zip. Don't specify format to keep normal phar.
|
||||
".Color::str('--compress=TYPE', Empir::PARAM_COLOR)." Specify the phar compression type. TYPE can be gz or bz2.
|
||||
";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,150 @@
|
|||
#!/usr/bin/php
|
||||
<?php
|
||||
// ===========
|
||||
// = Globals =
|
||||
// ===========
|
||||
$count = 0; // total files checked
|
||||
$errors = array();
|
||||
$options = setOptions(array(
|
||||
'quiet' => false,
|
||||
'recurse' => false,
|
||||
));
|
||||
|
||||
|
||||
if ($options['quiet']) {
|
||||
ob_start();
|
||||
}
|
||||
|
||||
// =============
|
||||
// = Scan path =
|
||||
// =============
|
||||
$files = getPipedFiles();
|
||||
|
||||
$path = $_SERVER['PWD']; // Default to execution directory
|
||||
|
||||
|
||||
// Piped files present
|
||||
if ($files) {
|
||||
foreach ($files as $file) {
|
||||
checkFile("$path/$file");
|
||||
}
|
||||
}
|
||||
// Use arguments
|
||||
else {
|
||||
if ($_SERVER['argc'] > 1) {
|
||||
$last = end($_SERVER['argv']);
|
||||
if (substr($last, 0, 1) != '-') {
|
||||
$path = $last; // snag last argument, if it wasn't an option switch
|
||||
}
|
||||
}
|
||||
|
||||
if (is_dir($path)) {
|
||||
checkDirectoryContents($path);
|
||||
}
|
||||
elseif (is_file($path)) {
|
||||
checkFile($path);
|
||||
}
|
||||
else {
|
||||
echo "$path is not a file or directory.\n";
|
||||
showHelp() AND exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
if ($options['quiet']) {
|
||||
ob_end_clean();
|
||||
}
|
||||
|
||||
echo "\n$count files checked, " . count($errors) . ' errors.';
|
||||
echo "\n", implode($errors,'');
|
||||
|
||||
function checkDirectoryContents($dir) {
|
||||
global $options, $i, $errors, $count;
|
||||
|
||||
$contents = scandir($dir);
|
||||
foreach($contents as $content) {
|
||||
if ($content == '.' || $content == '..') {
|
||||
continue;
|
||||
}
|
||||
|
||||
$path = "$dir/$content";
|
||||
|
||||
// Recurse into directories
|
||||
if (is_dir($path) && $options['recurse']) {
|
||||
checkDirectoryContents($path);
|
||||
} // if is_dir
|
||||
else {
|
||||
checkFile($path);
|
||||
} // !is_dir
|
||||
} // foreach
|
||||
} // function checkDirectoryContents
|
||||
|
||||
function checkFile($path) {
|
||||
global $count, $errors;
|
||||
// echo "$path\n";
|
||||
|
||||
// Skip non-php files
|
||||
if (substr($path, -4) != '.php') {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (($count % 60 == 0)) {
|
||||
echo "\n";
|
||||
}
|
||||
|
||||
$error = `php -l $path 2>&1 1> /dev/null`;
|
||||
if ($error) {
|
||||
$errors[] = $error;
|
||||
echo 'E';
|
||||
}
|
||||
else {
|
||||
echo '.';
|
||||
}
|
||||
|
||||
$count++;
|
||||
}
|
||||
|
||||
|
||||
function getPipedFiles() {
|
||||
$files = array();
|
||||
stream_set_blocking(STDIN,FALSE);
|
||||
while ($line = trim(fgets(STDIN))) {
|
||||
$files[] = $line;
|
||||
}
|
||||
return $files;
|
||||
}
|
||||
|
||||
function setOptions($options) {
|
||||
$args = array_keys(getopt('qRh', array('quiet', 'recursive', 'help')));
|
||||
foreach ($args as $arg) {
|
||||
switch ($arg) {
|
||||
case 'q':
|
||||
case 'quiet':
|
||||
$options['quiet'] = true;
|
||||
break;
|
||||
|
||||
case 'R':
|
||||
case 'recursive':
|
||||
$options['recurse'] = true;
|
||||
break;
|
||||
|
||||
case 'h':
|
||||
case 'help':
|
||||
default:
|
||||
showHelp() AND exit(0);
|
||||
} // Switch
|
||||
} // Foreach args
|
||||
return $options;
|
||||
} // function setOptions
|
||||
|
||||
function showHelp() {
|
||||
echo <<<HELP
|
||||
usage: lint [-qR] [path]
|
||||
|
||||
options:
|
||||
-q, --quiet: disable verbose output
|
||||
-R, --recursive: recurse into subdirectories
|
||||
-h, --help: display this help screen
|
||||
|
||||
HELP;
|
||||
return true;
|
||||
}
|
|
@ -1,29 +1,60 @@
|
|||
{
|
||||
"name": "there4/markdown-resume",
|
||||
"description": "Generate a responsive CSS3 and HTML5 resume with Markdown, with optional PDF output.",
|
||||
"description": "Markdown Resume Generator",
|
||||
"homepage": "https://github.com/there4/markdown-resume",
|
||||
"keywords": [
|
||||
"markdown",
|
||||
"resume",
|
||||
"html5"
|
||||
],
|
||||
"license": "MIT",
|
||||
"version": "2.0.0",
|
||||
"selfupdatepath": "://github.com/there4/markdown-resume/raw/master/bin/md2resume",
|
||||
"selfupdateversion": "://github.com/there4/markdown-resume/raw/master/version",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Craig Davis",
|
||||
"email": "craig@there4development.com",
|
||||
"role": "Developer"
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"name": "Kaiwen Xu",
|
||||
"email": "kevin@kevxu.net",
|
||||
"role": "Contributor"
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"name": "ishitcno1",
|
||||
"role": "Contributor"
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"name": "Roland O'Leary",
|
||||
"role": "Contributor"
|
||||
}, {
|
||||
},
|
||||
{
|
||||
"name": "Abhishek Kandoi",
|
||||
"email": "abhikandoi2000@gmail.com",
|
||||
"role": "Contributor"
|
||||
}
|
||||
],
|
||||
"support": {
|
||||
"issues": "https://github.com/there4/markdown-resume/issues"
|
||||
},
|
||||
"minimum-stability": "dev",
|
||||
"require": {
|
||||
"kriswallsmith/assetic": "1.1.2",
|
||||
"leafo/lessphp": "v0.4.0",
|
||||
"michelf/php-markdown": "1.4.0",
|
||||
"michelf/php-smartypants": "1.6.0-beta1",
|
||||
"mustache/mustache": "2.5.1",
|
||||
"simple-html-dom/simple-html-dom": "1.5.0",
|
||||
"symfony/config": "v2.3.4",
|
||||
"symfony/console": "v2.3.4",
|
||||
"symfony/yaml": "v2.3.4",
|
||||
"twig/twig": "v1.13.2"
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"vendor/simple-html-dom/simple-html-dom/"
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,608 @@
|
|||
{
|
||||
"_readme": [
|
||||
"This file locks the dependencies of your project to a known state",
|
||||
"Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file"
|
||||
],
|
||||
"hash": "40e7ded8558afab5c3b481ec2d33dafe",
|
||||
"packages": [
|
||||
{
|
||||
"name": "kriswallsmith/assetic",
|
||||
"version": "v1.1.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/kriswallsmith/assetic.git",
|
||||
"reference": "735cffd3982c6e8cdebe292d5db39d077f65890f"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/kriswallsmith/assetic/zipball/735cffd3982c6e8cdebe292d5db39d077f65890f",
|
||||
"reference": "735cffd3982c6e8cdebe292d5db39d077f65890f",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.1",
|
||||
"symfony/process": "~2.1"
|
||||
},
|
||||
"require-dev": {
|
||||
"cssmin/cssmin": "*",
|
||||
"joliclic/javascript-packer": "*",
|
||||
"kamicane/packager": "*",
|
||||
"leafo/lessphp": "*",
|
||||
"leafo/scssphp": "*",
|
||||
"leafo/scssphp-compass": "*",
|
||||
"mrclay/minify": "*",
|
||||
"phpunit/phpunit": "~3.7",
|
||||
"ptachoire/cssembed": "*",
|
||||
"twig/twig": "~1.6"
|
||||
},
|
||||
"suggest": {
|
||||
"leafo/lessphp": "Assetic provides the integration with the lessphp LESS compiler",
|
||||
"leafo/scssphp": "Assetic provides the integration with the scssphp SCSS compiler",
|
||||
"leafo/scssphp-compass": "Assetic provides the integration with the SCSS compass plugin",
|
||||
"ptachoire/cssembed": "Assetic provides the integration with phpcssembed to embed data uris",
|
||||
"twig/twig": "Assetic provides the integration with the Twig templating engine"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.1-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Assetic": "src/"
|
||||
},
|
||||
"files": [
|
||||
"src/functions.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Kris Wallsmith",
|
||||
"email": "kris.wallsmith@gmail.com",
|
||||
"homepage": "http://kriswallsmith.net/"
|
||||
}
|
||||
],
|
||||
"description": "Asset Management for PHP",
|
||||
"homepage": "https://github.com/kriswallsmith/assetic",
|
||||
"keywords": [
|
||||
"assets",
|
||||
"compression",
|
||||
"minification"
|
||||
],
|
||||
"time": "2013-07-19 00:03:27"
|
||||
},
|
||||
{
|
||||
"name": "leafo/lessphp",
|
||||
"version": "v0.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/leafo/lessphp.git",
|
||||
"reference": "51f3f06f0fe78a722dabfd14578444bdd078d9de"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/leafo/lessphp/zipball/51f3f06f0fe78a722dabfd14578444bdd078d9de",
|
||||
"reference": "51f3f06f0fe78a722dabfd14578444bdd078d9de",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "0.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"classmap": [
|
||||
"lessc.inc.php"
|
||||
]
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT",
|
||||
"GPL-3.0"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Leaf Corcoran",
|
||||
"email": "leafot@gmail.com",
|
||||
"homepage": "http://leafo.net"
|
||||
}
|
||||
],
|
||||
"description": "lessphp is a compiler for LESS written in PHP.",
|
||||
"homepage": "http://leafo.net/lessphp/",
|
||||
"time": "2013-08-09 17:09:19"
|
||||
},
|
||||
{
|
||||
"name": "michelf/php-markdown",
|
||||
"version": "1.4.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/michelf/php-markdown.git",
|
||||
"reference": "96d8150406f67e683ef4acc09fef91785fef1266"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/michelf/php-markdown/zipball/96d8150406f67e683ef4acc09fef91785fef1266",
|
||||
"reference": "96d8150406f67e683ef4acc09fef91785fef1266",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-lib": "1.4.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Michelf": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michel Fortin",
|
||||
"email": "michel.fortin@michelf.ca",
|
||||
"homepage": "http://michelf.ca/",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "John Gruber",
|
||||
"homepage": "http://daringfireball.net/"
|
||||
}
|
||||
],
|
||||
"description": "PHP Markdown",
|
||||
"homepage": "http://michelf.ca/projects/php-markdown/",
|
||||
"keywords": [
|
||||
"markdown"
|
||||
],
|
||||
"time": "2013-11-29 17:09:24"
|
||||
},
|
||||
{
|
||||
"name": "michelf/php-smartypants",
|
||||
"version": "1.6.0-beta1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/michelf/php-smartypants.git",
|
||||
"reference": "c0465c6d4c5ab853c2fa45df6c10bce7e35cc137"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/michelf/php-smartypants/zipball/c0465c6d4c5ab853c2fa45df6c10bce7e35cc137",
|
||||
"reference": "c0465c6d4c5ab853c2fa45df6c10bce7e35cc137",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.0"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-lib": "1.6.x-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Michelf": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michel Fortin",
|
||||
"email": "michel.fortin@michelf.ca",
|
||||
"homepage": "http://michelf.ca/",
|
||||
"role": "Developer"
|
||||
},
|
||||
{
|
||||
"name": "John Gruber",
|
||||
"homepage": "http://daringfireball.net/"
|
||||
}
|
||||
],
|
||||
"description": "PHP SmartyPants",
|
||||
"homepage": "http://michelf.ca/projects/php-smartypants/",
|
||||
"keywords": [
|
||||
"dashes",
|
||||
"quotes",
|
||||
"spaces",
|
||||
"typographer",
|
||||
"typography"
|
||||
],
|
||||
"time": "2013-07-31 18:13:10"
|
||||
},
|
||||
{
|
||||
"name": "mustache/mustache",
|
||||
"version": "v2.5.1",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/bobthecow/mustache.php.git",
|
||||
"reference": "996c944fa2ddedddfaf0d276b913809d6a32fd85"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/bobthecow/mustache.php/zipball/996c944fa2ddedddfaf0d276b913809d6a32fd85",
|
||||
"reference": "996c944fa2ddedddfaf0d276b913809d6a32fd85",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2.4"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "*"
|
||||
},
|
||||
"type": "library",
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Mustache": "src/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Justin Hileman",
|
||||
"email": "justin@justinhileman.info",
|
||||
"homepage": "http://justinhileman.com"
|
||||
}
|
||||
],
|
||||
"description": "A Mustache implementation in PHP.",
|
||||
"homepage": "https://github.com/bobthecow/mustache.php",
|
||||
"keywords": [
|
||||
"mustache",
|
||||
"templating"
|
||||
],
|
||||
"time": "2014-01-09 00:36:09"
|
||||
},
|
||||
{
|
||||
"name": "simple-html-dom/simple-html-dom",
|
||||
"version": "1.5.0",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/Youpie/simple-html-dom.git",
|
||||
"reference": "961610576c460546677a635062e9d3d7b6dab745"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/Youpie/simple-html-dom/zipball/961610576c460546677a635062e9d3d7b6dab745",
|
||||
"reference": "961610576c460546677a635062e9d3d7b6dab745",
|
||||
"shasum": ""
|
||||
},
|
||||
"type": "library",
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "S.C. Chen",
|
||||
"email": "me578022@gmail.com",
|
||||
"homepage": "http://simplehtmldom.sourceforge.net/"
|
||||
}
|
||||
],
|
||||
"description": "A copy of the PHP Simple HTML DOM Parser project.",
|
||||
"time": "2013-05-14 22:27:35"
|
||||
},
|
||||
{
|
||||
"name": "symfony/config",
|
||||
"version": "v2.3.4",
|
||||
"target-dir": "Symfony/Component/Config",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/Config.git",
|
||||
"reference": "65a927c15ca5a911ba2fa277a5457fa8129505b0"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/Config/zipball/65a927c15ca5a911ba2fa277a5457fa8129505b0",
|
||||
"reference": "65a927c15ca5a911ba2fa277a5457fa8129505b0",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3",
|
||||
"symfony/filesystem": "~2.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Symfony\\Component\\Config\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Config Component",
|
||||
"homepage": "http://symfony.com",
|
||||
"time": "2013-08-06 05:49:23"
|
||||
},
|
||||
{
|
||||
"name": "symfony/console",
|
||||
"version": "v2.3.4",
|
||||
"target-dir": "Symfony/Component/Console",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/Console.git",
|
||||
"reference": "db78f8ff7fc9e28d25ff9a0bf6ddf9f0e35fbbe3"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/Console/zipball/db78f8ff7fc9e28d25ff9a0bf6ddf9f0e35fbbe3",
|
||||
"reference": "db78f8ff7fc9e28d25ff9a0bf6ddf9f0e35fbbe3",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"require-dev": {
|
||||
"symfony/event-dispatcher": "~2.1"
|
||||
},
|
||||
"suggest": {
|
||||
"symfony/event-dispatcher": ""
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Symfony\\Component\\Console\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Console Component",
|
||||
"homepage": "http://symfony.com",
|
||||
"time": "2013-08-17 16:34:49"
|
||||
},
|
||||
{
|
||||
"name": "symfony/filesystem",
|
||||
"version": "dev-master",
|
||||
"target-dir": "Symfony/Component/Filesystem",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/Filesystem.git",
|
||||
"reference": "e81f1b30eb9748c3f8e0de3a92ea210845cff0a9"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/Filesystem/zipball/e81f1b30eb9748c3f8e0de3a92ea210845cff0a9",
|
||||
"reference": "e81f1b30eb9748c3f8e0de3a92ea210845cff0a9",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.5-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Symfony\\Component\\Filesystem\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Filesystem Component",
|
||||
"homepage": "http://symfony.com",
|
||||
"time": "2014-01-07 13:29:57"
|
||||
},
|
||||
{
|
||||
"name": "symfony/process",
|
||||
"version": "dev-master",
|
||||
"target-dir": "Symfony/Component/Process",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/Process.git",
|
||||
"reference": "d4b086ca4d6e192d8c2c64fe011159c8bc4c9daa"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/Process/zipball/d4b086ca4d6e192d8c2c64fe011159c8bc4c9daa",
|
||||
"reference": "d4b086ca4d6e192d8c2c64fe011159c8bc4c9daa",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.5-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Symfony\\Component\\Process\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Process Component",
|
||||
"homepage": "http://symfony.com",
|
||||
"time": "2014-01-07 13:29:57"
|
||||
},
|
||||
{
|
||||
"name": "symfony/yaml",
|
||||
"version": "v2.3.4",
|
||||
"target-dir": "Symfony/Component/Yaml",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/symfony/Yaml.git",
|
||||
"reference": "5a279f1b5f5e1045a6c432354d9ea727ff3a9847"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/symfony/Yaml/zipball/5a279f1b5f5e1045a6c432354d9ea727ff3a9847",
|
||||
"reference": "5a279f1b5f5e1045a6c432354d9ea727ff3a9847",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.3.3"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "2.3-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Symfony\\Component\\Yaml\\": ""
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"MIT"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Symfony Community",
|
||||
"homepage": "http://symfony.com/contributors"
|
||||
}
|
||||
],
|
||||
"description": "Symfony Yaml Component",
|
||||
"homepage": "http://symfony.com",
|
||||
"time": "2013-08-24 15:26:22"
|
||||
},
|
||||
{
|
||||
"name": "twig/twig",
|
||||
"version": "v1.13.2",
|
||||
"source": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/fabpot/Twig.git",
|
||||
"reference": "6d6a1009427d1f398c9d40904147bf9f723d5755"
|
||||
},
|
||||
"dist": {
|
||||
"type": "zip",
|
||||
"url": "https://api.github.com/repos/fabpot/Twig/zipball/6d6a1009427d1f398c9d40904147bf9f723d5755",
|
||||
"reference": "6d6a1009427d1f398c9d40904147bf9f723d5755",
|
||||
"shasum": ""
|
||||
},
|
||||
"require": {
|
||||
"php": ">=5.2.4"
|
||||
},
|
||||
"type": "library",
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.13-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-0": {
|
||||
"Twig_": "lib/"
|
||||
}
|
||||
},
|
||||
"notification-url": "https://packagist.org/downloads/",
|
||||
"license": [
|
||||
"BSD-3-Clause"
|
||||
],
|
||||
"authors": [
|
||||
{
|
||||
"name": "Fabien Potencier",
|
||||
"email": "fabien@symfony.com"
|
||||
},
|
||||
{
|
||||
"name": "Armin Ronacher",
|
||||
"email": "armin.ronacher@active-4.com"
|
||||
}
|
||||
],
|
||||
"description": "Twig, the flexible, fast, and secure template language for PHP",
|
||||
"homepage": "http://twig.sensiolabs.org",
|
||||
"keywords": [
|
||||
"templating"
|
||||
],
|
||||
"time": "2013-08-03 15:35:31"
|
||||
}
|
||||
],
|
||||
"packages-dev": [
|
||||
|
||||
],
|
||||
"aliases": [
|
||||
|
||||
],
|
||||
"minimum-stability": "dev",
|
||||
"stability-flags": {
|
||||
"michelf/php-smartypants": 10
|
||||
},
|
||||
"platform": [
|
||||
|
||||
],
|
||||
"platform-dev": [
|
||||
|
||||
]
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
# Craig Davis
|
||||
## Senior PHP Developer, UX Director
|
||||
|
||||
> [Download PDF](resume.pdf)
|
||||
> [craig@there4development.com](craig@there4development.com)
|
||||
> (999) 888-7777
|
||||
|
||||
------
|
||||
|
||||
### Profile {#profile}
|
||||
|
||||
Progressively evolve cross-platform ideas before impactful infomediaries. Energistically visualize tactical initiatives before cross-media catalysts for change.
|
||||
|
||||
------
|
||||
|
||||
### Skills {#skills}
|
||||
|
||||
* Web Design
|
||||
: Assertively exploit wireless initiatives rather than synergistic core competencies.
|
||||
|
||||
* Interface Design
|
||||
: Credibly streamline mission-critical value with multifunctional functionalities.
|
||||
|
||||
* Project Direction
|
||||
: Proven ability to lead and manage a wide variety of design and development projects in team and independent situations.
|
||||
|
||||
-------
|
||||
|
||||
### Technical {#technical}
|
||||
|
||||
1. XHTML
|
||||
1. CSS
|
||||
1. Javascript
|
||||
1. Jquery
|
||||
1. PHP
|
||||
1. CVS / Subversion
|
||||
1. OS X
|
||||
1. Windows XP/Vista
|
||||
1. Linux
|
||||
|
||||
------
|
||||
|
||||
### Experience {#experience}
|
||||
|
||||
Initrode Conglomerated
|
||||
: *Principal and Creative Lead*
|
||||
__2004-2005__
|
||||
Intrinsicly transform flexible manufactured products without excellent intellectual capital. Energistically evisculate orthogonal architectures through covalent action items. Assertively incentivize sticky platforms without synergistic materials.
|
||||
|
||||
Gizmonic Institute Company (GIM)
|
||||
: *Lead Web Designer*
|
||||
__2001-2004__
|
||||
Globally re-engineer cross-media schemas through viral methods of empowerment. Proactively grow long-term high-impact human capital and highly efficient innovation. Intrinsicly iterate excellent e-tailers with timely e-markets.
|
||||
|
||||
|
||||
Initrode Conglomerated
|
||||
: *Principal and Creative Lead*
|
||||
__2004-2005__
|
||||
Intrinsicly transform flexible manufactured products without excellent intellectual capital. Energistically evisculate orthogonal architectures through covalent action items. Assertively incentivize sticky platforms without synergistic materials.
|
||||
|
||||
Gizmonic Institute Company (GIM)
|
||||
: *Lead Web Designer*
|
||||
__2001-2004__
|
||||
Globally re-engineer cross-media schemas through viral methods of empowerment. Proactively grow long-term high-impact human capital and highly efficient innovation. Intrinsicly iterate excellent e-tailers with timely e-markets.
|
||||
|
||||
|
||||
Initrode Conglomerated
|
||||
: *Principal and Creative Lead*
|
||||
__2004-2005__
|
||||
Intrinsicly transform flexible manufactured products without excellent intellectual capital. Energistically evisculate orthogonal architectures through covalent action items. Assertively incentivize sticky platforms without synergistic materials.
|
||||
|
||||
Gizmonic Institute Company (GIM)
|
||||
: *Lead Web Designer*
|
||||
__2001-2004__
|
||||
Globally re-engineer cross-media schemas through viral methods of empowerment. Proactively grow long-term high-impact human capital and highly efficient innovation. Intrinsicly iterate excellent e-tailers with timely e-markets.
|
||||
|
||||
|
||||
Initrode Conglomerated
|
||||
: *Principal and Creative Lead*
|
||||
__2004-2005__
|
||||
Intrinsicly transform flexible manufactured products without excellent intellectual capital. Energistically evisculate orthogonal architectures through covalent action items. Assertively incentivize sticky platforms without synergistic materials.
|
||||
|
||||
Gizmonic Institute Company (GIM)
|
||||
: *Lead Web Designer*
|
||||
__2001-2004__
|
||||
Globally re-engineer cross-media schemas through viral methods of empowerment. Proactively grow long-term high-impact human capital and highly efficient innovation. Intrinsicly iterate excellent e-tailers with timely e-markets.
|
||||
|
||||
|
||||
Initrode Conglomerated
|
||||
: *Principal and Creative Lead*
|
||||
__2004-2005__
|
||||
Intrinsicly transform flexible manufactured products without excellent intellectual capital. Energistically evisculate orthogonal architectures through covalent action items. Assertively incentivize sticky platforms without synergistic materials.
|
||||
|
||||
Gizmonic Institute Company (GIM)
|
||||
: *Lead Web Designer*
|
||||
__2001-2004__
|
||||
Globally re-engineer cross-media schemas through viral methods of empowerment. Proactively grow long-term high-impact human capital and highly efficient innovation. Intrinsicly iterate excellent e-tailers with timely e-markets.
|
||||
|
||||
|
||||
Initrode Conglomerated
|
||||
: *Principal and Creative Lead*
|
||||
__2004-2005__
|
||||
Intrinsicly transform flexible manufactured products without excellent intellectual capital. Energistically evisculate orthogonal architectures through covalent action items. Assertively incentivize sticky platforms without synergistic materials.
|
||||
|
||||
Gizmonic Institute Company (GIM)
|
||||
: *Lead Web Designer*
|
||||
__2001-2004__
|
||||
Globally re-engineer cross-media schemas through viral methods of empowerment. Proactively grow long-term high-impact human capital and highly efficient innovation. Intrinsicly iterate excellent e-tailers with timely e-markets.
|
||||
|
||||
|
||||
Initrode Conglomerated
|
||||
: *Principal and Creative Lead*
|
||||
__2004-2005__
|
||||
Intrinsicly transform flexible manufactured products without excellent intellectual capital. Energistically evisculate orthogonal architectures through covalent action items. Assertively incentivize sticky platforms without synergistic materials.
|
||||
|
||||
Gizmonic Institute Company (GIM)
|
||||
: *Lead Web Designer*
|
||||
__2001-2004__
|
||||
Globally re-engineer cross-media schemas through viral methods of empowerment. Proactively grow long-term high-impact human capital and highly efficient innovation. Intrinsicly iterate excellent e-tailers with timely e-markets.
|
||||
|
||||
------
|
||||
|
||||
### Footer {#footer}
|
||||
|
||||
Craig Davis -- [craig@there4development.com](craig@there4development.com) -- (999) 888-7777
|
||||
|
||||
------
|
|
@ -0,0 +1,32 @@
|
|||
<?php
|
||||
error_reporting(E_ALL | E_STRICT);
|
||||
|
||||
// If the dependencies aren't installed, we have to bail and offer some help.
|
||||
if (!file_exists(__DIR__ . '/vendor/autoload.php')) {
|
||||
exit("\nPlease run `composer install` to install dependencies.\n\n");
|
||||
}
|
||||
|
||||
// Bootstrap our application with the Composer autoloader
|
||||
$app = require __DIR__ . '/vendor/autoload.php';
|
||||
|
||||
// Setup the namespace for our own namespace
|
||||
$app->add('Resume', __DIR__ . '/src');
|
||||
|
||||
// Instantiate our Console application
|
||||
$console = new Resume\Cli\Resume();
|
||||
|
||||
// If we're running from phar, we get these values from the stub
|
||||
if (!defined("IN_PHAR")) {
|
||||
$project = json_decode(file_get_contents(__DIR__ . '/composer.json'));
|
||||
}
|
||||
|
||||
$templatePath = __DIR__ . '/templates';
|
||||
$consoleTemplatePath = __DIR__ . '/src/Resume/Templates';
|
||||
|
||||
// Init the app with these params
|
||||
$console->initialize($templatePath, $consoleTemplatePath, $project);
|
||||
|
||||
// Execute the console app.
|
||||
$console->run();
|
||||
|
||||
/* End of resume.php */
|
|
@ -0,0 +1,121 @@
|
|||
<?php
|
||||
|
||||
pake_desc('Run the unit tests');
|
||||
pake_task('test');
|
||||
|
||||
pake_desc('Check the code for psr2 standards');
|
||||
pake_task('sniff');
|
||||
|
||||
pake_desc('Run php-cs-fixer on the src directory');
|
||||
pake_task('fixer');
|
||||
|
||||
pake_desc('Update the README with the latest command output');
|
||||
pake_task('readme');
|
||||
|
||||
pake_desc('Build phar file');
|
||||
pake_task('phar');
|
||||
|
||||
pake_desc('PHP Lint the src folder');
|
||||
pake_task('lint');
|
||||
|
||||
pake_desc('Display the version');
|
||||
pake_task('version');
|
||||
|
||||
pake_desc('Create the selfupdate version file');
|
||||
pake_task('version_file');
|
||||
|
||||
pake_desc('Copy to ~/bin');
|
||||
pake_task('mv');
|
||||
|
||||
pake_desc('Build the app for deployment');
|
||||
pake_task('build', 'version', 'version_file', 'readme', 'lint', 'fixer', 'sniff', 'phar');
|
||||
|
||||
pake_alias('default', 'build');
|
||||
|
||||
function run_build() {}
|
||||
|
||||
function run_test() {
|
||||
passthru("phpunit");
|
||||
}
|
||||
|
||||
function run_version() {
|
||||
$composer = json_decode(file_get_contents('composer.json'));
|
||||
echo "\n Building Markdown Resume Builder version " . $composer->version . "\n";
|
||||
echo str_repeat("=", 80) . "\n";
|
||||
}
|
||||
|
||||
function run_version_file() {
|
||||
// Find the latest tag
|
||||
$version = trim(shell_exec('git describe --abbrev=0 --tags'));
|
||||
// Write it to the version file for the self update command
|
||||
file_put_contents('./version', $version);
|
||||
// Write it to the composer.json file as well
|
||||
$config = json_decode(file_get_contents('composer.json'));
|
||||
$config->version = $version;
|
||||
file_put_contents('composer.json', json_encode($config, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES));
|
||||
}
|
||||
|
||||
function run_lint() {
|
||||
echo "\n * Linting files\n";
|
||||
passthru("./build/lint -R ./src");
|
||||
}
|
||||
|
||||
function run_phar()
|
||||
{
|
||||
echo " * Construction phar and moving to ./bin/md2resume\n";
|
||||
$command =
|
||||
'rm -f ./bin/md2resume && rm -f ./bin/md2resume.phar &&'
|
||||
. 'php -dphar.readonly=0 build/empir make ./bin/md2resume.phar md2resume_dev.php . --exclude="'
|
||||
. '*.git/*|*.gitignore|*test*|*Tests*|*.md|*/doc/*|*.lock|*token.txt|pakefile'
|
||||
. '|.*|build/*|*.markdown|*.phar|*LICENSE|*AUTHORS|*CHANGELOG|*.dist|*.tpl|.travis.yml'
|
||||
. '" && chmod a+x ./bin/md2resume.phar'
|
||||
. ' && mv ./bin/md2resume.phar ./bin/md2resume';
|
||||
passthru($command);
|
||||
}
|
||||
|
||||
function run_sniff()
|
||||
{
|
||||
echo " * Checking files for PSR2\n";
|
||||
passthru("phpcs -p --standard=PSR2 ./src/ ./md2resume_dev.php");
|
||||
}
|
||||
|
||||
function run_fixer()
|
||||
{
|
||||
echo "\n * Running php-cs-fixer\n";
|
||||
passthru(
|
||||
"php-cs-fixer fix ./md2resume_dev.php"
|
||||
. " && php-cs-fixer fix ./src/Resume/Cli/"
|
||||
. " && php-cs-fixer fix ./src/Resume/Command/"
|
||||
);
|
||||
}
|
||||
|
||||
function run_readme()
|
||||
{
|
||||
echo " * Updating README documentation\n";
|
||||
$readme = file("README.md");
|
||||
$help = explode("\n", shell_exec("php ./md2resume_dev.php list --no-interaction"));
|
||||
|
||||
$helpStart = $helpEnd = 0;
|
||||
foreach ($readme as $lineNumber => $line) {
|
||||
if (trim($line) == "## Help") {
|
||||
$helpStart = $lineNumber;
|
||||
continue;
|
||||
}
|
||||
if ($helpStart && (substr(trim($line), 0, 2) == "##")) {
|
||||
$helpEnd = $lineNumber;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
$output = join(array_slice($readme, 0, $helpStart + 1));
|
||||
$output .= "\n " . implode("\n ", $help) . "\n";
|
||||
$output .= join(array_slice($readme, $helpEnd));
|
||||
|
||||
file_put_contents("README.md", $output);
|
||||
}
|
||||
|
||||
function run_mv() {
|
||||
exec('cp ./bin/md2resume ~/bin/md2resume');
|
||||
}
|
||||
|
||||
/* End of pakefile */
|
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<phpunit bootstrap="./tests/bootstrap.php" colors="true">
|
||||
<testsuites>
|
||||
<testsuite name="Markdown Resume Builder Test Suite">
|
||||
<directory suffix="Test.php">./tests/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
</phpunit>
|
|
@ -0,0 +1,144 @@
|
|||
<?php
|
||||
namespace Resume\Cli;
|
||||
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Formatter\OutputFormatterStyle;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Input\ArgvInput;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Symfony\Component\Console\Output\ConsoleOutput;
|
||||
use Resume\Cli;
|
||||
use Resume\Command;
|
||||
|
||||
class Resume extends Application
|
||||
{
|
||||
|
||||
public $defaultTemplate = 'modern';
|
||||
|
||||
public $recentCaseLimit = 10;
|
||||
|
||||
public function initialize($templatePath, $consoleTemplatePath, $project)
|
||||
{
|
||||
$runSetup = false;
|
||||
|
||||
// Add the composer information for use in version info and such.
|
||||
$this->project = $project;
|
||||
|
||||
// The absolute path to the html output templates
|
||||
$this->templatePath = $templatePath;
|
||||
|
||||
// https://github.com/symfony/Console/blob/master/Output/Output.php
|
||||
// the alternative is OutputInterface::OUTPUT_PLAIN;
|
||||
$this->outputFormat = OutputInterface::OUTPUT_NORMAL;
|
||||
|
||||
// We do this now because we've loaded the project info from the composer file
|
||||
$this->setName($this->project->description);
|
||||
$this->setVersion($this->project->version);
|
||||
|
||||
// Load our commands into the application
|
||||
$this->add(new Command\HtmlCommand());
|
||||
$this->add(new Command\PdfCommand());
|
||||
$this->add(new Command\SelfUpdateCommand());
|
||||
$this->add(new Command\TemplatesCommand());
|
||||
$this->add(new Command\VersionCommand());
|
||||
|
||||
// We'll use [Twig](http://twig.sensiolabs.org/) for template output
|
||||
$loader = new \Twig_Loader_Filesystem($consoleTemplatePath);
|
||||
$this->twig = new \Twig_Environment(
|
||||
$loader,
|
||||
array(
|
||||
"cache" => false,
|
||||
"autoescape" => false,
|
||||
"strict_variables" => false // SET TO TRUE WHILE DEBUGGING
|
||||
)
|
||||
);
|
||||
|
||||
// These are helpers that we use to format output on the cli: styling and padding and such
|
||||
$this->twig->addFilter('pad', new \Twig_Filter_Function("Resume\Cli\TwigFormatters::strpad"));
|
||||
$this->twig->addFilter('style', new \Twig_Filter_Function("Resume\Cli\TwigFormatters::style"));
|
||||
$this->twig->addFilter('repeat', new \Twig_Filter_Function("str_repeat"));
|
||||
$this->twig->addFilter('wrap', new \Twig_Filter_Function("wordwrap"));
|
||||
}
|
||||
|
||||
public function getLongVersion()
|
||||
{
|
||||
return parent::getLongVersion().' by <comment>Craig Davis</comment>';
|
||||
}
|
||||
|
||||
public function registerStyles(&$output)
|
||||
{
|
||||
// https://github.com/symfony/Console/blob/master/Formatter/OutputFormatterStyle.php
|
||||
// http://symfony.com/doc/2.0/components/console/introduction.html#coloring-the-output
|
||||
//
|
||||
// * <info></info> green
|
||||
// * <comment></comment> yellow
|
||||
// * <question></question> black text on a cyan background
|
||||
// * <alert></alert> yellow
|
||||
// * <error></error> white text on a red background
|
||||
// * <fire></fire> red text on a yellow background
|
||||
// * <notice></notice> blue
|
||||
// * <heading></heading> black on white
|
||||
|
||||
$style = new OutputFormatterStyle('red', 'yellow', array('bold'));
|
||||
$output->getFormatter()->setStyle('fire', $style);
|
||||
|
||||
$style = new OutputFormatterStyle('blue', 'black', array());
|
||||
$output->getFormatter()->setStyle('notice', $style);
|
||||
|
||||
$style = new OutputFormatterStyle('red', 'black', array('bold'));
|
||||
$output->getFormatter()->setStyle('alert', $style);
|
||||
|
||||
$style = new OutputFormatterStyle('white', 'black', array('bold'));
|
||||
$output->getFormatter()->setStyle('bold', $style);
|
||||
|
||||
$style = new OutputFormatterStyle('black', 'white', array());
|
||||
$output->getFormatter()->setStyle('heading', $style);
|
||||
|
||||
$style = new OutputFormatterStyle('blue', 'black', array('bold'));
|
||||
$output->getFormatter()->setStyle('logo', $style);
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
public function statusStyle($status)
|
||||
{
|
||||
switch (true) {
|
||||
case (strpos(strtolower($status), 'closed') === 0):
|
||||
return 'alert';
|
||||
case (strpos(strtolower($status), 'open') === 0):
|
||||
case (strpos(strtolower($status), 'active') === 0):
|
||||
return 'logo';
|
||||
// fallthrough to final return
|
||||
}
|
||||
|
||||
return "info";
|
||||
}
|
||||
|
||||
public function run(InputInterface $input = null, OutputInterface $output = null)
|
||||
{
|
||||
if (null === $input) {
|
||||
$input = new ArgvInput();
|
||||
}
|
||||
|
||||
if (null === $output) {
|
||||
$output = new ConsoleOutput();
|
||||
}
|
||||
|
||||
$this->registerStyles($output);
|
||||
|
||||
// Did they supply a command name?
|
||||
$name = $this->getCommandName($input);
|
||||
if ($name) {
|
||||
// Does the command exist and is not ambiguous?
|
||||
try {
|
||||
$command = $this->find($name);
|
||||
} catch (\Exception $e) {
|
||||
exit($e->getMessage() . "\n");
|
||||
}
|
||||
}
|
||||
|
||||
return parent::run($input, $output);
|
||||
}
|
||||
}
|
||||
|
||||
/* End of file Resume.php */
|
|
@ -0,0 +1,36 @@
|
|||
<?php
|
||||
namespace Resume\Cli;
|
||||
|
||||
class TwigFormatters
|
||||
{
|
||||
public static function strpad($string, $length, $position = "center")
|
||||
{
|
||||
switch ($position) {
|
||||
case "left":
|
||||
$padding = STR_PAD_RIGHT;
|
||||
break;
|
||||
case "right":
|
||||
$padding = STR_PAD_LEFT;
|
||||
break;
|
||||
case "center":
|
||||
default:
|
||||
$padding = STR_PAD_BOTH;
|
||||
}
|
||||
|
||||
// This must handle tagged strings for our Console formatting
|
||||
// <info>this is a long title</info>
|
||||
$total_length = strlen($string);
|
||||
$stripped_length = strlen(strip_tags($string));
|
||||
|
||||
$length = $length + $total_length - $stripped_length;
|
||||
|
||||
return str_pad(substr($string, 0, $length), $length, " ", $padding);
|
||||
}
|
||||
|
||||
public static function style($string, $format)
|
||||
{
|
||||
return sprintf('<%2$s>%1$s</%2$s>', $string, $format);
|
||||
}
|
||||
}
|
||||
|
||||
/* End of file TwigFormatters */
|
|
@ -0,0 +1,155 @@
|
|||
<?php
|
||||
namespace Resume\Command;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
use Assetic\Asset\AssetCollection;
|
||||
use Assetic\Asset\FileAsset;
|
||||
use Assetic\Filter;
|
||||
use Michelf\MarkdownExtra;
|
||||
use Michelf\SmartyPants;
|
||||
|
||||
class HtmlCommand extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
// resume html source.md resume.html -template blockish -refresh
|
||||
$this
|
||||
->setName('html')
|
||||
->setDescription('Generate an HTML resume from a markdown file')
|
||||
->addArgument(
|
||||
'source',
|
||||
InputArgument::REQUIRED,
|
||||
'Source markdown document'
|
||||
)
|
||||
->addArgument(
|
||||
'destination',
|
||||
InputArgument::REQUIRED,
|
||||
'Output destination folder'
|
||||
)
|
||||
->addOption(
|
||||
'template',
|
||||
't',
|
||||
InputOption::VALUE_OPTIONAL,
|
||||
'Which of the templates to use'
|
||||
)
|
||||
->addOption(
|
||||
'refresh',
|
||||
'r',
|
||||
InputOption::VALUE_NONE,
|
||||
'If set, the html will include a meta command to refresh the ' .
|
||||
'document every 5 seconds.'
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->app = $this->getApplication();
|
||||
$source = $input->getArgument('source');
|
||||
$destination = trim($input->getArgument('destination'), DIRECTORY_SEPARATOR);
|
||||
$template = $input->getOption('template');
|
||||
$refresh = $input->getOption('refresh');
|
||||
$destFilename = join(DIRECTORY_SEPARATOR, array($destination, pathinfo($source, PATHINFO_FILENAME) . '.html'));
|
||||
|
||||
$rendered = $this->generateHtml($source, $template, $refresh);
|
||||
file_put_contents($destFilename, $rendered);
|
||||
$output->writeln(
|
||||
sprintf(
|
||||
"Wrote resume to: <info>%s</info>",
|
||||
$destFilename
|
||||
),
|
||||
$this->app->outputFormat
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected function generateHtml($source, $template, $refresh)
|
||||
{
|
||||
// Check that the source file is sane
|
||||
if (!file_exists($source)) {
|
||||
$output->writeln(
|
||||
sprintf(
|
||||
"<error>Unable to open source file: %s</error>",
|
||||
$source
|
||||
),
|
||||
$this->app->outputFormat
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check that our template is sane, or set to the default one
|
||||
if (!$template) {
|
||||
$template = $this->app->defaultTemplate;
|
||||
}
|
||||
$templatePath = join(DIRECTORY_SEPARATOR, array($this->app->templatePath, basename($template)));
|
||||
$templateIndexPath = join(DIRECTORY_SEPARATOR, array($templatePath, 'index.html'));
|
||||
if (!file_exists($templateIndexPath)) {
|
||||
$output->writeln(
|
||||
sprintf(
|
||||
"<error>Unable to open template file: %s</error>",
|
||||
$templateIndexPath
|
||||
),
|
||||
$this->app->outputFormat
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
// We build these into a single string so that we can deploy this resume as a
|
||||
// single file.
|
||||
$cssAssetPath = join(DIRECTORY_SEPARATOR, array($templatePath, '/css'));
|
||||
$cssAssets = array();
|
||||
|
||||
// Our PHAR deployment can't handle the GlobAsset typically used here
|
||||
foreach (new \DirectoryIterator($cssAssetPath) as $fileInfo) {
|
||||
if ($fileInfo->isDot() || !$fileInfo->isFile()) {
|
||||
continue;
|
||||
}
|
||||
array_push($cssAssets, new FileAsset($fileInfo->getPathname()));
|
||||
}
|
||||
|
||||
$css = new AssetCollection(
|
||||
$cssAssets,
|
||||
array(new Filter\LessphpFilter())
|
||||
);
|
||||
|
||||
$style = $css->dump();
|
||||
|
||||
$templateContent = file_get_contents($templateIndexPath);
|
||||
$resumeContent = file_get_contents($source);
|
||||
|
||||
// Process with Markdown, and then use SmartyPants to clean up punctuation.
|
||||
$resumeHtml = MarkdownExtra::defaultTransform($resumeContent);
|
||||
$resumeHtml = SmartyPants::defaultTransform($resumeHtml);
|
||||
|
||||
// We'll construct the title for the html document from the h1 and h2 tags
|
||||
$simpleDom = new \simple_html_dom();
|
||||
$simpleDom->load($resumeHtml);
|
||||
$title = sprintf(
|
||||
'%s | %s',
|
||||
$simpleDom->find('h1', 0)->innertext,
|
||||
$simpleDom->find('h2', 0)->innertext
|
||||
);
|
||||
|
||||
// We'll now render the Markdown into an html file with Mustache Templates
|
||||
$m = new \Mustache_Engine;
|
||||
$rendered = $m->render(
|
||||
$templateContent,
|
||||
array(
|
||||
'title' => $title,
|
||||
'style' => $style,
|
||||
'resume' => $resumeHtml,
|
||||
'reload' => $refresh
|
||||
)
|
||||
);
|
||||
|
||||
return $rendered;
|
||||
}
|
||||
}
|
||||
|
||||
/* End of file HtmlCommand.php */
|
|
@ -0,0 +1,89 @@
|
|||
<?php
|
||||
namespace Resume\Command;
|
||||
|
||||
use Resume\Command\HtmlCommand;
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputOption;
|
||||
use Symfony\Component\Console\Input\InputArgument;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class PdfCommand extends HtmlCommand
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('pdf')
|
||||
->setDescription('Generate a PDF from a markdown file')
|
||||
->addArgument(
|
||||
'source',
|
||||
InputArgument::REQUIRED,
|
||||
'Source markdown document'
|
||||
)
|
||||
->addArgument(
|
||||
'destination',
|
||||
InputArgument::REQUIRED,
|
||||
'Output destination folder'
|
||||
)
|
||||
->addOption(
|
||||
'template',
|
||||
't',
|
||||
InputOption::VALUE_NONE,
|
||||
'Which of the templates to use'
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->app = $this->getApplication();
|
||||
$source = $input->getArgument('source');
|
||||
$destination = trim($input->getArgument('destination'), DIRECTORY_SEPARATOR);
|
||||
$template = $input->getOption('template');
|
||||
$pdfSource = join(DIRECTORY_SEPARATOR, array($destination, '.tmp_pdf_source.html'));
|
||||
$destFilename = join(DIRECTORY_SEPARATOR, array($destination, pathinfo($source, PATHINFO_FILENAME) . '.pdf'));
|
||||
|
||||
// Make sure we've got out converter available
|
||||
exec('wkhtmltopdf -V', $results, $returnVal);
|
||||
if ($returnVal) {
|
||||
$output->writeln(
|
||||
"\n<error>Error:</error> Unable to locate wkhtmltopdf.\n" .
|
||||
" Please make sure that it is installed and available in " .
|
||||
"your path. \n For installation help, please read: " .
|
||||
"https://github.com/pdfkit/pdfkit/wiki/Installing-WKHTMLTOPDF \n\n",
|
||||
$this->app->outputFormat
|
||||
);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$rendered = $this->generateHtml($source, $template, false);
|
||||
|
||||
// The pdf needs some extra css rules, and so we'll add them here
|
||||
// to our html document
|
||||
$simpleDom = new \simple_html_dom($rendered);
|
||||
$body = $simpleDom->find('body', 0);
|
||||
$body->class = $body->class . ' pdf';
|
||||
$rendered = (string) $simpleDom;
|
||||
|
||||
// Save to a temp destination for the pdf renderer to use
|
||||
file_put_contents($pdfSource, $rendered);
|
||||
|
||||
// Process the document with wkhtmltopdf
|
||||
exec('wkhtmltopdf ' . $pdfSource .' ' . $destFilename);
|
||||
|
||||
// Unlink the temporary file
|
||||
unlink($pdfSource);
|
||||
|
||||
$output->writeln(
|
||||
sprintf(
|
||||
"Wrote pdf resume to: <info>%s</info>",
|
||||
$destFilename
|
||||
),
|
||||
$this->app->outputFormat
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* End of file PdfCommand.php */
|
|
@ -0,0 +1,86 @@
|
|||
<?php
|
||||
namespace Resume\Command;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class SelfUpdateCommand extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('selfupdate')
|
||||
->setDescription('Updates md2resume.phar to the latest version.')
|
||||
->setHelp(
|
||||
<<<EOT
|
||||
The <info>self-update</info> command checks github for newer
|
||||
versions of the command line client and if found, installs the latest.
|
||||
|
||||
EOT
|
||||
);
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->app = $this->getApplication();
|
||||
$localFilename = realpath($_SERVER['argv'][0]) ?: $_SERVER['argv'][0];
|
||||
$tempFilename = dirname($localFilename) . '/' . basename($localFilename, '.phar').'-temp.phar';
|
||||
|
||||
if (substr($localFilename, -4) === '.php') {
|
||||
throw new \Exception('You must run this from the compiled phar file.');
|
||||
}
|
||||
|
||||
// check for permissions in local filesystem before start connection process
|
||||
if (!is_writable($tempDirectory = dirname($tempFilename))) {
|
||||
throw new \Exception(
|
||||
'Self update failed: the "' . $tempDirectory
|
||||
. '" directory used to download the temp file could not be written'
|
||||
);
|
||||
}
|
||||
|
||||
if (!is_writable($localFilename)) {
|
||||
throw new \Exception(
|
||||
'Self update failed: the "' . $localFilename . '" file could not be written'
|
||||
);
|
||||
}
|
||||
|
||||
$protocol = extension_loaded('openssl') ? 'https' : 'http';
|
||||
$latest = trim(file_get_contents($protocol . $this->app->project->selfupdateversion, false));
|
||||
|
||||
if ($this->app->project->version !== $latest) {
|
||||
$output->writeln(sprintf("Updating to version <info>%s</info>.", $latest));
|
||||
|
||||
$remoteFilename = $protocol . $this->app->project->selfupdatepath;
|
||||
|
||||
$phar = file_get_contents($remoteFilename);
|
||||
file_put_contents($tempFilename, $phar);
|
||||
|
||||
if (!file_exists($tempFilename)) {
|
||||
$output->writeln('<error>The download of the new version failed for an unexpected reason</error>');
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
try {
|
||||
@chmod($tempFilename, 0777 & ~umask());
|
||||
// test the phar validity
|
||||
$phar = new \Phar($tempFilename);
|
||||
// free the variable to unlock the file
|
||||
unset($phar);
|
||||
rename($tempFilename, $localFilename);
|
||||
} catch (\Exception $e) {
|
||||
@unlink($tempFilename);
|
||||
if (!$e instanceof \UnexpectedValueException && !$e instanceof \PharException) {
|
||||
throw $e;
|
||||
}
|
||||
$output->writeln('<error>The download is corrupted ('.$e->getMessage().').</error>');
|
||||
$output->writeln('<error>Please re-run the self-update command to try again.</error>');
|
||||
}
|
||||
} else {
|
||||
$output->writeln("<info>You are using the latest version.</info>");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* End of file SelfUpdateCommand.php */
|
|
@ -0,0 +1,35 @@
|
|||
<?php
|
||||
namespace Resume\Command;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class TemplatesCommand extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('templates')
|
||||
->setDescription('List available templates');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->app = $this->getApplication();
|
||||
$tplData = array('templates' => array());
|
||||
foreach (glob($this->app->templatePath . '/*', GLOB_ONLYDIR) as $dir) {
|
||||
$tplData['templates'][] = (object) array(
|
||||
'name' => basename($dir),
|
||||
'description' => file_exists($dir . '/description.txt')
|
||||
? trim(file_get_contents($dir . '/description.txt'))
|
||||
: 'No description available'
|
||||
);
|
||||
}
|
||||
$template = $this->app->twig->loadTemplate('templates.twig');
|
||||
$view = $template->render($tplData);
|
||||
$output->write($view, true, $this->app->outputFormat);
|
||||
}
|
||||
}
|
||||
|
||||
/* End of file TemplatesCommand.php */
|
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
namespace Resume\Command;
|
||||
|
||||
use Symfony\Component\Console\Command\Command;
|
||||
use Symfony\Component\Console\Input\InputInterface;
|
||||
use Symfony\Component\Console\Output\OutputInterface;
|
||||
|
||||
class VersionCommand extends Command
|
||||
{
|
||||
protected function configure()
|
||||
{
|
||||
$this
|
||||
->setName('version')
|
||||
->setDescription('Show current version information');
|
||||
}
|
||||
|
||||
protected function execute(InputInterface $input, OutputInterface $output)
|
||||
{
|
||||
$this->app = $this->getApplication();
|
||||
$output->writeln($this->app->project->version, $this->app->outputFormat);
|
||||
}
|
||||
}
|
||||
|
||||
/* End of file VersionCommand.php */
|
|
@ -0,0 +1,9 @@
|
|||
————————————————————————————————————————————————————————————————————————————————
|
||||
<heading> Available Templates </heading>
|
||||
————————————————————————————————————————————————————————————————————————————————
|
||||
{% for template in templates %}
|
||||
{{template.name|style("info")|pad(15, "left")}}{{template.description}}
|
||||
{% endfor %}
|
||||
{% if templates|length == 0%}
|
||||
<notice>There are no templates available</notice>
|
||||
{% endif %}
|
|
@ -0,0 +1 @@
|
|||
Blocky and bold colors
|
|
@ -0,0 +1 @@
|
|||
Modern and clean layout (default)
|
|
@ -0,0 +1 @@
|
|||
Unstyled, useful as a base for your own templates
|
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Tester\CommandTester;
|
||||
|
||||
class ListCommandTest extends \ResumeTest
|
||||
{
|
||||
public function testExecute()
|
||||
{
|
||||
$command = $this->console->find('list');
|
||||
$commandTester = new CommandTester($command);
|
||||
$commandTester->execute(array(
|
||||
'command' => $command->getName()
|
||||
));
|
||||
$this->assertRegExp('/Available commands/', $commandTester->getDisplay());
|
||||
$this->assertRegExp('/Options/', $commandTester->getDisplay());
|
||||
$this->assertRegExp('/list/', $commandTester->getDisplay());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* End of file ListCommandTest.php */
|
|
@ -0,0 +1,20 @@
|
|||
<?php
|
||||
|
||||
use Symfony\Component\Console\Application;
|
||||
use Symfony\Component\Console\Tester\CommandTester;
|
||||
|
||||
class VersionCommandTest extends \ResumeTest
|
||||
{
|
||||
public function testExecute()
|
||||
{
|
||||
$command = $this->console->find('version');
|
||||
$commandTester = new CommandTester($command);
|
||||
$commandTester->execute(array(
|
||||
'command' => $command->getName()
|
||||
));
|
||||
$this->assertEquals($this->console->project->version, trim($commandTester->getDisplay()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/* End of file VersionCommandTest.php */
|
|
@ -0,0 +1,23 @@
|
|||
<?php
|
||||
|
||||
$app = require __DIR__ . '/../vendor/autoload.php';
|
||||
$app->add('Resume', __DIR__ . '/../src');
|
||||
|
||||
use Resume\Cli\Resume;
|
||||
|
||||
class ResumeTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
|
||||
public $console;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$templatePath = realpath(__DIR__ . '/../templates/');
|
||||
$consoleTemplatePath = realpath(__DIR__ . '/../src/Resume/Templates');
|
||||
$project = json_decode(file_get_contents(__DIR__ . '/../composer.json'));
|
||||
$this->console = new Resume();
|
||||
$this->console->initialize($templatePath, $consoleTemplatePath, $project);
|
||||
}
|
||||
}
|
||||
|
||||
/* End file bootstrap.php */
|
|
@ -1,163 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Asset;
|
||||
|
||||
use Assetic\Cache\CacheInterface;
|
||||
use Assetic\Filter\FilterInterface;
|
||||
|
||||
/**
|
||||
* Caches an asset to avoid the cost of loading and dumping.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class AssetCache implements AssetInterface
|
||||
{
|
||||
private $asset;
|
||||
private $cache;
|
||||
|
||||
public function __construct(AssetInterface $asset, CacheInterface $cache)
|
||||
{
|
||||
$this->asset = $asset;
|
||||
$this->cache = $cache;
|
||||
}
|
||||
|
||||
public function ensureFilter(FilterInterface $filter)
|
||||
{
|
||||
$this->asset->ensureFilter($filter);
|
||||
}
|
||||
|
||||
public function getFilters()
|
||||
{
|
||||
return $this->asset->getFilters();
|
||||
}
|
||||
|
||||
public function clearFilters()
|
||||
{
|
||||
$this->asset->clearFilters();
|
||||
}
|
||||
|
||||
public function load(FilterInterface $additionalFilter = null)
|
||||
{
|
||||
$cacheKey = self::getCacheKey($this->asset, $additionalFilter, 'load');
|
||||
if ($this->cache->has($cacheKey)) {
|
||||
$this->asset->setContent($this->cache->get($cacheKey));
|
||||
return;
|
||||
}
|
||||
|
||||
$this->asset->load($additionalFilter);
|
||||
$this->cache->set($cacheKey, $this->asset->getContent());
|
||||
}
|
||||
|
||||
public function dump(FilterInterface $additionalFilter = null)
|
||||
{
|
||||
$cacheKey = self::getCacheKey($this->asset, $additionalFilter, 'dump');
|
||||
if ($this->cache->has($cacheKey)) {
|
||||
return $this->cache->get($cacheKey);
|
||||
}
|
||||
|
||||
$content = $this->asset->dump($additionalFilter);
|
||||
$this->cache->set($cacheKey, $content);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
return $this->asset->getContent();
|
||||
}
|
||||
|
||||
public function setContent($content)
|
||||
{
|
||||
$this->asset->setContent($content);
|
||||
}
|
||||
|
||||
public function getSourceRoot()
|
||||
{
|
||||
return $this->asset->getSourceRoot();
|
||||
}
|
||||
|
||||
public function getSourcePath()
|
||||
{
|
||||
return $this->asset->getSourcePath();
|
||||
}
|
||||
|
||||
public function getTargetPath()
|
||||
{
|
||||
return $this->asset->getTargetPath();
|
||||
}
|
||||
|
||||
public function setTargetPath($targetPath)
|
||||
{
|
||||
$this->asset->setTargetPath($targetPath);
|
||||
}
|
||||
|
||||
public function getLastModified()
|
||||
{
|
||||
return $this->asset->getLastModified();
|
||||
}
|
||||
|
||||
public function getVars()
|
||||
{
|
||||
return $this->asset->getVars();
|
||||
}
|
||||
|
||||
public function setValues(array $values)
|
||||
{
|
||||
$this->asset->setValues($values);
|
||||
}
|
||||
|
||||
public function getValues()
|
||||
{
|
||||
return $this->asset->getValues();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a cache key for the current asset.
|
||||
*
|
||||
* The key is composed of everything but an asset's content:
|
||||
*
|
||||
* * source root
|
||||
* * source path
|
||||
* * target url
|
||||
* * last modified
|
||||
* * filters
|
||||
*
|
||||
* @param AssetInterface $asset The asset
|
||||
* @param FilterInterface $additionalFilter Any additional filter being applied
|
||||
* @param string $salt Salt for the key
|
||||
*
|
||||
* @return string A key for identifying the current asset
|
||||
*/
|
||||
static private function getCacheKey(AssetInterface $asset, FilterInterface $additionalFilter = null, $salt = '')
|
||||
{
|
||||
if ($additionalFilter) {
|
||||
$asset = clone $asset;
|
||||
$asset->ensureFilter($additionalFilter);
|
||||
}
|
||||
|
||||
$cacheKey = $asset->getSourceRoot();
|
||||
$cacheKey .= $asset->getSourcePath();
|
||||
$cacheKey .= $asset->getTargetPath();
|
||||
$cacheKey .= $asset->getLastModified();
|
||||
|
||||
foreach ($asset->getFilters() as $filter) {
|
||||
$cacheKey .= serialize($filter);
|
||||
}
|
||||
|
||||
if ($values = $asset->getValues()) {
|
||||
asort($values);
|
||||
$cacheKey .= serialize($values);
|
||||
}
|
||||
|
||||
return md5($cacheKey.$salt);
|
||||
}
|
||||
}
|
|
@ -1,217 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Asset;
|
||||
|
||||
use Assetic\Asset\Iterator\AssetCollectionFilterIterator;
|
||||
use Assetic\Asset\Iterator\AssetCollectionIterator;
|
||||
use Assetic\Filter\FilterCollection;
|
||||
use Assetic\Filter\FilterInterface;
|
||||
|
||||
/**
|
||||
* A collection of assets.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class AssetCollection implements \IteratorAggregate, AssetCollectionInterface
|
||||
{
|
||||
private $assets;
|
||||
private $filters;
|
||||
private $sourceRoot;
|
||||
private $targetPath;
|
||||
private $content;
|
||||
private $clones;
|
||||
private $vars;
|
||||
private $values;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $assets Assets for the current collection
|
||||
* @param array $filters Filters for the current collection
|
||||
* @param string $sourceRoot The root directory
|
||||
*/
|
||||
public function __construct($assets = array(), $filters = array(), $sourceRoot = null, array $vars = array())
|
||||
{
|
||||
$this->assets = array();
|
||||
foreach ($assets as $asset) {
|
||||
$this->add($asset);
|
||||
}
|
||||
|
||||
$this->filters = new FilterCollection($filters);
|
||||
$this->sourceRoot = $sourceRoot;
|
||||
$this->clones = new \SplObjectStorage();
|
||||
$this->vars = $vars;
|
||||
$this->values = array();
|
||||
}
|
||||
|
||||
public function all()
|
||||
{
|
||||
return $this->assets;
|
||||
}
|
||||
|
||||
public function add(AssetInterface $asset)
|
||||
{
|
||||
$this->assets[] = $asset;
|
||||
}
|
||||
|
||||
public function removeLeaf(AssetInterface $needle, $graceful = false)
|
||||
{
|
||||
foreach ($this->assets as $i => $asset) {
|
||||
$clone = isset($this->clones[$asset]) ? $this->clones[$asset] : null;
|
||||
if (in_array($needle, array($asset, $clone), true)) {
|
||||
unset($this->clones[$asset], $this->assets[$i]);
|
||||
return true;
|
||||
} elseif ($asset instanceof AssetCollectionInterface && $asset->removeLeaf($needle, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($graceful) {
|
||||
return false;
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('Leaf not found.');
|
||||
}
|
||||
|
||||
public function replaceLeaf(AssetInterface $needle, AssetInterface $replacement, $graceful = false)
|
||||
{
|
||||
foreach ($this->assets as $i => $asset) {
|
||||
$clone = isset($this->clones[$asset]) ? $this->clones[$asset] : null;
|
||||
if (in_array($needle, array($asset, $clone), true)) {
|
||||
unset($this->clones[$asset]);
|
||||
$this->assets[$i] = $replacement;
|
||||
return true;
|
||||
} elseif ($asset instanceof AssetCollectionInterface && $asset->replaceLeaf($needle, $replacement, true)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if ($graceful) {
|
||||
return false;
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('Leaf not found.');
|
||||
}
|
||||
|
||||
public function ensureFilter(FilterInterface $filter)
|
||||
{
|
||||
$this->filters->ensure($filter);
|
||||
}
|
||||
|
||||
public function getFilters()
|
||||
{
|
||||
return $this->filters->all();
|
||||
}
|
||||
|
||||
public function clearFilters()
|
||||
{
|
||||
$this->filters->clear();
|
||||
}
|
||||
|
||||
public function load(FilterInterface $additionalFilter = null)
|
||||
{
|
||||
// loop through leaves and load each asset
|
||||
$parts = array();
|
||||
foreach ($this as $asset) {
|
||||
$asset->load($additionalFilter);
|
||||
$parts[] = $asset->getContent();
|
||||
}
|
||||
|
||||
$this->content = implode("\n", $parts);
|
||||
}
|
||||
|
||||
public function dump(FilterInterface $additionalFilter = null)
|
||||
{
|
||||
// loop through leaves and dump each asset
|
||||
$parts = array();
|
||||
foreach ($this as $asset) {
|
||||
$parts[] = $asset->dump($additionalFilter);
|
||||
}
|
||||
|
||||
return implode("\n", $parts);
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function setContent($content)
|
||||
{
|
||||
$this->content = $content;
|
||||
}
|
||||
|
||||
public function getSourceRoot()
|
||||
{
|
||||
return $this->sourceRoot;
|
||||
}
|
||||
|
||||
public function getSourcePath()
|
||||
{
|
||||
}
|
||||
|
||||
public function getTargetPath()
|
||||
{
|
||||
return $this->targetPath;
|
||||
}
|
||||
|
||||
public function setTargetPath($targetPath)
|
||||
{
|
||||
$this->targetPath = $targetPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the highest last-modified value of all assets in the current collection.
|
||||
*
|
||||
* @return integer|null A UNIX timestamp
|
||||
*/
|
||||
public function getLastModified()
|
||||
{
|
||||
if (!count($this->assets)) {
|
||||
return;
|
||||
}
|
||||
|
||||
$mapper = function (AssetInterface $asset)
|
||||
{
|
||||
return $asset->getLastModified();
|
||||
};
|
||||
|
||||
return max(array_map($mapper, $this->assets));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator for looping recursively over unique leaves.
|
||||
*/
|
||||
public function getIterator()
|
||||
{
|
||||
return new \RecursiveIteratorIterator(new AssetCollectionFilterIterator(new AssetCollectionIterator($this, $this->clones)));
|
||||
}
|
||||
|
||||
public function getVars()
|
||||
{
|
||||
return $this->vars;
|
||||
}
|
||||
|
||||
public function setValues(array $values)
|
||||
{
|
||||
$this->values = $values;
|
||||
|
||||
foreach ($this as $asset) {
|
||||
$asset->setValues(array_intersect_key($values, array_flip($asset->getVars())));
|
||||
}
|
||||
}
|
||||
|
||||
public function getValues()
|
||||
{
|
||||
return $this->values;
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Asset;
|
||||
|
||||
/**
|
||||
* An asset collection.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
interface AssetCollectionInterface extends AssetInterface, \Traversable
|
||||
{
|
||||
/**
|
||||
* Returns all child assets.
|
||||
*
|
||||
* @return array An array of AssetInterface objects
|
||||
*/
|
||||
function all();
|
||||
|
||||
/**
|
||||
* Adds an asset to the current collection.
|
||||
*
|
||||
* @param AssetInterface $asset An asset
|
||||
*/
|
||||
function add(AssetInterface $asset);
|
||||
|
||||
/**
|
||||
* Removes a leaf.
|
||||
*
|
||||
* @param AssetInterface $needle The leaf to remove
|
||||
*
|
||||
* @throws InvalidArgumentException If the asset cannot be found
|
||||
*/
|
||||
function removeLeaf(AssetInterface $leaf);
|
||||
|
||||
/**
|
||||
* Replaces an existing leaf with a new one.
|
||||
*
|
||||
* @param AssetInterface $needle The current asset to replace
|
||||
* @param AssetInterface $replacement The new asset
|
||||
*
|
||||
* @throws InvalidArgumentException If the asset cannot be found
|
||||
*/
|
||||
function replaceLeaf(AssetInterface $needle, AssetInterface $replacement);
|
||||
}
|
|
@ -1,156 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Asset;
|
||||
|
||||
use Assetic\Filter\FilterInterface;
|
||||
|
||||
/**
|
||||
* An asset has a mutable URL and content and can be loaded and dumped.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
interface AssetInterface
|
||||
{
|
||||
/**
|
||||
* Ensures the current asset includes the supplied filter.
|
||||
*
|
||||
* @param FilterInterface $filter A filter
|
||||
*/
|
||||
function ensureFilter(FilterInterface $filter);
|
||||
|
||||
/**
|
||||
* Returns an array of filters currently applied.
|
||||
*
|
||||
* @return array An array of filters
|
||||
*/
|
||||
function getFilters();
|
||||
|
||||
/**
|
||||
* Clears all filters from the current asset.
|
||||
*/
|
||||
function clearFilters();
|
||||
|
||||
/**
|
||||
* Loads the asset into memory and applies load filters.
|
||||
*
|
||||
* You may provide an additional filter to apply during load.
|
||||
*
|
||||
* @param FilterInterface $additionalFilter An additional filter
|
||||
*/
|
||||
function load(FilterInterface $additionalFilter = null);
|
||||
|
||||
/**
|
||||
* Applies dump filters and returns the asset as a string.
|
||||
*
|
||||
* You may provide an additional filter to apply during dump.
|
||||
*
|
||||
* Dumping an asset should not change its state.
|
||||
*
|
||||
* If the current asset has not been loaded yet, it should be
|
||||
* automatically loaded at this time.
|
||||
*
|
||||
* @param FilterInterface $additionalFilter An additional filter
|
||||
*
|
||||
* @return string The filtered content of the current asset
|
||||
*/
|
||||
function dump(FilterInterface $additionalFilter = null);
|
||||
|
||||
/**
|
||||
* Returns the loaded content of the current asset.
|
||||
*
|
||||
* @return string The content
|
||||
*/
|
||||
function getContent();
|
||||
|
||||
/**
|
||||
* Sets the content of the current asset.
|
||||
*
|
||||
* Filters can use this method to change the content of the asset.
|
||||
*
|
||||
* @param string $content The asset content
|
||||
*/
|
||||
function setContent($content);
|
||||
|
||||
/**
|
||||
* Returns an absolute path or URL to the source asset's root directory.
|
||||
*
|
||||
* This value should be an absolute path to a directory in the filesystem,
|
||||
* an absolute URL with no path, or null.
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* * '/path/to/web'
|
||||
* * 'http://example.com'
|
||||
* * null
|
||||
*
|
||||
* @return string|null The asset's root
|
||||
*/
|
||||
function getSourceRoot();
|
||||
|
||||
/**
|
||||
* Returns the relative path for the source asset.
|
||||
*
|
||||
* This value can be combined with the asset's source root (if both are
|
||||
* non-null) to get something compatible with file_get_contents().
|
||||
*
|
||||
* For example:
|
||||
*
|
||||
* * 'js/main.js'
|
||||
* * 'main.js'
|
||||
* * null
|
||||
*
|
||||
* @return string|null The source asset path
|
||||
*/
|
||||
function getSourcePath();
|
||||
|
||||
/**
|
||||
* Returns the URL for the current asset.
|
||||
*
|
||||
* @return string|null A web URL where the asset will be dumped
|
||||
*/
|
||||
function getTargetPath();
|
||||
|
||||
/**
|
||||
* Sets the URL for the current asset.
|
||||
*
|
||||
* @param string $targetPath A web URL where the asset will be dumped
|
||||
*/
|
||||
function setTargetPath($targetPath);
|
||||
|
||||
/**
|
||||
* Returns the time the current asset was last modified.
|
||||
*
|
||||
* @return integer|null A UNIX timestamp
|
||||
*/
|
||||
function getLastModified();
|
||||
|
||||
/**
|
||||
* Returns an array of variable names for this asset.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function getVars();
|
||||
|
||||
/**
|
||||
* Sets the values for the asset's variables.
|
||||
*
|
||||
* @param array $values
|
||||
*/
|
||||
function setValues(array $values);
|
||||
|
||||
/**
|
||||
* Returns the current values for this asset.
|
||||
*
|
||||
* @return array an array of strings
|
||||
*/
|
||||
function getValues();
|
||||
}
|
|
@ -1,134 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Asset;
|
||||
|
||||
use Assetic\AssetManager;
|
||||
use Assetic\Filter\FilterCollection;
|
||||
use Assetic\Filter\FilterInterface;
|
||||
|
||||
/**
|
||||
* A reference to an asset in the asset manager.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class AssetReference implements AssetInterface
|
||||
{
|
||||
private $am;
|
||||
private $name;
|
||||
private $filters = array();
|
||||
|
||||
public function __construct(AssetManager $am, $name)
|
||||
{
|
||||
$this->am = $am;
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function ensureFilter(FilterInterface $filter)
|
||||
{
|
||||
$this->filters[] = $filter;
|
||||
}
|
||||
|
||||
public function getFilters()
|
||||
{
|
||||
$this->flushFilters();
|
||||
|
||||
return $this->callAsset(__FUNCTION__);
|
||||
}
|
||||
|
||||
public function clearFilters()
|
||||
{
|
||||
$this->filters = array();
|
||||
$this->callAsset(__FUNCTION__);
|
||||
}
|
||||
|
||||
public function load(FilterInterface $additionalFilter = null)
|
||||
{
|
||||
$this->flushFilters();
|
||||
|
||||
return $this->callAsset(__FUNCTION__, array($additionalFilter));
|
||||
}
|
||||
|
||||
public function dump(FilterInterface $additionalFilter = null)
|
||||
{
|
||||
$this->flushFilters();
|
||||
|
||||
return $this->callAsset(__FUNCTION__, array($additionalFilter));
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
return $this->callAsset(__FUNCTION__);
|
||||
}
|
||||
|
||||
public function setContent($content)
|
||||
{
|
||||
$this->callAsset(__FUNCTION__, array($content));
|
||||
}
|
||||
|
||||
public function getSourceRoot()
|
||||
{
|
||||
return $this->callAsset(__FUNCTION__);
|
||||
}
|
||||
|
||||
public function getSourcePath()
|
||||
{
|
||||
return $this->callAsset(__FUNCTION__);
|
||||
}
|
||||
|
||||
public function getTargetPath()
|
||||
{
|
||||
return $this->callAsset(__FUNCTION__);
|
||||
}
|
||||
|
||||
public function setTargetPath($targetPath)
|
||||
{
|
||||
$this->callAsset(__FUNCTION__, array($targetPath));
|
||||
}
|
||||
|
||||
public function getLastModified()
|
||||
{
|
||||
return $this->callAsset(__FUNCTION__);
|
||||
}
|
||||
|
||||
public function getVars()
|
||||
{
|
||||
return $this->callAsset(__FUNCTION__);
|
||||
}
|
||||
|
||||
public function getValues()
|
||||
{
|
||||
return $this->callAsset(__FUNCTION__);
|
||||
}
|
||||
|
||||
public function setValues(array $values)
|
||||
{
|
||||
$this->callAsset(__FUNCTION__, array($values));
|
||||
}
|
||||
|
||||
// private
|
||||
|
||||
private function callAsset($method, $arguments = array())
|
||||
{
|
||||
$asset = $this->am->get($this->name);
|
||||
|
||||
return call_user_func_array(array($asset, $method), $arguments);
|
||||
}
|
||||
|
||||
private function flushFilters()
|
||||
{
|
||||
$asset = $this->am->get($this->name);
|
||||
|
||||
while ($filter = array_shift($this->filters)) {
|
||||
$asset->ensureFilter($filter);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,169 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Asset;
|
||||
|
||||
use Assetic\Filter\FilterCollection;
|
||||
use Assetic\Filter\FilterInterface;
|
||||
|
||||
/**
|
||||
* A base abstract asset.
|
||||
*
|
||||
* The methods load() and getLastModified() are left undefined, although a
|
||||
* reusable doLoad() method is available to child classes.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
abstract class BaseAsset implements AssetInterface
|
||||
{
|
||||
private $filters;
|
||||
private $sourceRoot;
|
||||
private $sourcePath;
|
||||
private $targetPath;
|
||||
private $content;
|
||||
private $loaded;
|
||||
private $vars;
|
||||
private $values;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param array $filters Filters for the asset
|
||||
*/
|
||||
public function __construct($filters = array(), $sourceRoot = null, $sourcePath = null, array $vars = array())
|
||||
{
|
||||
$this->filters = new FilterCollection($filters);
|
||||
$this->sourceRoot = $sourceRoot;
|
||||
$this->sourcePath = $sourcePath;
|
||||
$this->vars = $vars;
|
||||
$this->values = array();
|
||||
$this->loaded = false;
|
||||
}
|
||||
|
||||
public function __clone()
|
||||
{
|
||||
$this->filters = clone $this->filters;
|
||||
}
|
||||
|
||||
public function ensureFilter(FilterInterface $filter)
|
||||
{
|
||||
$this->filters->ensure($filter);
|
||||
}
|
||||
|
||||
public function getFilters()
|
||||
{
|
||||
return $this->filters->all();
|
||||
}
|
||||
|
||||
public function clearFilters()
|
||||
{
|
||||
$this->filters->clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Encapsulates asset loading logic.
|
||||
*
|
||||
* @param string $content The asset content
|
||||
* @param FilterInterface $additionalFilter An additional filter
|
||||
*/
|
||||
protected function doLoad($content, FilterInterface $additionalFilter = null)
|
||||
{
|
||||
$filter = clone $this->filters;
|
||||
if ($additionalFilter) {
|
||||
$filter->ensure($additionalFilter);
|
||||
}
|
||||
|
||||
$asset = clone $this;
|
||||
$asset->setContent($content);
|
||||
|
||||
$filter->filterLoad($asset);
|
||||
$this->content = $asset->getContent();
|
||||
|
||||
$this->loaded = true;
|
||||
}
|
||||
|
||||
public function dump(FilterInterface $additionalFilter = null)
|
||||
{
|
||||
if (!$this->loaded) {
|
||||
$this->load();
|
||||
}
|
||||
|
||||
$filter = clone $this->filters;
|
||||
if ($additionalFilter) {
|
||||
$filter->ensure($additionalFilter);
|
||||
}
|
||||
|
||||
$asset = clone $this;
|
||||
$filter->filterDump($asset);
|
||||
|
||||
return $asset->getContent();
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function setContent($content)
|
||||
{
|
||||
$this->content = $content;
|
||||
}
|
||||
|
||||
public function getSourceRoot()
|
||||
{
|
||||
return $this->sourceRoot;
|
||||
}
|
||||
|
||||
public function getSourcePath()
|
||||
{
|
||||
return $this->sourcePath;
|
||||
}
|
||||
|
||||
public function getTargetPath()
|
||||
{
|
||||
return $this->targetPath;
|
||||
}
|
||||
|
||||
public function setTargetPath($targetPath)
|
||||
{
|
||||
if ($this->vars) {
|
||||
foreach ($this->vars as $var) {
|
||||
if (false === strpos($targetPath, $var)) {
|
||||
throw new \RuntimeException(sprintf('The asset target path "%s" must contain the variable "{%s}".', $targetPath, $var));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->targetPath = $targetPath;
|
||||
}
|
||||
|
||||
public function getVars()
|
||||
{
|
||||
return $this->vars;
|
||||
}
|
||||
|
||||
public function setValues(array $values)
|
||||
{
|
||||
foreach ($values as $var => $v) {
|
||||
if (!in_array($var, $this->vars, true)) {
|
||||
throw new \InvalidArgumentException(sprintf('The asset with source path "%s" has no variable named "%s".', $this->sourcePath, $var));
|
||||
}
|
||||
}
|
||||
|
||||
$this->values = $values;
|
||||
$this->loaded = false;
|
||||
}
|
||||
|
||||
public function getValues()
|
||||
{
|
||||
return $this->values;
|
||||
}
|
||||
}
|
|
@ -1,78 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Asset;
|
||||
|
||||
use Assetic\Util\PathUtils;
|
||||
use Assetic\Filter\FilterInterface;
|
||||
|
||||
/**
|
||||
* Represents an asset loaded from a file.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class FileAsset extends BaseAsset
|
||||
{
|
||||
private $source;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $source An absolute path
|
||||
* @param array $filters An array of filters
|
||||
* @param string $sourceRoot The source asset root directory
|
||||
* @param string $sourcePath The source asset path
|
||||
*
|
||||
* @throws InvalidArgumentException If the supplied root doesn't match the source when guessing the path
|
||||
*/
|
||||
public function __construct($source, $filters = array(), $sourceRoot = null, $sourcePath = null, array $vars = array())
|
||||
{
|
||||
if (null === $sourceRoot) {
|
||||
$sourceRoot = dirname($source);
|
||||
if (null === $sourcePath) {
|
||||
$sourcePath = basename($source);
|
||||
}
|
||||
} elseif (null === $sourcePath) {
|
||||
if (0 !== strpos($source, $sourceRoot)) {
|
||||
throw new \InvalidArgumentException(sprintf('The source "%s" is not in the root directory "%s"', $source, $sourceRoot));
|
||||
}
|
||||
|
||||
$sourcePath = substr($source, strlen($sourceRoot) + 1);
|
||||
}
|
||||
|
||||
$this->source = $source;
|
||||
|
||||
parent::__construct($filters, $sourceRoot, $sourcePath, $vars);
|
||||
}
|
||||
|
||||
public function load(FilterInterface $additionalFilter = null)
|
||||
{
|
||||
$source = PathUtils::resolvePath($this->source, $this->getVars(),
|
||||
$this->getValues());
|
||||
|
||||
if (!is_file($source)) {
|
||||
throw new \RuntimeException(sprintf('The source file "%s" does not exist.', $source));
|
||||
}
|
||||
|
||||
$this->doLoad(file_get_contents($source), $additionalFilter);
|
||||
}
|
||||
|
||||
public function getLastModified()
|
||||
{
|
||||
$source = PathUtils::resolvePath($this->source, $this->getVars(),
|
||||
$this->getValues());
|
||||
|
||||
if (!is_file($source)) {
|
||||
throw new \RuntimeException(sprintf('The source file "%s" does not exist.', $source));
|
||||
}
|
||||
return filemtime($source);
|
||||
}
|
||||
}
|
|
@ -1,111 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Asset;
|
||||
|
||||
use Assetic\Util\PathUtils;
|
||||
|
||||
use Assetic\Filter\FilterInterface;
|
||||
|
||||
/**
|
||||
* A collection of assets loaded by glob.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class GlobAsset extends AssetCollection
|
||||
{
|
||||
private $globs;
|
||||
private $initialized;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string|array $globs A single glob path or array of paths
|
||||
* @param array $filters An array of filters
|
||||
* @param string $root The root directory
|
||||
*/
|
||||
public function __construct($globs, $filters = array(), $root = null, array $vars = array())
|
||||
{
|
||||
$this->globs = (array) $globs;
|
||||
$this->initialized = false;
|
||||
|
||||
parent::__construct(array(), $filters, $root, $vars);
|
||||
}
|
||||
|
||||
public function all()
|
||||
{
|
||||
if (!$this->initialized) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
return parent::all();
|
||||
}
|
||||
|
||||
public function load(FilterInterface $additionalFilter = null)
|
||||
{
|
||||
if (!$this->initialized) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
parent::load($additionalFilter);
|
||||
}
|
||||
|
||||
public function dump(FilterInterface $additionalFilter = null)
|
||||
{
|
||||
if (!$this->initialized) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
return parent::dump($additionalFilter);
|
||||
}
|
||||
|
||||
public function getLastModified()
|
||||
{
|
||||
if (!$this->initialized) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
return parent::getLastModified();
|
||||
}
|
||||
|
||||
public function getIterator()
|
||||
{
|
||||
if (!$this->initialized) {
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
return parent::getIterator();
|
||||
}
|
||||
|
||||
public function setValues(array $values)
|
||||
{
|
||||
parent::setValues($values);
|
||||
$this->initialized = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the collection based on the glob(s) passed in.
|
||||
*/
|
||||
private function initialize()
|
||||
{
|
||||
foreach ($this->globs as $glob) {
|
||||
$glob = PathUtils::resolvePath($glob, $this->getVars(), $this->getValues());
|
||||
|
||||
if (false !== $paths = glob($glob)) {
|
||||
foreach ($paths as $path) {
|
||||
$this->add(new FileAsset($path, array(), $this->getSourceRoot()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->initialized = true;
|
||||
}
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Asset;
|
||||
|
||||
use Assetic\Util\PathUtils;
|
||||
|
||||
use Assetic\Filter\FilterInterface;
|
||||
|
||||
/**
|
||||
* Represents an asset loaded via an HTTP request.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class HttpAsset extends BaseAsset
|
||||
{
|
||||
private $sourceUrl;
|
||||
private $ignoreErrors;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $sourceUrl The source URL
|
||||
* @param array $filters An array of filters
|
||||
*
|
||||
* @throws InvalidArgumentException If the first argument is not an URL
|
||||
*/
|
||||
public function __construct($sourceUrl, $filters = array(), $ignoreErrors = false, array $vars = array())
|
||||
{
|
||||
if (0 === strpos($sourceUrl, '//')) {
|
||||
$sourceUrl = 'http:'.$sourceUrl;
|
||||
} elseif (false === strpos($sourceUrl, '://')) {
|
||||
throw new \InvalidArgumentException(sprintf('"%s" is not a valid URL.', $sourceUrl));
|
||||
}
|
||||
|
||||
$this->sourceUrl = $sourceUrl;
|
||||
$this->ignoreErrors = $ignoreErrors;
|
||||
|
||||
list($scheme, $url) = explode('://', $sourceUrl, 2);
|
||||
list($host, $path) = explode('/', $url, 2);
|
||||
|
||||
parent::__construct($filters, $scheme.'://'.$host, $path, $vars);
|
||||
}
|
||||
|
||||
public function load(FilterInterface $additionalFilter = null)
|
||||
{
|
||||
if (false === $content = @file_get_contents(PathUtils::resolvePath(
|
||||
$this->sourceUrl, $this->getVars(), $this->getValues()))) {
|
||||
if ($this->ignoreErrors) {
|
||||
return;
|
||||
} else {
|
||||
throw new \RuntimeException(sprintf('Unable to load asset from URL "%s"', $this->sourceUrl));
|
||||
}
|
||||
}
|
||||
|
||||
$this->doLoad($content, $additionalFilter);
|
||||
}
|
||||
|
||||
public function getLastModified()
|
||||
{
|
||||
if (false !== @file_get_contents($this->sourceUrl, false, stream_context_create(array('http' => array('method' => 'HEAD'))))) {
|
||||
foreach ($http_response_header as $header) {
|
||||
if (0 === stripos($header, 'Last-Modified: ')) {
|
||||
list(, $mtime) = explode(':', $header, 2);
|
||||
|
||||
return strtotime(trim($mtime));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Asset\Iterator;
|
||||
|
||||
/**
|
||||
* Asset collection filter iterator.
|
||||
*
|
||||
* The filter iterator is responsible for de-duplication of leaf assets based
|
||||
* on both strict equality and source URL.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class AssetCollectionFilterIterator extends \RecursiveFilterIterator
|
||||
{
|
||||
private $visited;
|
||||
private $sources;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param AssetCollectionIterator $iterator The inner iterator
|
||||
* @param array $visited An array of visited asset objects
|
||||
* @param array $sources An array of visited source strings
|
||||
*/
|
||||
public function __construct(AssetCollectionIterator $iterator, array $visited = array(), array $sources = array())
|
||||
{
|
||||
parent::__construct($iterator);
|
||||
|
||||
$this->visited = $visited;
|
||||
$this->sources = $sources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the current asset is a duplicate.
|
||||
*
|
||||
* De-duplication is performed based on either strict equality or by
|
||||
* matching sources.
|
||||
*
|
||||
* @return Boolean Returns true if we have not seen this asset yet
|
||||
*/
|
||||
public function accept()
|
||||
{
|
||||
$asset = $this->getInnerIterator()->current(true);
|
||||
$duplicate = false;
|
||||
|
||||
// check strict equality
|
||||
if (in_array($asset, $this->visited, true)) {
|
||||
$duplicate = true;
|
||||
} else {
|
||||
$this->visited[] = $asset;
|
||||
}
|
||||
|
||||
// check source
|
||||
$sourceRoot = $asset->getSourceRoot();
|
||||
$sourcePath = $asset->getSourcePath();
|
||||
if ($sourceRoot && $sourcePath) {
|
||||
$source = $sourceRoot.'/'.$sourcePath;
|
||||
if (in_array($source, $this->sources)) {
|
||||
$duplicate = true;
|
||||
} else {
|
||||
$this->sources[] = $source;
|
||||
}
|
||||
}
|
||||
|
||||
return !$duplicate;
|
||||
}
|
||||
|
||||
/**
|
||||
* Passes visited objects and source URLs to the child iterator.
|
||||
*/
|
||||
public function getChildren()
|
||||
{
|
||||
return new self($this->getInnerIterator()->getChildren(), $this->visited, $this->sources);
|
||||
}
|
||||
}
|
|
@ -1,109 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Asset\Iterator;
|
||||
|
||||
use Assetic\Asset\AssetCollectionInterface;
|
||||
|
||||
/**
|
||||
* Iterates over an asset collection.
|
||||
*
|
||||
* The iterator is responsible for cascading filters and target URL patterns
|
||||
* from parent to child assets.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class AssetCollectionIterator implements \RecursiveIterator
|
||||
{
|
||||
private $assets;
|
||||
private $filters;
|
||||
private $output;
|
||||
private $clones;
|
||||
|
||||
public function __construct(AssetCollectionInterface $coll, \SplObjectStorage $clones)
|
||||
{
|
||||
$this->assets = $coll->all();
|
||||
$this->filters = $coll->getFilters();
|
||||
$this->output = $coll->getTargetPath();
|
||||
$this->clones = $clones;
|
||||
|
||||
if (false === $pos = strpos($this->output, '.')) {
|
||||
$this->output .= '_*';
|
||||
} else {
|
||||
$this->output = substr($this->output, 0, $pos).'_*'.substr($this->output, $pos);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a copy of the current asset with filters and a target URL applied.
|
||||
*
|
||||
* @param Boolean $raw Returns the unmodified asset if true
|
||||
*/
|
||||
public function current($raw = false)
|
||||
{
|
||||
$asset = current($this->assets);
|
||||
|
||||
if ($raw) {
|
||||
return $asset;
|
||||
}
|
||||
|
||||
// clone once
|
||||
if (!isset($this->clones[$asset])) {
|
||||
$clone = $this->clones[$asset] = clone $asset;
|
||||
|
||||
// generate a target path based on asset name
|
||||
$name = sprintf('%s_%d', pathinfo($asset->getSourcePath(), PATHINFO_FILENAME) ?: 'part', $this->key() + 1);
|
||||
$clone->setTargetPath(str_replace('*', $name, $this->output));
|
||||
} else {
|
||||
$clone = $this->clones[$asset];
|
||||
}
|
||||
|
||||
// cascade filters
|
||||
foreach ($this->filters as $filter) {
|
||||
$clone->ensureFilter($filter);
|
||||
}
|
||||
|
||||
return $clone;
|
||||
}
|
||||
|
||||
public function key()
|
||||
{
|
||||
return key($this->assets);
|
||||
}
|
||||
|
||||
public function next()
|
||||
{
|
||||
return next($this->assets);
|
||||
}
|
||||
|
||||
public function rewind()
|
||||
{
|
||||
return reset($this->assets);
|
||||
}
|
||||
|
||||
public function valid()
|
||||
{
|
||||
return false !== current($this->assets);
|
||||
}
|
||||
|
||||
public function hasChildren()
|
||||
{
|
||||
return current($this->assets) instanceof AssetCollectionInterface;
|
||||
}
|
||||
|
||||
/**
|
||||
* @uses current()
|
||||
*/
|
||||
public function getChildren()
|
||||
{
|
||||
return new self($this->current(), $this->clones);
|
||||
}
|
||||
}
|
|
@ -1,55 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Asset;
|
||||
|
||||
use Assetic\Filter\FilterInterface;
|
||||
|
||||
/**
|
||||
* Represents a string asset.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class StringAsset extends BaseAsset
|
||||
{
|
||||
private $content;
|
||||
private $lastModified;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $content The content of the asset
|
||||
* @param array $filters Filters for the asset
|
||||
* @param string $sourceRoot The source asset root directory
|
||||
* @param string $sourcePath The source asset path
|
||||
*/
|
||||
public function __construct($content, $filters = array(), $sourceRoot = null, $sourcePath = null)
|
||||
{
|
||||
$this->content = $content;
|
||||
|
||||
parent::__construct($filters, $sourceRoot, $sourcePath);
|
||||
}
|
||||
|
||||
public function load(FilterInterface $additionalFilter = null)
|
||||
{
|
||||
$this->doLoad($this->content, $additionalFilter);
|
||||
}
|
||||
|
||||
public function setLastModified($lastModified)
|
||||
{
|
||||
$this->lastModified = $lastModified;
|
||||
}
|
||||
|
||||
public function getLastModified()
|
||||
{
|
||||
return $this->lastModified;
|
||||
}
|
||||
}
|
|
@ -1,79 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
|
||||
/**
|
||||
* Manages assets.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class AssetManager
|
||||
{
|
||||
private $assets = array();
|
||||
|
||||
/**
|
||||
* Gets an asset by name.
|
||||
*
|
||||
* @param string $name The asset name
|
||||
*
|
||||
* @return AssetInterface The asset
|
||||
*
|
||||
* @throws InvalidArgumentException If there is no asset by that name
|
||||
*/
|
||||
public function get($name)
|
||||
{
|
||||
if (!isset($this->assets[$name])) {
|
||||
throw new \InvalidArgumentException(sprintf('There is no "%s" asset.', $name));
|
||||
}
|
||||
|
||||
return $this->assets[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current asset manager has a certain asset.
|
||||
*
|
||||
* @param string $name an asset name
|
||||
*
|
||||
* @return Boolean True if the asset has been set, false if not
|
||||
*/
|
||||
public function has($name)
|
||||
{
|
||||
return isset($this->assets[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers an asset to the current asset manager.
|
||||
*
|
||||
* @param string $name The asset name
|
||||
* @param AssetInterface $asset The asset
|
||||
*/
|
||||
public function set($name, AssetInterface $asset)
|
||||
{
|
||||
if (!ctype_alnum(str_replace('_', '', $name))) {
|
||||
throw new \InvalidArgumentException(sprintf('The name "%s" is invalid.', $name));
|
||||
}
|
||||
|
||||
$this->assets[$name] = $asset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of asset names.
|
||||
*
|
||||
* @return array An array of asset names
|
||||
*/
|
||||
public function getNames()
|
||||
{
|
||||
return array_keys($this->assets);
|
||||
}
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic;
|
||||
|
||||
use Assetic\Util\PathUtils;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
|
||||
/**
|
||||
* Writes assets to the filesystem.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class AssetWriter
|
||||
{
|
||||
private $dir;
|
||||
private $varValues;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $dir The base web directory
|
||||
*/
|
||||
public function __construct($dir, array $varValues = array())
|
||||
{
|
||||
foreach ($varValues as $var => $values) {
|
||||
foreach ($values as $value) {
|
||||
if (!is_string($value)) {
|
||||
throw new \InvalidArgumentException(sprintf('All variable values must be strings, but got %s for variable "%s".', json_encode($value), $var));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$this->dir = $dir;
|
||||
$this->varValues = $varValues;
|
||||
}
|
||||
|
||||
public function writeManagerAssets(AssetManager $am)
|
||||
{
|
||||
foreach ($am->getNames() as $name) {
|
||||
$this->writeAsset($am->get($name));
|
||||
}
|
||||
}
|
||||
|
||||
public function writeAsset(AssetInterface $asset)
|
||||
{
|
||||
foreach ($this->getCombinations($asset->getVars()) as $combination) {
|
||||
$asset->setValues($combination);
|
||||
|
||||
static::write($this->dir.'/'.PathUtils::resolvePath(
|
||||
$asset->getTargetPath(), $asset->getVars(), $asset->getValues()),
|
||||
$asset->dump());
|
||||
}
|
||||
}
|
||||
|
||||
private function getCombinations(array $vars)
|
||||
{
|
||||
if (!$vars) {
|
||||
return array(array());
|
||||
}
|
||||
|
||||
$combinations = array();
|
||||
$nbValues = array();
|
||||
foreach ($this->varValues as $var => $values) {
|
||||
if (!in_array($var, $vars, true)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$nbValues[$var] = count($values);
|
||||
}
|
||||
|
||||
for ($i=array_product($nbValues),$c=$i*2; $i<$c; $i++) {
|
||||
$k = $i;
|
||||
$combination = array();
|
||||
|
||||
foreach ($vars as $var) {
|
||||
$combination[$var] = $this->varValues[$var][$k % $nbValues[$var]];
|
||||
$k = intval($k/$nbValues[$var]);
|
||||
}
|
||||
|
||||
$combinations[] = $combination;
|
||||
}
|
||||
|
||||
return $combinations;
|
||||
}
|
||||
|
||||
static protected function write($path, $contents)
|
||||
{
|
||||
if (!is_dir($dir = dirname($path)) && false === @mkdir($dir, 0777, true)) {
|
||||
throw new \RuntimeException('Unable to create directory '.$dir);
|
||||
}
|
||||
|
||||
if (false === @file_put_contents($path, $contents)) {
|
||||
throw new \RuntimeException('Unable to write file '.$path);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Cache;
|
||||
|
||||
/**
|
||||
* Interface for a cache backend.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
interface CacheInterface
|
||||
{
|
||||
/**
|
||||
* Checks if the cache has a value for a key.
|
||||
*
|
||||
* @param string $key A unique key
|
||||
*
|
||||
* @return Boolean Whether the cache has a value for this key
|
||||
*/
|
||||
function has($key);
|
||||
|
||||
/**
|
||||
* Returns the value for a key.
|
||||
*
|
||||
* @param string $key A unique key
|
||||
*
|
||||
* @return string|null The value in the cache
|
||||
*/
|
||||
function get($key);
|
||||
|
||||
/**
|
||||
* Sets a value in the cache.
|
||||
*
|
||||
* @param string $key A unique key
|
||||
* @param string $value The value to cache
|
||||
*/
|
||||
function set($key, $value);
|
||||
|
||||
/**
|
||||
* Removes a value from the cache.
|
||||
*
|
||||
* @param string $key A unique key
|
||||
*/
|
||||
function remove($key);
|
||||
}
|
|
@ -1,123 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Cache;
|
||||
|
||||
/**
|
||||
* A config cache stores values using var_export() and include.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class ConfigCache
|
||||
{
|
||||
private $dir;
|
||||
|
||||
/**
|
||||
* Construct.
|
||||
*
|
||||
* @param string $dir The cache directory
|
||||
*/
|
||||
public function __construct($dir)
|
||||
{
|
||||
$this->dir = $dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks of the cache has a file.
|
||||
*
|
||||
* @param string $resource A cache key
|
||||
*
|
||||
* @return Boolean True if a file exists
|
||||
*/
|
||||
public function has($resource)
|
||||
{
|
||||
return file_exists($this->getSourcePath($resource));
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes a value to a file.
|
||||
*
|
||||
* @param string $resource A cache key
|
||||
* @param mixed $value A value to cache
|
||||
*/
|
||||
public function set($resource, $value)
|
||||
{
|
||||
$path = $this->getSourcePath($resource);
|
||||
|
||||
if (!is_dir($dir = dirname($path)) && false === @mkdir($dir, 0777, true)) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \RuntimeException('Unable to create directory '.$dir);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
if (false === @file_put_contents($path, sprintf("<?php\n\n// $resource\nreturn %s;\n", var_export($value, true)))) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \RuntimeException('Unable to write file '.$path);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads and returns the value for the supplied cache key.
|
||||
*
|
||||
* @param string $resource A cache key
|
||||
*
|
||||
* @return mixed The cached value
|
||||
*/
|
||||
public function get($resource)
|
||||
{
|
||||
$path = $this->getSourcePath($resource);
|
||||
|
||||
if (!file_exists($path)) {
|
||||
throw new \RuntimeException('There is no cached value for '.$resource);
|
||||
}
|
||||
|
||||
return include $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a timestamp for when the cache was created.
|
||||
*
|
||||
* @param string $resource A cache key
|
||||
*
|
||||
* @return integer A UNIX timestamp
|
||||
*/
|
||||
public function getTimestamp($resource)
|
||||
{
|
||||
$path = $this->getSourcePath($resource);
|
||||
|
||||
if (!file_exists($path)) {
|
||||
throw new \RuntimeException('There is no cached value for '.$resource);
|
||||
}
|
||||
|
||||
if (false === $mtime = @filemtime($path)) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \RuntimeException('Unable to determine file mtime for '.$path);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
return $mtime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the path where the file corresponding to the supplied cache key can be included from.
|
||||
*
|
||||
* @param string $resource A cache key
|
||||
*
|
||||
* @return string A file path
|
||||
*/
|
||||
private function getSourcePath($resource)
|
||||
{
|
||||
$key = md5($resource);
|
||||
|
||||
return $this->dir.'/'.$key[0].'/'.$key.'.php';
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Cache;
|
||||
|
||||
/**
|
||||
* Adds expiration to a cache backend.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class ExpiringCache implements CacheInterface
|
||||
{
|
||||
private $cache;
|
||||
private $lifetime;
|
||||
|
||||
public function __construct(CacheInterface $cache, $lifetime)
|
||||
{
|
||||
$this->cache = $cache;
|
||||
$this->lifetime = $lifetime;
|
||||
}
|
||||
|
||||
public function has($key)
|
||||
{
|
||||
if ($this->cache->has($key)) {
|
||||
if (time() < $this->cache->get($key.'.expires')) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$this->cache->remove($key.'.expires');
|
||||
$this->cache->remove($key);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function get($key)
|
||||
{
|
||||
return $this->cache->get($key);
|
||||
}
|
||||
|
||||
public function set($key, $value)
|
||||
{
|
||||
$this->cache->set($key.'.expires', time() + $this->lifetime);
|
||||
$this->cache->set($key, $value);
|
||||
}
|
||||
|
||||
public function remove($key)
|
||||
{
|
||||
$this->cache->remove($key.'.expires');
|
||||
$this->cache->remove($key);
|
||||
}
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Cache;
|
||||
|
||||
/**
|
||||
* A simple filesystem cache.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class FilesystemCache implements CacheInterface
|
||||
{
|
||||
private $dir;
|
||||
|
||||
public function __construct($dir)
|
||||
{
|
||||
$this->dir = $dir;
|
||||
}
|
||||
|
||||
public function has($key)
|
||||
{
|
||||
return file_exists($this->dir.'/'.$key);
|
||||
}
|
||||
|
||||
public function get($key)
|
||||
{
|
||||
$path = $this->dir.'/'.$key;
|
||||
|
||||
if (!file_exists($path)) {
|
||||
throw new \RuntimeException('There is no cached value for '.$key);
|
||||
}
|
||||
|
||||
return file_get_contents($path);
|
||||
}
|
||||
|
||||
public function set($key, $value)
|
||||
{
|
||||
if (!is_dir($this->dir) && false === @mkdir($this->dir, 0777, true)) {
|
||||
throw new \RuntimeException('Unable to create directory '.$this->dir);
|
||||
}
|
||||
|
||||
$path = $this->dir.'/'.$key;
|
||||
|
||||
if (false === @file_put_contents($path, $value)) {
|
||||
throw new \RuntimeException('Unable to write file '.$path);
|
||||
}
|
||||
}
|
||||
|
||||
public function remove($key)
|
||||
{
|
||||
$path = $this->dir.'/'.$key;
|
||||
|
||||
if (file_exists($path) && false === @unlink($path)) {
|
||||
throw new \RuntimeException('Unable to remove file '.$path);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Exception;
|
||||
|
||||
/**
|
||||
* Marker.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
interface Exception
|
||||
{
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Exception;
|
||||
|
||||
use Symfony\Component\Process\Process;
|
||||
|
||||
/**
|
||||
* Describes an exception that occurred within a filter.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
class FilterException extends \RuntimeException implements Exception
|
||||
{
|
||||
private $originalMessage;
|
||||
private $input;
|
||||
|
||||
public static function fromProcess(Process $proc)
|
||||
{
|
||||
$message = sprintf("An error occurred while running:\n%s", $proc->getCommandLine());
|
||||
|
||||
$errorOutput = $proc->getErrorOutput();
|
||||
if (!empty($errorOutput)) {
|
||||
$message .= "\n\nError Output:\n".str_replace("\r", '', $errorOutput);
|
||||
}
|
||||
|
||||
$output = $proc->getOutput();
|
||||
if (!empty($output)) {
|
||||
$message .= "\n\nOutput:\n".str_replace("\r", '', $output);
|
||||
}
|
||||
|
||||
return new self($message);
|
||||
}
|
||||
|
||||
public function __construct($message, $code = 0, \Exception $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
|
||||
$this->originalMessage = $message;
|
||||
}
|
||||
|
||||
public function setInput($input)
|
||||
{
|
||||
$this->input = $input;
|
||||
$this->updateMessage();
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getInput()
|
||||
{
|
||||
return $this->input;
|
||||
}
|
||||
|
||||
private function updateMessage()
|
||||
{
|
||||
$message = $this->originalMessage;
|
||||
|
||||
if (!empty($this->input)) {
|
||||
$message .= "\n\nInput:\n".$this->input;
|
||||
}
|
||||
|
||||
$this->message = $message;
|
||||
}
|
||||
}
|
|
@ -1,76 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Extension\Twig;
|
||||
|
||||
use Assetic\ValueSupplierInterface;
|
||||
use Assetic\Factory\AssetFactory;
|
||||
|
||||
class AsseticExtension extends \Twig_Extension
|
||||
{
|
||||
protected $factory;
|
||||
protected $functions;
|
||||
protected $valueSupplier;
|
||||
|
||||
public function __construct(AssetFactory $factory, $functions = array(), ValueSupplierInterface $valueSupplier = null)
|
||||
{
|
||||
$this->factory = $factory;
|
||||
$this->functions = array();
|
||||
$this->valueSupplier = $valueSupplier;
|
||||
|
||||
foreach ($functions as $function => $options) {
|
||||
if (is_integer($function) && is_string($options)) {
|
||||
$this->functions[$options] = array('filter' => $options);
|
||||
} else {
|
||||
$this->functions[$function] = $options + array('filter' => $function);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function getTokenParsers()
|
||||
{
|
||||
return array(
|
||||
new AsseticTokenParser($this->factory, 'javascripts', 'js/*.js'),
|
||||
new AsseticTokenParser($this->factory, 'stylesheets', 'css/*.css'),
|
||||
new AsseticTokenParser($this->factory, 'image', 'images/*', true),
|
||||
);
|
||||
}
|
||||
|
||||
public function getFunctions()
|
||||
{
|
||||
$functions = array();
|
||||
foreach ($this->functions as $function => $filter) {
|
||||
$functions[$function] = new AsseticFilterFunction($function);
|
||||
}
|
||||
|
||||
return $functions;
|
||||
}
|
||||
|
||||
public function getGlobals()
|
||||
{
|
||||
return array(
|
||||
'assetic' => array(
|
||||
'debug' => $this->factory->isDebug(),
|
||||
'vars' => null !== $this->valueSupplier ? $this->valueSupplier->getValues() : array(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
public function getFilterInvoker($function)
|
||||
{
|
||||
return new AsseticFilterInvoker($this->factory, $this->functions[$function]);
|
||||
}
|
||||
|
||||
public function getName()
|
||||
{
|
||||
return 'assetic';
|
||||
}
|
||||
}
|
|
@ -1,29 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Extension\Twig;
|
||||
|
||||
class AsseticFilterFunction extends \Twig_Function
|
||||
{
|
||||
private $filter;
|
||||
|
||||
public function __construct($filter, $options = array())
|
||||
{
|
||||
$this->filter = $filter;
|
||||
|
||||
parent::__construct($options);
|
||||
}
|
||||
|
||||
public function compile()
|
||||
{
|
||||
return sprintf('$this->env->getExtension(\'assetic\')->getFilterInvoker(\'%s\')->invoke', $this->filter);
|
||||
}
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Extension\Twig;
|
||||
|
||||
use Assetic\Factory\AssetFactory;
|
||||
|
||||
/**
|
||||
* Filters a single asset.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class AsseticFilterInvoker
|
||||
{
|
||||
private $factory;
|
||||
private $filters;
|
||||
private $options;
|
||||
|
||||
public function __construct($factory, $filter)
|
||||
{
|
||||
$this->factory = $factory;
|
||||
|
||||
if (is_array($filter) && isset($filter['filter'])) {
|
||||
$this->filters = (array) $filter['filter'];
|
||||
$this->options = isset($filter['options']) ? (array) $filter['options'] : array();
|
||||
} else {
|
||||
$this->filters = (array) $filter;
|
||||
$this->options = array();
|
||||
}
|
||||
}
|
||||
|
||||
public function getFactory()
|
||||
{
|
||||
return $this->factory;
|
||||
}
|
||||
|
||||
public function getFilters()
|
||||
{
|
||||
return $this->filters;
|
||||
}
|
||||
|
||||
public function getOptions()
|
||||
{
|
||||
return $this->options;
|
||||
}
|
||||
|
||||
public function invoke($input, array $options = array())
|
||||
{
|
||||
$asset = $this->factory->createAsset($input, $this->filters, $options + $this->options);
|
||||
|
||||
return $asset->getTargetPath();
|
||||
}
|
||||
}
|
|
@ -1,166 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Extension\Twig;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
|
||||
class AsseticNode extends \Twig_Node
|
||||
{
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Available attributes:
|
||||
*
|
||||
* * debug: The debug mode
|
||||
* * combine: Whether to combine assets
|
||||
* * var_name: The name of the variable to expose to the body node
|
||||
*
|
||||
* @param AssetInterface $asset The asset
|
||||
* @param Twig_NodeInterface $body The body node
|
||||
* @param array $inputs An array of input strings
|
||||
* @param array $filters An array of filter strings
|
||||
* @param string $name The name of the asset
|
||||
* @param array $attributes An array of attributes
|
||||
* @param integer $lineno The line number
|
||||
* @param string $tag The tag name
|
||||
*/
|
||||
public function __construct(AssetInterface $asset, \Twig_NodeInterface $body, array $inputs, array $filters, $name, array $attributes = array(), $lineno = 0, $tag = null)
|
||||
{
|
||||
$nodes = array('body' => $body);
|
||||
|
||||
$attributes = array_replace(
|
||||
array('debug' => null, 'combine' => null, 'var_name' => 'asset_url'),
|
||||
$attributes,
|
||||
array('asset' => $asset, 'inputs' => $inputs, 'filters' => $filters, 'name' => $name)
|
||||
);
|
||||
|
||||
parent::__construct($nodes, $attributes, $lineno, $tag);
|
||||
}
|
||||
|
||||
public function compile(\Twig_Compiler $compiler)
|
||||
{
|
||||
$compiler->addDebugInfo($this);
|
||||
|
||||
$combine = $this->getAttribute('combine');
|
||||
$debug = $this->getAttribute('debug');
|
||||
|
||||
if (null === $combine && null !== $debug) {
|
||||
$combine = !$debug;
|
||||
}
|
||||
|
||||
if (null === $combine) {
|
||||
$compiler
|
||||
->write("if (isset(\$context['assetic']['debug']) && \$context['assetic']['debug']) {\n")
|
||||
->indent()
|
||||
;
|
||||
|
||||
$this->compileDebug($compiler);
|
||||
|
||||
$compiler
|
||||
->outdent()
|
||||
->write("} else {\n")
|
||||
->indent()
|
||||
;
|
||||
|
||||
$this->compileAsset($compiler, $this->getAttribute('asset'), $this->getAttribute('name'));
|
||||
|
||||
$compiler
|
||||
->outdent()
|
||||
->write("}\n")
|
||||
;
|
||||
} elseif ($combine) {
|
||||
$this->compileAsset($compiler, $this->getAttribute('asset'), $this->getAttribute('name'));
|
||||
} else {
|
||||
$this->compileDebug($compiler);
|
||||
}
|
||||
|
||||
$compiler
|
||||
->write('unset($context[')
|
||||
->repr($this->getAttribute('var_name'))
|
||||
->raw("]);\n")
|
||||
;
|
||||
}
|
||||
|
||||
protected function compileDebug(\Twig_Compiler $compiler)
|
||||
{
|
||||
$i = 0;
|
||||
foreach ($this->getAttribute('asset') as $leaf) {
|
||||
$leafName = $this->getAttribute('name').'_'.$i++;
|
||||
$this->compileAsset($compiler, $leaf, $leafName);
|
||||
}
|
||||
}
|
||||
|
||||
protected function compileAsset(\Twig_Compiler $compiler, AssetInterface $asset, $name)
|
||||
{
|
||||
if ($vars = $asset->getVars()) {
|
||||
$compiler->write("// check variable conditions\n");
|
||||
|
||||
foreach ($vars as $var) {
|
||||
$compiler
|
||||
->write("if (!isset(\$context['assetic']['vars']['$var'])) {\n")
|
||||
->indent()
|
||||
->write("throw new \RuntimeException(sprintf('The asset \"".$name."\" expected variable \"".$var."\" to be set, but got only these vars: %s. Did you set-up a value supplier?', isset(\$context['assetic']['vars']) && \$context['assetic']['vars'] ? implode(', ', \$context['assetic']['vars']) : '# none #'));\n")
|
||||
->outdent()
|
||||
->write("}\n")
|
||||
;
|
||||
}
|
||||
|
||||
$compiler->raw("\n");
|
||||
}
|
||||
|
||||
$compiler
|
||||
->write("// asset \"$name\"\n")
|
||||
->write('$context[')
|
||||
->repr($this->getAttribute('var_name'))
|
||||
->raw('] = ')
|
||||
;
|
||||
|
||||
$this->compileAssetUrl($compiler, $asset, $name);
|
||||
|
||||
$compiler
|
||||
->raw(";\n")
|
||||
->subcompile($this->getNode('body'))
|
||||
;
|
||||
}
|
||||
|
||||
protected function compileAssetUrl(\Twig_Compiler $compiler, AssetInterface $asset, $name)
|
||||
{
|
||||
if (!$vars = $asset->getVars()) {
|
||||
$compiler->repr($asset->getTargetPath());
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
$compiler
|
||||
->raw("strtr(")
|
||||
->string($asset->getTargetPath())
|
||||
->raw(", array(");
|
||||
;
|
||||
|
||||
$first = true;
|
||||
foreach ($vars as $var) {
|
||||
if (!$first) {
|
||||
$compiler->raw(", ");
|
||||
}
|
||||
$first = false;
|
||||
|
||||
$compiler
|
||||
->string("{".$var."}")
|
||||
->raw(" => \$context['assetic']['vars']['$var']")
|
||||
;
|
||||
}
|
||||
|
||||
$compiler
|
||||
->raw("))")
|
||||
;
|
||||
}
|
||||
}
|
|
@ -1,150 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Extension\Twig;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
use Assetic\Factory\AssetFactory;
|
||||
|
||||
class AsseticTokenParser extends \Twig_TokenParser
|
||||
{
|
||||
private $factory;
|
||||
private $tag;
|
||||
private $output;
|
||||
private $single;
|
||||
private $extensions;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* Attributes can be added to the tag by passing names as the options
|
||||
* array. These values, if found, will be passed to the factory and node.
|
||||
*
|
||||
* @param AssetFactory $factory The asset factory
|
||||
* @param string $tag The tag name
|
||||
* @param string $output The default output string
|
||||
* @param Boolean $single Whether to force a single asset
|
||||
* @param array $extensions Additional attribute names to look for
|
||||
*/
|
||||
public function __construct(AssetFactory $factory, $tag, $output, $single = false, array $extensions = array())
|
||||
{
|
||||
$this->factory = $factory;
|
||||
$this->tag = $tag;
|
||||
$this->output = $output;
|
||||
$this->single = $single;
|
||||
$this->extensions = $extensions;
|
||||
}
|
||||
|
||||
public function parse(\Twig_Token $token)
|
||||
{
|
||||
$inputs = array();
|
||||
$filters = array();
|
||||
$name = null;
|
||||
$attributes = array(
|
||||
'output' => $this->output,
|
||||
'var_name' => 'asset_url',
|
||||
'vars' => array(),
|
||||
);
|
||||
|
||||
$stream = $this->parser->getStream();
|
||||
while (!$stream->test(\Twig_Token::BLOCK_END_TYPE)) {
|
||||
if ($stream->test(\Twig_Token::STRING_TYPE)) {
|
||||
// '@jquery', 'js/src/core/*', 'js/src/extra.js'
|
||||
$inputs[] = $stream->next()->getValue();
|
||||
} elseif ($stream->test(\Twig_Token::NAME_TYPE, 'filter')) {
|
||||
// filter='yui_js'
|
||||
$stream->next();
|
||||
$stream->expect(\Twig_Token::OPERATOR_TYPE, '=');
|
||||
$filters = array_merge($filters, array_filter(array_map('trim', explode(',', $stream->expect(\Twig_Token::STRING_TYPE)->getValue()))));
|
||||
} elseif ($stream->test(\Twig_Token::NAME_TYPE, 'output')) {
|
||||
// output='js/packed/*.js' OR output='js/core.js'
|
||||
$stream->next();
|
||||
$stream->expect(\Twig_Token::OPERATOR_TYPE, '=');
|
||||
$attributes['output'] = $stream->expect(\Twig_Token::STRING_TYPE)->getValue();
|
||||
} elseif ($stream->test(\Twig_Token::NAME_TYPE, 'name')) {
|
||||
// name='core_js'
|
||||
$stream->next();
|
||||
$stream->expect(\Twig_Token::OPERATOR_TYPE, '=');
|
||||
$name = $stream->expect(\Twig_Token::STRING_TYPE)->getValue();
|
||||
} elseif ($stream->test(\Twig_Token::NAME_TYPE, 'as')) {
|
||||
// as='the_url'
|
||||
$stream->next();
|
||||
$stream->expect(\Twig_Token::OPERATOR_TYPE, '=');
|
||||
$attributes['var_name'] = $stream->expect(\Twig_Token::STRING_TYPE)->getValue();
|
||||
} elseif ($stream->test(\Twig_Token::NAME_TYPE, 'debug')) {
|
||||
// debug=true
|
||||
$stream->next();
|
||||
$stream->expect(\Twig_Token::OPERATOR_TYPE, '=');
|
||||
$attributes['debug'] = 'true' == $stream->expect(\Twig_Token::NAME_TYPE, array('true', 'false'))->getValue();
|
||||
} elseif ($stream->test(\Twig_Token::NAME_TYPE, 'combine')) {
|
||||
// combine=true
|
||||
$stream->next();
|
||||
$stream->expect(\Twig_Token::OPERATOR_TYPE, '=');
|
||||
$attributes['combine'] = 'true' == $stream->expect(\Twig_Token::NAME_TYPE, array('true', 'false'))->getValue();
|
||||
} elseif ($stream->test(\Twig_Token::NAME_TYPE, 'vars')) {
|
||||
// vars=['locale','browser']
|
||||
$stream->next();
|
||||
$stream->expect(\Twig_Token::OPERATOR_TYPE, '=');
|
||||
$stream->expect(\Twig_Token::PUNCTUATION_TYPE, '[');
|
||||
|
||||
while ($stream->test(\Twig_Token::STRING_TYPE)) {
|
||||
$attributes['vars'][] = $stream->expect(\Twig_Token::STRING_TYPE)->getValue();
|
||||
|
||||
if (!$stream->test(\Twig_Token::PUNCTUATION_TYPE, ',')) {
|
||||
break;
|
||||
}
|
||||
|
||||
$stream->next();
|
||||
}
|
||||
|
||||
$stream->expect(\Twig_Token::PUNCTUATION_TYPE, ']');
|
||||
} elseif ($stream->test(\Twig_Token::NAME_TYPE, $this->extensions)) {
|
||||
// an arbitrary configured attribute
|
||||
$key = $stream->next()->getValue();
|
||||
$stream->expect(\Twig_Token::OPERATOR_TYPE, '=');
|
||||
$attributes[$key] = $stream->expect(\Twig_Token::STRING_TYPE)->getValue();
|
||||
} else {
|
||||
$token = $stream->getCurrent();
|
||||
throw new \Twig_Error_Syntax(sprintf('Unexpected token "%s" of value "%s"', \Twig_Token::typeToEnglish($token->getType(), $token->getLine()), $token->getValue()), $token->getLine());
|
||||
}
|
||||
}
|
||||
|
||||
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
|
||||
|
||||
$endtag = 'end'.$this->getTag();
|
||||
$test = function(\Twig_Token $token) use($endtag) { return $token->test($endtag); };
|
||||
$body = $this->parser->subparse($test, true);
|
||||
|
||||
$stream->expect(\Twig_Token::BLOCK_END_TYPE);
|
||||
|
||||
if ($this->single && 1 < count($inputs)) {
|
||||
$inputs = array_slice($inputs, -1);
|
||||
}
|
||||
|
||||
if (!$name) {
|
||||
$name = $this->factory->generateAssetName($inputs, $filters, $attributes);
|
||||
}
|
||||
|
||||
$asset = $this->factory->createAsset($inputs, $filters, $attributes + array('name' => $name));
|
||||
|
||||
return $this->createNode($asset, $body, $inputs, $filters, $name, $attributes, $token->getLine(), $this->getTag());
|
||||
}
|
||||
|
||||
public function getTag()
|
||||
{
|
||||
return $this->tag;
|
||||
}
|
||||
|
||||
protected function createNode(AssetInterface $asset, \Twig_NodeInterface $body, array $inputs, array $filters, $name, array $attributes = array(), $lineno = 0, $tag = null)
|
||||
{
|
||||
return new AsseticNode($asset, $body, $inputs, $filters, $name, $attributes, $lineno, $tag);
|
||||
}
|
||||
}
|
|
@ -1,97 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Extension\Twig;
|
||||
|
||||
use Assetic\Factory\Loader\FormulaLoaderInterface;
|
||||
use Assetic\Factory\Resource\ResourceInterface;
|
||||
|
||||
/**
|
||||
* Loads asset formulae from Twig templates.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class TwigFormulaLoader implements FormulaLoaderInterface
|
||||
{
|
||||
private $twig;
|
||||
|
||||
public function __construct(\Twig_Environment $twig)
|
||||
{
|
||||
$this->twig = $twig;
|
||||
}
|
||||
|
||||
public function load(ResourceInterface $resource)
|
||||
{
|
||||
try {
|
||||
$tokens = $this->twig->tokenize($resource->getContent(), (string) $resource);
|
||||
$nodes = $this->twig->parse($tokens);
|
||||
} catch (\Exception $e) {
|
||||
return array();
|
||||
}
|
||||
|
||||
return $this->loadNode($nodes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads assets from the supplied node.
|
||||
*
|
||||
* @return array An array of asset formulae indexed by name
|
||||
*/
|
||||
private function loadNode(\Twig_Node $node)
|
||||
{
|
||||
$formulae = array();
|
||||
|
||||
if ($node instanceof AsseticNode) {
|
||||
$formulae[$node->getAttribute('name')] = array(
|
||||
$node->getAttribute('inputs'),
|
||||
$node->getAttribute('filters'),
|
||||
array(
|
||||
'output' => $node->getAttribute('asset')->getTargetPath(),
|
||||
'name' => $node->getAttribute('name'),
|
||||
'debug' => $node->getAttribute('debug'),
|
||||
'combine' => $node->getAttribute('combine'),
|
||||
'vars' => $node->getAttribute('vars'),
|
||||
),
|
||||
);
|
||||
} elseif ($node instanceof \Twig_Node_Expression_Function) {
|
||||
$name = version_compare(\Twig_Environment::VERSION, '1.2.0-DEV', '<')
|
||||
? $node->getNode('name')->getAttribute('name')
|
||||
: $node->getAttribute('name');
|
||||
|
||||
if ($this->twig->getFunction($name) instanceof AsseticFilterFunction) {
|
||||
$arguments = array();
|
||||
foreach ($node->getNode('arguments') as $argument) {
|
||||
$arguments[] = eval('return '.$this->twig->compile($argument).';');
|
||||
}
|
||||
|
||||
$invoker = $this->twig->getExtension('assetic')->getFilterInvoker($name);
|
||||
|
||||
$inputs = isset($arguments[0]) ? (array) $arguments[0] : array();
|
||||
$filters = $invoker->getFilters();
|
||||
$options = array_replace($invoker->getOptions(), isset($arguments[1]) ? $arguments[1] : array());
|
||||
|
||||
if (!isset($options['name'])) {
|
||||
$options['name'] = $invoker->getFactory()->generateAssetName($inputs, $filters, $options);
|
||||
}
|
||||
|
||||
$formulae[$options['name']] = array($inputs, $filters, $options);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($node as $child) {
|
||||
if ($child instanceof \Twig_Node) {
|
||||
$formulae += $this->loadNode($child);
|
||||
}
|
||||
}
|
||||
|
||||
return $formulae;
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Extension\Twig;
|
||||
|
||||
use Assetic\Factory\Resource\ResourceInterface;
|
||||
|
||||
/**
|
||||
* A Twig template resource.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class TwigResource implements ResourceInterface
|
||||
{
|
||||
private $loader;
|
||||
private $name;
|
||||
|
||||
public function __construct(\Twig_LoaderInterface $loader, $name)
|
||||
{
|
||||
$this->loader = $loader;
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
try {
|
||||
return $this->loader->getSource($this->name);
|
||||
} catch (\Twig_Error_Loader $e) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
public function isFresh($timestamp)
|
||||
{
|
||||
try {
|
||||
return $this->loader->isFresh($this->name, $timestamp);
|
||||
} catch (\Twig_Error_Loader $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->name;
|
||||
}
|
||||
}
|
|
@ -1,386 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Factory;
|
||||
|
||||
use Assetic\Asset\AssetCollection;
|
||||
use Assetic\Asset\AssetCollectionInterface;
|
||||
use Assetic\Asset\AssetInterface;
|
||||
use Assetic\Asset\AssetReference;
|
||||
use Assetic\Asset\FileAsset;
|
||||
use Assetic\Asset\GlobAsset;
|
||||
use Assetic\Asset\HttpAsset;
|
||||
use Assetic\AssetManager;
|
||||
use Assetic\Factory\Worker\WorkerInterface;
|
||||
use Assetic\FilterManager;
|
||||
|
||||
/**
|
||||
* The asset factory creates asset objects.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class AssetFactory
|
||||
{
|
||||
private $root;
|
||||
private $debug;
|
||||
private $output;
|
||||
private $workers;
|
||||
private $am;
|
||||
private $fm;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $root The default root directory
|
||||
* @param string $output The default output string
|
||||
* @param Boolean $debug Filters prefixed with a "?" will be omitted in debug mode
|
||||
*/
|
||||
public function __construct($root, $debug = false)
|
||||
{
|
||||
$this->root = rtrim($root, '/');
|
||||
$this->debug = $debug;
|
||||
$this->output = 'assetic/*';
|
||||
$this->workers = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets debug mode for the current factory.
|
||||
*
|
||||
* @param Boolean $debug Debug mode
|
||||
*/
|
||||
public function setDebug($debug)
|
||||
{
|
||||
$this->debug = $debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the factory is in debug mode.
|
||||
*
|
||||
* @return Boolean Debug mode
|
||||
*/
|
||||
public function isDebug()
|
||||
{
|
||||
return $this->debug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the default output string.
|
||||
*
|
||||
* @param string $output The default output string
|
||||
*/
|
||||
public function setDefaultOutput($output)
|
||||
{
|
||||
$this->output = $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a factory worker.
|
||||
*
|
||||
* @param WorkerInterface $worker A worker
|
||||
*/
|
||||
public function addWorker(WorkerInterface $worker)
|
||||
{
|
||||
$this->workers[] = $worker;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current asset manager.
|
||||
*
|
||||
* @return AssetManager|null The asset manager
|
||||
*/
|
||||
public function getAssetManager()
|
||||
{
|
||||
return $this->am;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the asset manager to use when creating asset references.
|
||||
*
|
||||
* @param AssetManager $am The asset manager
|
||||
*/
|
||||
public function setAssetManager(AssetManager $am)
|
||||
{
|
||||
$this->am = $am;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current filter manager.
|
||||
*
|
||||
* @return FilterManager|null The filter manager
|
||||
*/
|
||||
public function getFilterManager()
|
||||
{
|
||||
return $this->fm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the filter manager to use when adding filters.
|
||||
*
|
||||
* @param FilterManager $fm The filter manager
|
||||
*/
|
||||
public function setFilterManager(FilterManager $fm)
|
||||
{
|
||||
$this->fm = $fm;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new asset.
|
||||
*
|
||||
* Prefixing a filter name with a question mark will cause it to be
|
||||
* omitted when the factory is in debug mode.
|
||||
*
|
||||
* Available options:
|
||||
*
|
||||
* * output: An output string
|
||||
* * name: An asset name for interpolation in output patterns
|
||||
* * debug: Forces debug mode on or off for this asset
|
||||
* * root: An array or string of more root directories
|
||||
*
|
||||
* @param array|string $inputs An array of input strings
|
||||
* @param array|string $filters An array of filter names
|
||||
* @param array $options An array of options
|
||||
*
|
||||
* @return AssetCollection An asset collection
|
||||
*/
|
||||
public function createAsset($inputs = array(), $filters = array(), array $options = array())
|
||||
{
|
||||
if (!is_array($inputs)) {
|
||||
$inputs = array($inputs);
|
||||
}
|
||||
|
||||
if (!is_array($filters)) {
|
||||
$filters = array($filters);
|
||||
}
|
||||
|
||||
if (!isset($options['output'])) {
|
||||
$options['output'] = $this->output;
|
||||
}
|
||||
|
||||
if (!isset($options['vars'])) {
|
||||
$options['vars'] = array();
|
||||
}
|
||||
|
||||
if (!isset($options['debug'])) {
|
||||
$options['debug'] = $this->debug;
|
||||
}
|
||||
|
||||
if (!isset($options['root'])) {
|
||||
$options['root'] = array($this->root);
|
||||
} else {
|
||||
if (!is_array($options['root'])) {
|
||||
$options['root'] = array($options['root']);
|
||||
}
|
||||
|
||||
$options['root'][] = $this->root;
|
||||
}
|
||||
|
||||
if (!isset($options['name'])) {
|
||||
$options['name'] = $this->generateAssetName($inputs, $filters, $options);
|
||||
}
|
||||
|
||||
$asset = $this->createAssetCollection(array(), $options);
|
||||
$extensions = array();
|
||||
|
||||
// inner assets
|
||||
foreach ($inputs as $input) {
|
||||
if (is_array($input)) {
|
||||
// nested formula
|
||||
$asset->add(call_user_func_array(array($this, 'createAsset'), $input));
|
||||
} else {
|
||||
$asset->add($this->parseInput($input, $options));
|
||||
$extensions[pathinfo($input, PATHINFO_EXTENSION)] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// filters
|
||||
foreach ($filters as $filter) {
|
||||
if ('?' != $filter[0]) {
|
||||
$asset->ensureFilter($this->getFilter($filter));
|
||||
} elseif (!$options['debug']) {
|
||||
$asset->ensureFilter($this->getFilter(substr($filter, 1)));
|
||||
}
|
||||
}
|
||||
|
||||
// append variables
|
||||
if (!empty($options['vars'])) {
|
||||
$toAdd = array();
|
||||
foreach ($options['vars'] as $var) {
|
||||
if (false !== strpos($options['output'], '{'.$var.'}')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$toAdd[] = '{'.$var.'}';
|
||||
}
|
||||
|
||||
if ($toAdd) {
|
||||
$options['output'] = str_replace('*', '*.'.implode('.', $toAdd), $options['output']);
|
||||
}
|
||||
}
|
||||
|
||||
// append consensus extension if missing
|
||||
if (1 == count($extensions) && !pathinfo($options['output'], PATHINFO_EXTENSION) && $extension = key($extensions)) {
|
||||
$options['output'] .= '.'.$extension;
|
||||
}
|
||||
|
||||
// output --> target url
|
||||
$asset->setTargetPath(str_replace('*', $options['name'], $options['output']));
|
||||
|
||||
// apply workers and return
|
||||
return $this->applyWorkers($asset);
|
||||
}
|
||||
|
||||
public function generateAssetName($inputs, $filters, $options = array())
|
||||
{
|
||||
foreach (array_diff(array_keys($options), array('output', 'debug', 'root')) as $key) {
|
||||
unset($options[$key]);
|
||||
}
|
||||
|
||||
ksort($options);
|
||||
|
||||
return substr(sha1(serialize($inputs).serialize($filters).serialize($options)), 0, 7);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an input string string into an asset.
|
||||
*
|
||||
* The input string can be one of the following:
|
||||
*
|
||||
* * A reference: If the string starts with an "at" sign it will be interpreted as a reference to an asset in the asset manager
|
||||
* * An absolute URL: If the string contains "://" or starts with "//" it will be interpreted as an HTTP asset
|
||||
* * A glob: If the string contains a "*" it will be interpreted as a glob
|
||||
* * A path: Otherwise the string is interpreted as a filesystem path
|
||||
*
|
||||
* Both globs and paths will be absolutized using the current root directory.
|
||||
*
|
||||
* @param string $input An input string
|
||||
* @param array $options An array of options
|
||||
*
|
||||
* @return AssetInterface An asset
|
||||
*/
|
||||
protected function parseInput($input, array $options = array())
|
||||
{
|
||||
if ('@' == $input[0]) {
|
||||
return $this->createAssetReference(substr($input, 1));
|
||||
}
|
||||
|
||||
if (false !== strpos($input, '://') || 0 === strpos($input, '//')) {
|
||||
return $this->createHttpAsset($input, $options['vars']);
|
||||
}
|
||||
|
||||
if (self::isAbsolutePath($input)) {
|
||||
if ($root = self::findRootDir($input, $options['root'])) {
|
||||
$path = ltrim(substr($input, strlen($root)), '/');
|
||||
} else {
|
||||
$path = null;
|
||||
}
|
||||
} else {
|
||||
$root = $this->root;
|
||||
$path = $input;
|
||||
$input = $this->root.'/'.$path;
|
||||
}
|
||||
if (false !== strpos($input, '*')) {
|
||||
return $this->createGlobAsset($input, $root, $options['vars']);
|
||||
} else {
|
||||
return $this->createFileAsset($input, $root, $path, $options['vars']);
|
||||
}
|
||||
}
|
||||
|
||||
protected function createAssetCollection(array $assets = array(), array $options = array())
|
||||
{
|
||||
return new AssetCollection($assets, array(), null, isset($options['vars']) ? $options['vars'] : array());
|
||||
}
|
||||
|
||||
protected function createAssetReference($name)
|
||||
{
|
||||
if (!$this->am) {
|
||||
throw new \LogicException('There is no asset manager.');
|
||||
}
|
||||
|
||||
return new AssetReference($this->am, $name);
|
||||
}
|
||||
|
||||
protected function createHttpAsset($sourceUrl, $vars)
|
||||
{
|
||||
return new HttpAsset($sourceUrl, array(), false, $vars);
|
||||
}
|
||||
|
||||
protected function createGlobAsset($glob, $root = null, $vars)
|
||||
{
|
||||
return new GlobAsset($glob, array(), $root, $vars);
|
||||
}
|
||||
|
||||
protected function createFileAsset($source, $root = null, $path = null, $vars)
|
||||
{
|
||||
return new FileAsset($source, array(), $root, $path, $vars);
|
||||
}
|
||||
|
||||
protected function getFilter($name)
|
||||
{
|
||||
if (!$this->fm) {
|
||||
throw new \LogicException('There is no filter manager.');
|
||||
}
|
||||
|
||||
return $this->fm->get($name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters an asset collection through the factory workers.
|
||||
*
|
||||
* Each leaf asset will be processed first, followed by the asset
|
||||
* collection itself.
|
||||
*
|
||||
* @param AssetCollectionInterface $asset An asset collection
|
||||
*/
|
||||
private function applyWorkers(AssetCollectionInterface $asset)
|
||||
{
|
||||
foreach ($asset as $leaf) {
|
||||
foreach ($this->workers as $worker) {
|
||||
$retval = $worker->process($leaf);
|
||||
|
||||
if ($retval instanceof AssetInterface && $leaf !== $retval) {
|
||||
$asset->replaceLeaf($leaf, $retval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($this->workers as $worker) {
|
||||
$retval = $worker->process($asset);
|
||||
|
||||
if ($retval instanceof AssetInterface) {
|
||||
$asset = $retval;
|
||||
}
|
||||
}
|
||||
|
||||
return $asset instanceof AssetCollectionInterface ? $asset : $this->createAssetCollection(array($asset));
|
||||
}
|
||||
|
||||
static private function isAbsolutePath($path)
|
||||
{
|
||||
return '/' == $path[0] || '\\' == $path[0] || (3 < strlen($path) && ctype_alpha($path[0]) && $path[1] == ':' && ('\\' == $path[2] || '/' == $path[2]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Loops through the root directories and returns the first match.
|
||||
*
|
||||
* @param string $path An absolute path
|
||||
* @param array $roots An array of root directories
|
||||
*
|
||||
* @return string|null The matching root directory, if found
|
||||
*/
|
||||
static private function findRootDir($path, array $roots)
|
||||
{
|
||||
foreach ($roots as $root) {
|
||||
if (0 === strpos($path, $root)) {
|
||||
return $root;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,204 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Factory;
|
||||
|
||||
use Assetic\AssetManager;
|
||||
use Assetic\Factory\Loader\FormulaLoaderInterface;
|
||||
use Assetic\Factory\Resource\ResourceInterface;
|
||||
|
||||
/**
|
||||
* A lazy asset manager is a composition of a factory and many formula loaders.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class LazyAssetManager extends AssetManager
|
||||
{
|
||||
private $factory;
|
||||
private $loaders;
|
||||
private $resources;
|
||||
private $formulae;
|
||||
private $loaded;
|
||||
private $loading;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param AssetFactory $factory The asset factory
|
||||
* @param array $loaders An array of loaders indexed by alias
|
||||
*/
|
||||
public function __construct(AssetFactory $factory, $loaders = array())
|
||||
{
|
||||
$this->factory = $factory;
|
||||
$this->loaders = array();
|
||||
$this->resources = array();
|
||||
$this->formulae = array();
|
||||
$this->loaded = false;
|
||||
$this->loading = false;
|
||||
|
||||
foreach ($loaders as $alias => $loader) {
|
||||
$this->setLoader($alias, $loader);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a loader to the asset manager.
|
||||
*
|
||||
* @param string $alias An alias for the loader
|
||||
* @param FormulaLoaderInterface $loader A loader
|
||||
*/
|
||||
public function setLoader($alias, FormulaLoaderInterface $loader)
|
||||
{
|
||||
$this->loaders[$alias] = $loader;
|
||||
$this->loaded = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a resource to the asset manager.
|
||||
*
|
||||
* @param ResourceInterface $resource A resource
|
||||
* @param string $loader The loader alias for this resource
|
||||
*/
|
||||
public function addResource(ResourceInterface $resource, $loader)
|
||||
{
|
||||
$this->resources[$loader][] = $resource;
|
||||
$this->loaded = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of resources.
|
||||
*
|
||||
* @return array An array of resources
|
||||
*/
|
||||
public function getResources()
|
||||
{
|
||||
$resources = array();
|
||||
foreach ($this->resources as $r) {
|
||||
$resources = array_merge($resources, $r);
|
||||
}
|
||||
|
||||
return $resources;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for an asset formula.
|
||||
*
|
||||
* @param string $name An asset name
|
||||
*
|
||||
* @return Boolean If there is a formula
|
||||
*/
|
||||
public function hasFormula($name)
|
||||
{
|
||||
if (!$this->loaded) {
|
||||
$this->load();
|
||||
}
|
||||
|
||||
return isset($this->formulae[$name]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an asset's formula.
|
||||
*
|
||||
* @param string $name An asset name
|
||||
*
|
||||
* @return array The formula
|
||||
*
|
||||
* @throws InvalidArgumentException If there is no formula by that name
|
||||
*/
|
||||
public function getFormula($name)
|
||||
{
|
||||
if (!$this->loaded) {
|
||||
$this->load();
|
||||
}
|
||||
|
||||
if (!isset($this->formulae[$name])) {
|
||||
throw new \InvalidArgumentException(sprintf('There is no "%s" formula.', $name));
|
||||
}
|
||||
|
||||
return $this->formulae[$name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a formula on the asset manager.
|
||||
*
|
||||
* @param string $name An asset name
|
||||
* @param array $formula A formula
|
||||
*/
|
||||
public function setFormula($name, array $formula)
|
||||
{
|
||||
$this->formulae[$name] = $formula;
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads formulae from resources.
|
||||
*
|
||||
* @throws LogicException If a resource has been added to an invalid loader
|
||||
*/
|
||||
public function load()
|
||||
{
|
||||
if ($this->loading) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($diff = array_diff(array_keys($this->resources), array_keys($this->loaders))) {
|
||||
throw new \LogicException('The following loader(s) are not registered: '.implode(', ', $diff));
|
||||
}
|
||||
|
||||
$this->loading = true;
|
||||
|
||||
foreach ($this->resources as $loader => $resources) {
|
||||
foreach ($resources as $resource) {
|
||||
$this->formulae = array_replace($this->formulae, $this->loaders[$loader]->load($resource));
|
||||
}
|
||||
}
|
||||
|
||||
$this->loaded = true;
|
||||
$this->loading = false;
|
||||
}
|
||||
|
||||
public function get($name)
|
||||
{
|
||||
if (!$this->loaded) {
|
||||
$this->load();
|
||||
}
|
||||
|
||||
if (!parent::has($name) && isset($this->formulae[$name])) {
|
||||
list($inputs, $filters, $options) = $this->formulae[$name];
|
||||
$options['name'] = $name;
|
||||
parent::set($name, $this->factory->createAsset($inputs, $filters, $options));
|
||||
}
|
||||
|
||||
return parent::get($name);
|
||||
}
|
||||
|
||||
public function has($name)
|
||||
{
|
||||
if (!$this->loaded) {
|
||||
$this->load();
|
||||
}
|
||||
|
||||
return isset($this->formulae[$name]) || parent::has($name);
|
||||
}
|
||||
|
||||
public function getNames()
|
||||
{
|
||||
if (!$this->loaded) {
|
||||
$this->load();
|
||||
}
|
||||
|
||||
return array_unique(array_merge(parent::getNames(), array_keys($this->formulae)));
|
||||
}
|
||||
|
||||
public function isDebug()
|
||||
{
|
||||
return $this->factory->isDebug();
|
||||
}
|
||||
}
|
|
@ -1,159 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Factory\Loader;
|
||||
|
||||
use Assetic\Factory\AssetFactory;
|
||||
use Assetic\Factory\Resource\ResourceInterface;
|
||||
|
||||
/**
|
||||
* Loads asset formulae from PHP files.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
abstract class BasePhpFormulaLoader implements FormulaLoaderInterface
|
||||
{
|
||||
protected $factory;
|
||||
protected $prototypes;
|
||||
|
||||
public function __construct(AssetFactory $factory)
|
||||
{
|
||||
$this->factory = $factory;
|
||||
$this->prototypes = array();
|
||||
|
||||
foreach ($this->registerPrototypes() as $prototype => $options) {
|
||||
$this->addPrototype($prototype, $options);
|
||||
}
|
||||
}
|
||||
|
||||
public function addPrototype($prototype, array $options = array())
|
||||
{
|
||||
$tokens = token_get_all('<?php '.$prototype);
|
||||
array_shift($tokens);
|
||||
|
||||
$this->prototypes[$prototype] = array($tokens, $options);
|
||||
}
|
||||
|
||||
public function load(ResourceInterface $resource)
|
||||
{
|
||||
if (!$nbProtos = count($this->prototypes)) {
|
||||
throw new \LogicException('There are no prototypes registered.');
|
||||
}
|
||||
|
||||
$buffers = array_fill(0, $nbProtos, '');
|
||||
$bufferLevels = array_fill(0, $nbProtos, 0);
|
||||
$buffersInWildcard = array();
|
||||
|
||||
$tokens = token_get_all($resource->getContent());
|
||||
$calls = array();
|
||||
|
||||
while ($token = array_shift($tokens)) {
|
||||
$current = self::tokenToString($token);
|
||||
// loop through each prototype (by reference)
|
||||
foreach (array_keys($this->prototypes) as $i) {
|
||||
$prototype =& $this->prototypes[$i][0];
|
||||
$options = $this->prototypes[$i][1];
|
||||
$buffer =& $buffers[$i];
|
||||
$level =& $bufferLevels[$i];
|
||||
|
||||
if (isset($buffersInWildcard[$i])) {
|
||||
switch ($current) {
|
||||
case '(': ++$level; break;
|
||||
case ')': --$level; break;
|
||||
}
|
||||
|
||||
$buffer .= $current;
|
||||
|
||||
if (!$level) {
|
||||
$calls[] = array($buffer.';', $options);
|
||||
$buffer = '';
|
||||
unset($buffersInWildcard[$i]);
|
||||
}
|
||||
} elseif ($current == self::tokenToString(current($prototype))) {
|
||||
$buffer .= $current;
|
||||
if ('*' == self::tokenToString(next($prototype))) {
|
||||
$buffersInWildcard[$i] = true;
|
||||
++$level;
|
||||
}
|
||||
} else {
|
||||
reset($prototype);
|
||||
unset($buffersInWildcard[$i]);
|
||||
$buffer = '';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$formulae = array();
|
||||
foreach ($calls as $call) {
|
||||
$formulae += call_user_func_array(array($this, 'processCall'), $call);
|
||||
}
|
||||
|
||||
return $formulae;
|
||||
}
|
||||
|
||||
private function processCall($call, array $protoOptions = array())
|
||||
{
|
||||
$tmp = tempnam(sys_get_temp_dir(), 'assetic');
|
||||
file_put_contents($tmp, implode("\n", array(
|
||||
'<?php',
|
||||
$this->registerSetupCode(),
|
||||
$call,
|
||||
'echo serialize($_call);',
|
||||
)));
|
||||
$args = unserialize(shell_exec('php '.escapeshellarg($tmp)));
|
||||
unlink($tmp);
|
||||
|
||||
$inputs = isset($args[0]) ? self::argumentToArray($args[0]) : array();
|
||||
$filters = isset($args[1]) ? self::argumentToArray($args[1]) : array();
|
||||
$options = isset($args[2]) ? $args[2] : array();
|
||||
|
||||
if (!isset($options['debug'])) {
|
||||
$options['debug'] = $this->factory->isDebug();
|
||||
}
|
||||
|
||||
if (!is_array($options)) {
|
||||
throw new \RuntimeException('The third argument must be omitted, null or an array.');
|
||||
}
|
||||
|
||||
// apply the prototype options
|
||||
$options += $protoOptions;
|
||||
|
||||
if (!isset($options['name'])) {
|
||||
$options['name'] = $this->factory->generateAssetName($inputs, $filters, $options);
|
||||
}
|
||||
|
||||
return array($options['name'] => array($inputs, $filters, $options));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of prototypical calls and options.
|
||||
*
|
||||
* @return array Prototypes and options
|
||||
*/
|
||||
abstract protected function registerPrototypes();
|
||||
|
||||
/**
|
||||
* Returns setup code for the reflection scriptlet.
|
||||
*
|
||||
* @return string Some PHP setup code
|
||||
*/
|
||||
abstract protected function registerSetupCode();
|
||||
|
||||
static protected function tokenToString($token)
|
||||
{
|
||||
return is_array($token) ? $token[1] : $token;
|
||||
}
|
||||
|
||||
static protected function argumentToArray($argument)
|
||||
{
|
||||
return is_array($argument) ? $argument : array_filter(array_map('trim', explode(',', $argument)));
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Factory\Loader;
|
||||
|
||||
use Assetic\Cache\ConfigCache;
|
||||
use Assetic\Factory\Resource\IteratorResourceInterface;
|
||||
use Assetic\Factory\Resource\ResourceInterface;
|
||||
|
||||
/**
|
||||
* Adds a caching layer to a loader.
|
||||
*
|
||||
* A cached formula loader is a composition of a formula loader and a cache.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class CachedFormulaLoader implements FormulaLoaderInterface
|
||||
{
|
||||
private $loader;
|
||||
private $configCache;
|
||||
private $debug;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* When the loader is in debug mode it will ensure the cached formulae
|
||||
* are fresh before returning them.
|
||||
*
|
||||
* @param FormulaLoaderInterface $loader A formula loader
|
||||
* @param ConfigCache $configCache A config cache
|
||||
* @param Boolean $debug The debug mode
|
||||
*/
|
||||
public function __construct(FormulaLoaderInterface $loader, ConfigCache $configCache, $debug = false)
|
||||
{
|
||||
$this->loader = $loader;
|
||||
$this->configCache = $configCache;
|
||||
$this->debug = $debug;
|
||||
}
|
||||
|
||||
public function load(ResourceInterface $resources)
|
||||
{
|
||||
if (!$resources instanceof IteratorResourceInterface) {
|
||||
$resources = array($resources);
|
||||
}
|
||||
|
||||
$formulae = array();
|
||||
|
||||
foreach ($resources as $resource) {
|
||||
$id = (string) $resource;
|
||||
if (!$this->configCache->has($id) || ($this->debug && !$resource->isFresh($this->configCache->getTimestamp($id)))) {
|
||||
$formulae += $this->loader->load($resource);
|
||||
$this->configCache->set($id, $formulae);
|
||||
} else {
|
||||
$formulae += $this->configCache->get($id);
|
||||
}
|
||||
}
|
||||
|
||||
return $formulae;
|
||||
}
|
||||
}
|
|
@ -1,34 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Factory\Loader;
|
||||
|
||||
use Assetic\Factory\Resource\ResourceInterface;
|
||||
|
||||
/**
|
||||
* Loads formulae.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
interface FormulaLoaderInterface
|
||||
{
|
||||
/**
|
||||
* Loads formulae from a resource.
|
||||
*
|
||||
* Formulae should be loaded the same regardless of the current debug
|
||||
* mode. Debug considerations should happen downstream.
|
||||
*
|
||||
* @param ResourceInterface $resource A resource
|
||||
*
|
||||
* @return array An array of formulae
|
||||
*/
|
||||
function load(ResourceInterface $resource);
|
||||
}
|
|
@ -1,53 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Factory\Loader;
|
||||
|
||||
/**
|
||||
* Loads asset formulae from PHP files.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class FunctionCallsFormulaLoader extends BasePhpFormulaLoader
|
||||
{
|
||||
protected function registerPrototypes()
|
||||
{
|
||||
return array(
|
||||
'assetic_javascripts(*)' => array('output' => 'js/*.js'),
|
||||
'assetic_stylesheets(*)' => array('output' => 'css/*.css'),
|
||||
'assetic_image(*)' => array('output' => 'images/*'),
|
||||
);
|
||||
}
|
||||
|
||||
protected function registerSetupCode()
|
||||
{
|
||||
return <<<'EOF'
|
||||
function assetic_javascripts()
|
||||
{
|
||||
global $_call;
|
||||
$_call = func_get_args();
|
||||
}
|
||||
|
||||
function assetic_stylesheets()
|
||||
{
|
||||
global $_call;
|
||||
$_call = func_get_args();
|
||||
}
|
||||
|
||||
function assetic_image()
|
||||
{
|
||||
global $_call;
|
||||
$_call = func_get_args();
|
||||
}
|
||||
|
||||
EOF;
|
||||
}
|
||||
}
|
|
@ -1,112 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Factory\Resource;
|
||||
|
||||
/**
|
||||
* Coalesces multiple directories together into one merged resource.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class CoalescingDirectoryResource implements IteratorResourceInterface
|
||||
{
|
||||
private $directories;
|
||||
|
||||
public function __construct($directories)
|
||||
{
|
||||
$this->directories = array();
|
||||
|
||||
foreach ($directories as $directory) {
|
||||
$this->addDirectory($directory);
|
||||
}
|
||||
}
|
||||
|
||||
public function addDirectory(IteratorResourceInterface $directory)
|
||||
{
|
||||
$this->directories[] = $directory;
|
||||
}
|
||||
|
||||
public function isFresh($timestamp)
|
||||
{
|
||||
foreach ($this->getFileResources() as $file) {
|
||||
if (!$file->isFresh($timestamp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
$parts = array();
|
||||
foreach ($this->getFileResources() as $file) {
|
||||
$parts[] = $file->getContent();
|
||||
}
|
||||
|
||||
return implode("\n", $parts);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string to uniquely identify the current resource.
|
||||
*
|
||||
* @return string An identifying string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
$parts = array();
|
||||
foreach ($this->directories as $directory) {
|
||||
$parts[] = (string) $directory;
|
||||
}
|
||||
|
||||
return implode(',', $parts);
|
||||
}
|
||||
|
||||
public function getIterator()
|
||||
{
|
||||
return new \ArrayIterator($this->getFileResources());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the relative version of a filename.
|
||||
*
|
||||
* @param ResourceInterface $file The file
|
||||
* @param ResourceInterface $directory The directory
|
||||
*
|
||||
* @return string The name to compare with files from other directories
|
||||
*/
|
||||
protected function getRelativeName(ResourceInterface $file, ResourceInterface $directory)
|
||||
{
|
||||
return substr((string) $file, strlen((string) $directory));
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs the coalesce.
|
||||
*
|
||||
* @return array An array of file resources
|
||||
*/
|
||||
private function getFileResources()
|
||||
{
|
||||
$paths = array();
|
||||
|
||||
foreach ($this->directories as $directory) {
|
||||
foreach ($directory as $file) {
|
||||
$relative = $this->getRelativeName($file, $directory);
|
||||
|
||||
if (!isset($paths[$relative])) {
|
||||
$paths[$relative] = $file;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return array_values($paths);
|
||||
}
|
||||
}
|
|
@ -1,133 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Factory\Resource;
|
||||
|
||||
/**
|
||||
* A resource is something formulae can be loaded from.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class DirectoryResource implements IteratorResourceInterface
|
||||
{
|
||||
private $path;
|
||||
private $pattern;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $path A directory path
|
||||
* @param string $pattern A filename pattern
|
||||
*/
|
||||
public function __construct($path, $pattern = null)
|
||||
{
|
||||
if (DIRECTORY_SEPARATOR != substr($path, -1)) {
|
||||
$path .= DIRECTORY_SEPARATOR;
|
||||
}
|
||||
|
||||
$this->path = $path;
|
||||
$this->pattern = $pattern;
|
||||
}
|
||||
|
||||
public function isFresh($timestamp)
|
||||
{
|
||||
if (!is_dir($this->path) || filemtime($this->path) > $timestamp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ($this as $resource) {
|
||||
if (!$resource->isFresh($timestamp)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the combined content of all inner resources.
|
||||
*/
|
||||
public function getContent()
|
||||
{
|
||||
$content = array();
|
||||
foreach ($this as $resource) {
|
||||
$content[] = $resource->getContent();
|
||||
}
|
||||
|
||||
return implode("\n", $content);
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
|
||||
public function getIterator()
|
||||
{
|
||||
return is_dir($this->path)
|
||||
? new DirectoryResourceIterator($this->getInnerIterator())
|
||||
: new \EmptyIterator();
|
||||
}
|
||||
|
||||
protected function getInnerIterator()
|
||||
{
|
||||
return new DirectoryResourceFilterIterator(new \RecursiveDirectoryIterator($this->path), $this->pattern);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* An iterator that converts file objects into file resources.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
* @access private
|
||||
*/
|
||||
class DirectoryResourceIterator extends \RecursiveIteratorIterator
|
||||
{
|
||||
public function current()
|
||||
{
|
||||
return new FileResource(parent::current()->getPathname());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters files by a basename pattern.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
* @access private
|
||||
*/
|
||||
class DirectoryResourceFilterIterator extends \RecursiveFilterIterator
|
||||
{
|
||||
protected $pattern;
|
||||
|
||||
public function __construct(\RecursiveDirectoryIterator $iterator, $pattern = null)
|
||||
{
|
||||
parent::__construct($iterator);
|
||||
|
||||
$this->pattern = $pattern;
|
||||
}
|
||||
|
||||
public function accept()
|
||||
{
|
||||
$file = $this->current();
|
||||
$name = $file->getBasename();
|
||||
|
||||
if ($file->isDir()) {
|
||||
return '.' != $name[0];
|
||||
} else {
|
||||
return null === $this->pattern || 0 < preg_match($this->pattern, $name);
|
||||
}
|
||||
}
|
||||
|
||||
public function getChildren()
|
||||
{
|
||||
return new self(new \RecursiveDirectoryIterator($this->current()->getPathname()), $this->pattern);
|
||||
}
|
||||
}
|
|
@ -1,47 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Factory\Resource;
|
||||
|
||||
/**
|
||||
* A resource is something formulae can be loaded from.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class FileResource implements ResourceInterface
|
||||
{
|
||||
private $path;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $path The path to a file
|
||||
*/
|
||||
public function __construct($path)
|
||||
{
|
||||
$this->path = $path;
|
||||
}
|
||||
|
||||
public function isFresh($timestamp)
|
||||
{
|
||||
return file_exists($this->path) && filemtime($this->path) <= $timestamp;
|
||||
}
|
||||
|
||||
public function getContent()
|
||||
{
|
||||
return file_exists($this->path) ? file_get_contents($this->path) : '';
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->path;
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Factory\Resource;
|
||||
|
||||
/**
|
||||
* A resource is something formulae can be loaded from.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
interface IteratorResourceInterface extends ResourceInterface, \IteratorAggregate
|
||||
{
|
||||
}
|
|
@ -1,43 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Factory\Resource;
|
||||
|
||||
/**
|
||||
* A resource is something formulae can be loaded from.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
interface ResourceInterface
|
||||
{
|
||||
/**
|
||||
* Checks if a timestamp represents the latest resource.
|
||||
*
|
||||
* @param integer $timestamp A UNIX timestamp
|
||||
*
|
||||
* @return Boolean True if the timestamp is up to date
|
||||
*/
|
||||
function isFresh($timestamp);
|
||||
|
||||
/**
|
||||
* Returns the content of the resource.
|
||||
*
|
||||
* @return string The content
|
||||
*/
|
||||
function getContent();
|
||||
|
||||
/**
|
||||
* Returns a unique string for the current resource.
|
||||
*
|
||||
* @return string A unique string to identity the current resource
|
||||
*/
|
||||
function __toString();
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Factory\Worker;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
use Assetic\Filter\FilterInterface;
|
||||
|
||||
/**
|
||||
* Applies a filter to an asset based on a source and/or target path match.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
* @todo A better asset-matcher mechanism
|
||||
*/
|
||||
class EnsureFilterWorker implements WorkerInterface
|
||||
{
|
||||
const CHECK_SOURCE = 1;
|
||||
const CHECK_TARGET = 2;
|
||||
|
||||
private $pattern;
|
||||
private $filter;
|
||||
private $flags;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $pattern A regex for checking the asset's target URL
|
||||
* @param FilterInterface $filter A filter to apply if the regex matches
|
||||
* @param integer $flags Flags for what to check
|
||||
*/
|
||||
public function __construct($pattern, FilterInterface $filter, $flags = null)
|
||||
{
|
||||
if (null === $flags) {
|
||||
$flags = self::CHECK_SOURCE | self::CHECK_TARGET;
|
||||
}
|
||||
|
||||
$this->pattern = $pattern;
|
||||
$this->filter = $filter;
|
||||
$this->flags = $flags;
|
||||
}
|
||||
|
||||
public function process(AssetInterface $asset)
|
||||
{
|
||||
if (
|
||||
(self::CHECK_SOURCE === (self::CHECK_SOURCE & $this->flags) && preg_match($this->pattern, $asset->getSourcePath()))
|
||||
||
|
||||
(self::CHECK_TARGET === (self::CHECK_TARGET & $this->flags) && preg_match($this->pattern, $asset->getTargetPath()))
|
||||
) {
|
||||
$asset->ensureFilter($this->filter);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Factory\Worker;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
|
||||
/**
|
||||
* Assets are passed through factory workers before leaving the factory.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
interface WorkerInterface
|
||||
{
|
||||
/**
|
||||
* Processes an asset.
|
||||
*
|
||||
* @param AssetInterface $asset An asset
|
||||
*
|
||||
* @return AssetInterface|null May optionally return a replacement asset
|
||||
*/
|
||||
function process(AssetInterface $asset);
|
||||
}
|
|
@ -1,71 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter;
|
||||
|
||||
/**
|
||||
* An abstract filter for dealing with CSS.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
abstract class BaseCssFilter implements FilterInterface
|
||||
{
|
||||
/**
|
||||
* Filters all references -- url() and "@import" -- through a callable.
|
||||
*
|
||||
* @param string $content The CSS
|
||||
* @param mixed $callback A PHP callable
|
||||
*
|
||||
* @return string The filtered CSS
|
||||
*/
|
||||
protected function filterReferences($content, $callback, $limit = -1, & $count = 0)
|
||||
{
|
||||
$content = $this->filterUrls($content, $callback, $limit, $count);
|
||||
$content = $this->filterImports($content, $callback, $limit, $count, false);
|
||||
|
||||
return $content;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters all CSS url()'s through a callable.
|
||||
*
|
||||
* @param string $content The CSS
|
||||
* @param mixed $callback A PHP callable
|
||||
* @param integer $limit Limit the number of replacements
|
||||
* @param integer $count Will be populated with the count
|
||||
*
|
||||
* @return string The filtered CSS
|
||||
*/
|
||||
protected function filterUrls($content, $callback, $limit = -1, & $count = 0)
|
||||
{
|
||||
return preg_replace_callback('/url\((["\']?)(?<url>.*?)(\\1)\)/', $callback, $content, $limit, $count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters all CSS imports through a callable.
|
||||
*
|
||||
* @param string $content The CSS
|
||||
* @param mixed $callback A PHP callable
|
||||
* @param integer $limit Limit the number of replacements
|
||||
* @param integer $count Will be populated with the count
|
||||
* @param Boolean $includeUrl Whether to include url() in the pattern
|
||||
*
|
||||
* @return string The filtered CSS
|
||||
*/
|
||||
protected function filterImports($content, $callback, $limit = -1, & $count = 0, $includeUrl = true)
|
||||
{
|
||||
$pattern = $includeUrl
|
||||
? '/@import (?:url\()?(\'|"|)(?<url>[^\'"\)\n\r]*)\1\)?;?/'
|
||||
: '/@import (?!url\()(\'|"|)(?<url>[^\'"\)\n\r]*)\1;?/';
|
||||
|
||||
return preg_replace_callback($pattern, $callback, $content, $limit, $count);
|
||||
}
|
||||
}
|
|
@ -1,45 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
|
||||
/**
|
||||
* A filter that wraps callables.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class CallablesFilter implements FilterInterface
|
||||
{
|
||||
private $loader;
|
||||
private $dumper;
|
||||
|
||||
public function __construct($loader = null, $dumper = null)
|
||||
{
|
||||
$this->loader = $loader;
|
||||
$this->dumper = $dumper;
|
||||
}
|
||||
|
||||
public function filterLoad(AssetInterface $asset)
|
||||
{
|
||||
if (null !== $callable = $this->loader) {
|
||||
$callable($asset);
|
||||
}
|
||||
}
|
||||
|
||||
public function filterDump(AssetInterface $asset)
|
||||
{
|
||||
if (null !== $callable = $this->dumper) {
|
||||
$callable($asset);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,73 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
use Assetic\Exception\FilterException;
|
||||
use Symfony\Component\Process\ProcessBuilder;
|
||||
|
||||
/**
|
||||
* Compiles CoffeeScript into Javascript.
|
||||
*
|
||||
* @link http://coffeescript.org/
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class CoffeeScriptFilter implements FilterInterface
|
||||
{
|
||||
private $coffeePath;
|
||||
private $nodePath;
|
||||
|
||||
// coffee options
|
||||
private $bare;
|
||||
|
||||
public function __construct($coffeePath = '/usr/bin/coffee', $nodePath = '/usr/bin/node')
|
||||
{
|
||||
$this->coffeePath = $coffeePath;
|
||||
$this->nodePath = $nodePath;
|
||||
}
|
||||
|
||||
public function setBare($bare)
|
||||
{
|
||||
$this->bare = $bare;
|
||||
}
|
||||
|
||||
public function filterLoad(AssetInterface $asset)
|
||||
{
|
||||
$input = tempnam(sys_get_temp_dir(), 'assetic_coffeescript');
|
||||
file_put_contents($input, $asset->getContent());
|
||||
|
||||
$pb = new ProcessBuilder(array(
|
||||
$this->nodePath,
|
||||
$this->coffeePath,
|
||||
'-cp',
|
||||
));
|
||||
|
||||
if ($this->bare) {
|
||||
$pb->add('--bare');
|
||||
}
|
||||
|
||||
$pb->add($input);
|
||||
$proc = $pb->getProcess();
|
||||
$code = $proc->run();
|
||||
unlink($input);
|
||||
|
||||
if (0 < $code) {
|
||||
throw FilterException::fromProcess($proc)->setInput($asset->getContent());
|
||||
}
|
||||
|
||||
$asset->setContent($proc->getOutput());
|
||||
}
|
||||
|
||||
public function filterDump(AssetInterface $asset)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,329 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter;
|
||||
|
||||
use Assetic\Exception\FilterException;
|
||||
use Assetic\Asset\AssetInterface;
|
||||
use Assetic\Filter\FilterInterface;
|
||||
use Symfony\Component\Process\ProcessBuilder;
|
||||
|
||||
/**
|
||||
* Loads Compass files.
|
||||
*
|
||||
* @link http://compass-style.org/
|
||||
* @author Maxime Thirouin <maxime.thirouin@gmail.com>
|
||||
*/
|
||||
class CompassFilter implements FilterInterface
|
||||
{
|
||||
private $compassPath;
|
||||
private $scss;
|
||||
|
||||
// sass options
|
||||
private $unixNewlines;
|
||||
private $debugInfo;
|
||||
private $cacheLocation;
|
||||
private $noCache;
|
||||
|
||||
// compass options
|
||||
private $force;
|
||||
private $style;
|
||||
private $quiet;
|
||||
private $boring;
|
||||
private $noLineComments;
|
||||
private $imagesDir;
|
||||
private $javascriptsDir;
|
||||
|
||||
// compass configuration file options
|
||||
private $plugins = array();
|
||||
private $loadPaths = array();
|
||||
private $httpPath;
|
||||
private $httpImagesPath;
|
||||
private $httpJavascriptsPath;
|
||||
|
||||
public function __construct($compassPath = '/usr/bin/compass')
|
||||
{
|
||||
$this->compassPath = $compassPath;
|
||||
$this->cacheLocation = sys_get_temp_dir();
|
||||
|
||||
if ('cli' !== php_sapi_name()) {
|
||||
$this->boring = true;
|
||||
}
|
||||
}
|
||||
|
||||
public function setScss($scss)
|
||||
{
|
||||
$this->scss = $scss;
|
||||
}
|
||||
|
||||
// sass options setters
|
||||
public function setUnixNewlines($unixNewlines)
|
||||
{
|
||||
$this->unixNewlines = $unixNewlines;
|
||||
}
|
||||
|
||||
public function setDebugInfo($debugInfo)
|
||||
{
|
||||
$this->debugInfo = $debugInfo;
|
||||
}
|
||||
|
||||
public function setCacheLocation($cacheLocation)
|
||||
{
|
||||
$this->cacheLocation = $cacheLocation;
|
||||
}
|
||||
|
||||
public function setNoCache($noCache)
|
||||
{
|
||||
$this->noCache = $noCache;
|
||||
}
|
||||
|
||||
// compass options setters
|
||||
public function setForce($force)
|
||||
{
|
||||
$this->force = $force;
|
||||
}
|
||||
|
||||
public function setStyle($style)
|
||||
{
|
||||
$this->style = $style;
|
||||
}
|
||||
|
||||
public function setQuiet($quiet)
|
||||
{
|
||||
$this->quiet = $quiet;
|
||||
}
|
||||
|
||||
public function setBoring($boring)
|
||||
{
|
||||
$this->boring = $boring;
|
||||
}
|
||||
|
||||
public function setNoLineComments($noLineComments)
|
||||
{
|
||||
$this->noLineComments = $noLineComments;
|
||||
}
|
||||
|
||||
public function setImagesDir($imagesDir)
|
||||
{
|
||||
$this->imagesDir = $imagesDir;
|
||||
}
|
||||
|
||||
public function setJavascriptsDir($javascriptsDir)
|
||||
{
|
||||
$this->javascriptsDir = $javascriptsDir;
|
||||
}
|
||||
|
||||
// compass configuration file options setters
|
||||
public function setPlugins(array $plugins)
|
||||
{
|
||||
$this->plugins = $plugins;
|
||||
}
|
||||
|
||||
public function addPlugin($plugin)
|
||||
{
|
||||
$this->plugins[] = $plugin;
|
||||
}
|
||||
|
||||
public function addLoadPath($loadPath)
|
||||
{
|
||||
$this->loadPaths[] = $loadPath;
|
||||
}
|
||||
|
||||
public function setHttpPath($httpPath)
|
||||
{
|
||||
$this->httpPath = $httpPath;
|
||||
}
|
||||
|
||||
public function setHttpImagesPath($httpImagesPath)
|
||||
{
|
||||
$this->httpImagesPath = $httpImagesPath;
|
||||
}
|
||||
|
||||
public function setHttpJavascriptsPath($httpJavascriptsPath)
|
||||
{
|
||||
$this->httpJavascriptsPath = $httpJavascriptsPath;
|
||||
}
|
||||
|
||||
public function filterLoad(AssetInterface $asset)
|
||||
{
|
||||
$root = $asset->getSourceRoot();
|
||||
$path = $asset->getSourcePath();
|
||||
|
||||
$loadPaths = $this->loadPaths;
|
||||
if ($root && $path) {
|
||||
$loadPaths[] = dirname($root.'/'.$path);
|
||||
}
|
||||
|
||||
// compass does not seems to handle symlink, so we use realpath()
|
||||
$tempDir = realpath(sys_get_temp_dir());
|
||||
|
||||
$pb = new ProcessBuilder(array(
|
||||
$this->compassPath,
|
||||
'compile',
|
||||
$tempDir,
|
||||
));
|
||||
$pb->inheritEnvironmentVariables();
|
||||
|
||||
if ($this->force) {
|
||||
$pb->add('--force');
|
||||
}
|
||||
|
||||
if ($this->style) {
|
||||
$pb->add('--output-style')->add($this->style);
|
||||
}
|
||||
|
||||
if ($this->quiet) {
|
||||
$pb->add('--quiet');
|
||||
}
|
||||
|
||||
if ($this->boring) {
|
||||
$pb->add('--boring');
|
||||
}
|
||||
|
||||
if ($this->noLineComments) {
|
||||
$pb->add('--no-line-comments');
|
||||
}
|
||||
|
||||
// these two options are not passed into the config file
|
||||
// because like this, compass adapts this to be xxx_dir or xxx_path
|
||||
// whether it's an absolute path or not
|
||||
if ($this->imagesDir) {
|
||||
$pb->add('--images-dir')->add($this->imagesDir);
|
||||
}
|
||||
|
||||
if ($this->javascriptsDir) {
|
||||
$pb->add('--javascripts-dir')->add($this->javascriptsDir);
|
||||
}
|
||||
|
||||
// options in config file
|
||||
$optionsConfig = array();
|
||||
|
||||
if (!empty($loadPaths)) {
|
||||
$optionsConfig['additional_import_paths'] = $loadPaths;
|
||||
}
|
||||
|
||||
if ($this->unixNewlines) {
|
||||
$optionsConfig['sass_options']['unix_newlines'] = true;
|
||||
}
|
||||
|
||||
if ($this->debugInfo) {
|
||||
$optionsConfig['sass_options']['debug_info'] = true;
|
||||
}
|
||||
|
||||
if ($this->cacheLocation) {
|
||||
$optionsConfig['sass_options']['cache_location'] = $this->cacheLocation;
|
||||
}
|
||||
|
||||
if ($this->noCache) {
|
||||
$optionsConfig['sass_options']['no_cache'] = true;
|
||||
}
|
||||
|
||||
if ($this->httpPath) {
|
||||
$optionsConfig['http_path'] = $this->httpPath;
|
||||
}
|
||||
|
||||
if ($this->httpImagesPath) {
|
||||
$optionsConfig['http_images_path'] = $this->httpImagesPath;
|
||||
}
|
||||
|
||||
if ($this->httpJavascriptsPath) {
|
||||
$optionsConfig['http_javascripts_path'] = $this->httpJavascriptsPath;
|
||||
}
|
||||
|
||||
// options in configuration file
|
||||
if (count($optionsConfig)) {
|
||||
$config = array();
|
||||
foreach ($this->plugins as $plugin) {
|
||||
$config[] = sprintf("require '%s'", addcslashes($plugin, '\\'));
|
||||
}
|
||||
foreach ($optionsConfig as $name => $value) {
|
||||
if (!is_array($value)) {
|
||||
$config[] = sprintf('%s = "%s"', $name, addcslashes($value, '\\'));
|
||||
} elseif (!empty($value)) {
|
||||
$config[] = sprintf('%s = %s', $name, $this->formatArrayToRuby($value));
|
||||
}
|
||||
}
|
||||
|
||||
$configFile = tempnam($tempDir, 'assetic_compass');
|
||||
file_put_contents($configFile, implode("\n", $config)."\n");
|
||||
$pb->add('--config')->add($configFile);
|
||||
}
|
||||
|
||||
$pb->add('--sass-dir')->add('')->add('--css-dir')->add('');
|
||||
|
||||
// compass choose the type (sass or scss from the filename)
|
||||
if (null !== $this->scss) {
|
||||
$type = $this->scss ? 'scss' : 'sass';
|
||||
} elseif ($path) {
|
||||
// FIXME: what if the extension is something else?
|
||||
$type = pathinfo($path, PATHINFO_EXTENSION);
|
||||
} else {
|
||||
$type = 'scss';
|
||||
}
|
||||
|
||||
$tempName = tempnam($tempDir, 'assetic_compass');
|
||||
unlink($tempName); // FIXME: don't use tempnam() here
|
||||
|
||||
// input
|
||||
$pb->add($input = $tempName.'.'.$type);
|
||||
file_put_contents($input, $asset->getContent());
|
||||
|
||||
// output
|
||||
$output = $tempName.'.css';
|
||||
|
||||
// it's not really usefull but... https://github.com/chriseppstein/compass/issues/376
|
||||
$pb->setEnv('HOME', sys_get_temp_dir());
|
||||
|
||||
$proc = $pb->getProcess();
|
||||
$code = $proc->run();
|
||||
|
||||
if (0 < $code) {
|
||||
unlink($input);
|
||||
if (isset($configFile)) {
|
||||
unlink($configFile);
|
||||
}
|
||||
|
||||
throw FilterException::fromProcess($proc)->setInput($asset->getContent());
|
||||
}
|
||||
|
||||
$asset->setContent(file_get_contents($output));
|
||||
|
||||
unlink($input);
|
||||
unlink($output);
|
||||
if (isset($configFile)) {
|
||||
unlink($configFile);
|
||||
}
|
||||
}
|
||||
|
||||
public function filterDump(AssetInterface $asset)
|
||||
{
|
||||
}
|
||||
|
||||
private function formatArrayToRuby($array)
|
||||
{
|
||||
$output = array();
|
||||
|
||||
// does we have an associative array ?
|
||||
if (count(array_filter(array_keys($array), "is_numeric")) != count($array)) {
|
||||
foreach($array as $name => $value) {
|
||||
$output[] = sprintf(' :%s => "%s"', $name, addcslashes($value, '\\'));
|
||||
}
|
||||
$output = "{\n".implode(",\n", $output)."\n}";
|
||||
} else {
|
||||
foreach($array as $name => $value) {
|
||||
$output[] = sprintf(' "%s"', addcslashes($value, '\\'));
|
||||
}
|
||||
$output = "[\n".implode(",\n", $output)."\n]";
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
}
|
|
@ -1,139 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
use Assetic\Exception\FilterException;
|
||||
use Symfony\Component\Process\ProcessBuilder;
|
||||
|
||||
/**
|
||||
* CSSEmbed filter
|
||||
*
|
||||
* @link https://github.com/nzakas/cssembed
|
||||
* @author Maxime Thirouin <maxime.thirouin@gmail.com>
|
||||
*/
|
||||
class CssEmbedFilter implements FilterInterface
|
||||
{
|
||||
private $jarPath;
|
||||
private $javaPath;
|
||||
private $charset;
|
||||
private $mhtml; // Enable MHTML mode.
|
||||
private $mhtmlRoot; // Use <root> as the MHTML root for the file.
|
||||
private $root; // Prepends <root> to all relative URLs.
|
||||
private $skipMissing; // Don't throw an error for missing image files.
|
||||
private $maxUriLength; // Maximum length for a data URI. Defaults to 32768.
|
||||
private $maxImageSize; // Maximum image size (in bytes) to convert.
|
||||
|
||||
public function __construct($jarPath, $javaPath = '/usr/bin/java')
|
||||
{
|
||||
$this->jarPath = $jarPath;
|
||||
$this->javaPath = $javaPath;
|
||||
}
|
||||
|
||||
public function setCharset($charset)
|
||||
{
|
||||
$this->charset = $charset;
|
||||
}
|
||||
|
||||
public function setMhtml($mhtml)
|
||||
{
|
||||
$this->mhtml = $mhtml;
|
||||
}
|
||||
|
||||
public function setMhtmlRoot($mhtmlRoot)
|
||||
{
|
||||
$this->mhtmlRoot = $mhtmlRoot;
|
||||
}
|
||||
|
||||
public function setRoot($root)
|
||||
{
|
||||
$this->root = $root;
|
||||
}
|
||||
|
||||
public function setSkipMissing($skipMissing)
|
||||
{
|
||||
$this->skipMissing = $skipMissing;
|
||||
}
|
||||
|
||||
public function setMaxUriLength($maxUriLength)
|
||||
{
|
||||
$this->maxUriLength = $maxUriLength;
|
||||
}
|
||||
|
||||
public function setMaxImageSize($maxImageSize)
|
||||
{
|
||||
$this->maxImageSize = $maxImageSize;
|
||||
}
|
||||
|
||||
public function filterLoad(AssetInterface $asset)
|
||||
{
|
||||
}
|
||||
|
||||
public function filterDump(AssetInterface $asset)
|
||||
{
|
||||
$pb = new ProcessBuilder(array(
|
||||
$this->javaPath,
|
||||
'-jar',
|
||||
$this->jarPath,
|
||||
));
|
||||
|
||||
if (null !== $this->charset) {
|
||||
$pb->add('--charset')->add($this->charset);
|
||||
}
|
||||
|
||||
if ($this->mhtml) {
|
||||
$pb->add('--mhtml');
|
||||
}
|
||||
|
||||
if (null !== $this->mhtmlRoot) {
|
||||
$pb->add('--mhtmlroot')->add($this->mhtmlRoot);
|
||||
}
|
||||
|
||||
// automatically define root if not already defined
|
||||
if (null === $this->root) {
|
||||
$root = $asset->getSourceRoot();
|
||||
$path = $asset->getSourcePath();
|
||||
|
||||
if ($root && $path) {
|
||||
$pb->add('--root')->add(dirname($root.'/'.$path));
|
||||
}
|
||||
} else {
|
||||
$pb->add('--root')->add($this->root);
|
||||
}
|
||||
|
||||
if ($this->skipMissing) {
|
||||
$pb->add('--skip-missing');
|
||||
}
|
||||
|
||||
if (null !== $this->maxUriLength) {
|
||||
$pb->add('--max-uri-length')->add($this->maxUriLength);
|
||||
}
|
||||
|
||||
if (null !== $this->maxImageSize) {
|
||||
$pb->add('--max-image-size')->add($this->maxImageSize);
|
||||
}
|
||||
|
||||
// input
|
||||
$pb->add($input = tempnam(sys_get_temp_dir(), 'assetic_cssembed'));
|
||||
file_put_contents($input, $asset->getContent());
|
||||
|
||||
$proc = $pb->getProcess();
|
||||
$code = $proc->run();
|
||||
unlink($input);
|
||||
|
||||
if (0 < $code) {
|
||||
throw FilterException::fromProcess($proc)->setInput($asset->getContent());
|
||||
}
|
||||
|
||||
$asset->setContent($proc->getOutput());
|
||||
}
|
||||
}
|
|
@ -1,107 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
use Assetic\Asset\FileAsset;
|
||||
use Assetic\Asset\HttpAsset;
|
||||
|
||||
/**
|
||||
* Inlines imported stylesheets.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class CssImportFilter extends BaseCssFilter
|
||||
{
|
||||
private $importFilter;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param FilterInterface $importFilter Filter for each imported asset
|
||||
*/
|
||||
public function __construct(FilterInterface $importFilter = null)
|
||||
{
|
||||
$this->importFilter = $importFilter ?: new CssRewriteFilter();
|
||||
}
|
||||
|
||||
public function filterLoad(AssetInterface $asset)
|
||||
{
|
||||
$importFilter = $this->importFilter;
|
||||
$sourceRoot = $asset->getSourceRoot();
|
||||
$sourcePath = $asset->getSourcePath();
|
||||
|
||||
$callback = function($matches) use($importFilter, $sourceRoot, $sourcePath)
|
||||
{
|
||||
if (!$matches['url'] || null === $sourceRoot) {
|
||||
return $matches[0];
|
||||
}
|
||||
|
||||
$importRoot = $sourceRoot;
|
||||
|
||||
if (false !== strpos($matches['url'], '://')) {
|
||||
// absolute
|
||||
list($importScheme, $tmp) = explode('://', $matches['url'], 2);
|
||||
list($importHost, $importPath) = explode('/', $tmp, 2);
|
||||
$importRoot = $importScheme.'://'.$importHost;
|
||||
} elseif (0 === strpos($matches['url'], '//')) {
|
||||
// protocol-relative
|
||||
list($importHost, $importPath) = explode('/', substr($matches['url'], 2), 2);
|
||||
$importHost = '//'.$importHost;
|
||||
} elseif ('/' == $matches['url'][0]) {
|
||||
// root-relative
|
||||
$importPath = substr($matches['url'], 1);
|
||||
} elseif (null !== $sourcePath) {
|
||||
// document-relative
|
||||
$importPath = $matches['url'];
|
||||
if ('.' != $sourceDir = dirname($sourcePath)) {
|
||||
$importPath = $sourceDir.'/'.$importPath;
|
||||
}
|
||||
} else {
|
||||
return $matches[0];
|
||||
}
|
||||
|
||||
// ignore other imports
|
||||
if ('css' != pathinfo($importPath, PATHINFO_EXTENSION)) {
|
||||
return $matches[0];
|
||||
}
|
||||
|
||||
$importSource = $importRoot.'/'.$importPath;
|
||||
if (false !== strpos($importSource, '://') || 0 === strpos($importSource, '//')) {
|
||||
$import = new HttpAsset($importSource, array($importFilter), true);
|
||||
} elseif (!file_exists($importSource)) {
|
||||
// ignore not found imports
|
||||
return $matches[0];
|
||||
} else {
|
||||
$import = new FileAsset($importSource, array($importFilter), $importRoot, $importPath);
|
||||
}
|
||||
|
||||
$import->setTargetPath($sourcePath);
|
||||
|
||||
return $import->dump();
|
||||
};
|
||||
|
||||
$content = $asset->getContent();
|
||||
$lastHash = md5($content);
|
||||
|
||||
do {
|
||||
$content = $this->filterImports($content, $callback);
|
||||
$hash = md5($content);
|
||||
} while ($lastHash != $hash && $lastHash = $hash);
|
||||
|
||||
$asset->setContent($content);
|
||||
}
|
||||
|
||||
public function filterDump(AssetInterface $asset)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,74 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
|
||||
/**
|
||||
* Filters assets through CssMin.
|
||||
*
|
||||
* @link http://code.google.com/p/cssmin
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class CssMinFilter implements FilterInterface
|
||||
{
|
||||
private $filters;
|
||||
private $plugins;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->filters = array();
|
||||
$this->plugins = array();
|
||||
}
|
||||
|
||||
public function setFilters(array $filters)
|
||||
{
|
||||
$this->filters = $filters;
|
||||
}
|
||||
|
||||
public function setFilter($name, $value)
|
||||
{
|
||||
$this->filters[$name] = $value;
|
||||
}
|
||||
|
||||
public function setPlugins(array $plugins)
|
||||
{
|
||||
$this->plugins = $plugins;
|
||||
}
|
||||
|
||||
public function setPlugin($name, $value)
|
||||
{
|
||||
$this->plugins[$name] = $value;
|
||||
}
|
||||
|
||||
public function filterLoad(AssetInterface $asset)
|
||||
{
|
||||
}
|
||||
|
||||
public function filterDump(AssetInterface $asset)
|
||||
{
|
||||
$filters = $this->filters;
|
||||
$plugins = $this->plugins;
|
||||
|
||||
if (isset($filters['ImportImports']) && true === $filters['ImportImports']) {
|
||||
$root = $asset->getSourceRoot();
|
||||
$path = $asset->getSourcePath();
|
||||
if ($root && $path) {
|
||||
$filters['ImportImports'] = array('BasePath' => dirname($root.'/'.$path));
|
||||
} else {
|
||||
unset($filters['ImportImports']);
|
||||
}
|
||||
}
|
||||
|
||||
$asset->setContent(\CssMin::minify($asset->getContent(), $filters, $plugins));
|
||||
}
|
||||
}
|
|
@ -1,94 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
|
||||
/**
|
||||
* Fixes relative CSS urls.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class CssRewriteFilter extends BaseCssFilter
|
||||
{
|
||||
public function filterLoad(AssetInterface $asset)
|
||||
{
|
||||
}
|
||||
|
||||
public function filterDump(AssetInterface $asset)
|
||||
{
|
||||
$sourceBase = $asset->getSourceRoot();
|
||||
$sourcePath = $asset->getSourcePath();
|
||||
$targetPath = $asset->getTargetPath();
|
||||
|
||||
if (null === $sourcePath || null === $targetPath || $sourcePath == $targetPath) {
|
||||
return;
|
||||
}
|
||||
|
||||
// learn how to get from the target back to the source
|
||||
if (false !== strpos($sourceBase, '://')) {
|
||||
list($scheme, $url) = explode('://', $sourceBase.'/'.$sourcePath, 2);
|
||||
list($host, $path) = explode('/', $url, 2);
|
||||
|
||||
$host = $scheme.'://'.$host.'/';
|
||||
$path = false === strpos($path, '/') ? '' : dirname($path);
|
||||
$path .= '/';
|
||||
} else {
|
||||
// assume source and target are on the same host
|
||||
$host = '';
|
||||
|
||||
// pop entries off the target until it fits in the source
|
||||
if ('.' == dirname($sourcePath)) {
|
||||
$path = str_repeat('../', substr_count($targetPath, '/'));
|
||||
} elseif ('.' == $targetDir = dirname($targetPath)) {
|
||||
$path = dirname($sourcePath).'/';
|
||||
} else {
|
||||
$path = '';
|
||||
while (0 !== strpos($sourcePath, $targetDir)) {
|
||||
if (false !== $pos = strrpos($targetDir, '/')) {
|
||||
$targetDir = substr($targetDir, 0, $pos);
|
||||
$path .= '../';
|
||||
} else {
|
||||
$targetDir = '';
|
||||
$path .= '../';
|
||||
break;
|
||||
}
|
||||
}
|
||||
$path .= ltrim(substr(dirname($sourcePath).'/', strlen($targetDir)), '/');
|
||||
}
|
||||
}
|
||||
|
||||
$content = $this->filterReferences($asset->getContent(), function($matches) use($host, $path)
|
||||
{
|
||||
if (false !== strpos($matches['url'], '://') || 0 === strpos($matches['url'], '//') || 0 === strpos($matches['url'], 'data:')) {
|
||||
// absolute or protocol-relative or data uri
|
||||
return $matches[0];
|
||||
}
|
||||
|
||||
if ('/' == $matches['url'][0]) {
|
||||
// root relative
|
||||
return str_replace($matches['url'], $host.$matches['url'], $matches[0]);
|
||||
}
|
||||
|
||||
// document relative
|
||||
$url = $matches['url'];
|
||||
while (0 === strpos($url, '../') && 2 <= substr_count($path, '/')) {
|
||||
$path = substr($path, 0, strrpos(rtrim($path, '/'), '/') + 1);
|
||||
$url = substr($url, 3);
|
||||
}
|
||||
|
||||
return str_replace($matches['url'], $host.$path.$url, $matches[0]);
|
||||
});
|
||||
|
||||
$asset->setContent($content);
|
||||
}
|
||||
}
|
|
@ -1,82 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
|
||||
/**
|
||||
* A collection of filters.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class FilterCollection implements FilterInterface, \IteratorAggregate, \Countable
|
||||
{
|
||||
private $filters = array();
|
||||
|
||||
public function __construct($filters = array())
|
||||
{
|
||||
foreach ($filters as $filter) {
|
||||
$this->ensure($filter);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that the current collection contains the supplied filter.
|
||||
*
|
||||
* If the supplied filter is another filter collection, each of its
|
||||
* filters will be checked.
|
||||
*/
|
||||
public function ensure(FilterInterface $filter)
|
||||
{
|
||||
if ($filter instanceof \Traversable) {
|
||||
foreach ($filter as $f) {
|
||||
$this->ensure($f);
|
||||
}
|
||||
} elseif (!in_array($filter, $this->filters, true)) {
|
||||
$this->filters[] = $filter;
|
||||
}
|
||||
}
|
||||
|
||||
public function all()
|
||||
{
|
||||
return $this->filters;
|
||||
}
|
||||
|
||||
public function clear()
|
||||
{
|
||||
$this->filters = array();
|
||||
}
|
||||
|
||||
public function filterLoad(AssetInterface $asset)
|
||||
{
|
||||
foreach ($this->filters as $filter) {
|
||||
$filter->filterLoad($asset);
|
||||
}
|
||||
}
|
||||
|
||||
public function filterDump(AssetInterface $asset)
|
||||
{
|
||||
foreach ($this->filters as $filter) {
|
||||
$filter->filterDump($asset);
|
||||
}
|
||||
}
|
||||
|
||||
public function getIterator()
|
||||
{
|
||||
return new \ArrayIterator($this->filters);
|
||||
}
|
||||
|
||||
public function count()
|
||||
{
|
||||
return count($this->filters);
|
||||
}
|
||||
}
|
|
@ -1,36 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
|
||||
/**
|
||||
* A filter manipulates an asset at load and dump.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
interface FilterInterface
|
||||
{
|
||||
/**
|
||||
* Filters an asset after it has been loaded.
|
||||
*
|
||||
* @param AssetInterface $asset An asset
|
||||
*/
|
||||
function filterLoad(AssetInterface $asset);
|
||||
|
||||
/**
|
||||
* Filters an asset just before it's dumped.
|
||||
*
|
||||
* @param AssetInterface $asset An asset
|
||||
*/
|
||||
function filterDump(AssetInterface $asset);
|
||||
}
|
|
@ -1,84 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter\GoogleClosure;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
use Assetic\Filter\FilterInterface;
|
||||
|
||||
/**
|
||||
* Base filter for the Google Closure Compiler implementations.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
abstract class BaseCompilerFilter implements FilterInterface
|
||||
{
|
||||
// compilation levels
|
||||
const COMPILE_WHITESPACE_ONLY = 'WHITESPACE_ONLY';
|
||||
const COMPILE_SIMPLE_OPTIMIZATIONS = 'SIMPLE_OPTIMIZATIONS';
|
||||
const COMPILE_ADVANCED_OPTIMIZATIONS = 'ADVANCED_OPTIMIZATIONS';
|
||||
|
||||
// formatting modes
|
||||
const FORMAT_PRETTY_PRINT = 'pretty_print';
|
||||
const FORMAT_PRINT_INPUT_DELIMITER = 'print_input_delimiter';
|
||||
|
||||
// warning levels
|
||||
const LEVEL_QUIET = 'QUIET';
|
||||
const LEVEL_DEFAULT = 'DEFAULT';
|
||||
const LEVEL_VERBOSE = 'VERBOSE';
|
||||
|
||||
protected $compilationLevel;
|
||||
protected $jsExterns;
|
||||
protected $externsUrl;
|
||||
protected $excludeDefaultExterns;
|
||||
protected $formatting;
|
||||
protected $useClosureLibrary;
|
||||
protected $warningLevel;
|
||||
|
||||
public function setCompilationLevel($compilationLevel)
|
||||
{
|
||||
$this->compilationLevel = $compilationLevel;
|
||||
}
|
||||
|
||||
public function setJsExterns($jsExterns)
|
||||
{
|
||||
$this->jsExterns = $jsExterns;
|
||||
}
|
||||
|
||||
public function setExternsUrl($externsUrl)
|
||||
{
|
||||
$this->externsUrl = $externsUrl;
|
||||
}
|
||||
|
||||
public function setExcludeDefaultExterns($excludeDefaultExterns)
|
||||
{
|
||||
$this->excludeDefaultExterns = $excludeDefaultExterns;
|
||||
}
|
||||
|
||||
public function setFormatting($formatting)
|
||||
{
|
||||
$this->formatting = $formatting;
|
||||
}
|
||||
|
||||
public function setUseClosureLibrary($useClosureLibrary)
|
||||
{
|
||||
$this->useClosureLibrary = $useClosureLibrary;
|
||||
}
|
||||
|
||||
public function setWarningLevel($warningLevel)
|
||||
{
|
||||
$this->warningLevel = $warningLevel;
|
||||
}
|
||||
|
||||
public function filterLoad(AssetInterface $asset)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter\GoogleClosure;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
|
||||
/**
|
||||
* Filter for the Google Closure Compiler API.
|
||||
*
|
||||
* @link https://developers.google.com/closure/compiler/
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class CompilerApiFilter extends BaseCompilerFilter
|
||||
{
|
||||
public function filterDump(AssetInterface $asset)
|
||||
{
|
||||
$query = array(
|
||||
'js_code' => $asset->getContent(),
|
||||
'output_format' => 'json',
|
||||
'output_info' => 'compiled_code',
|
||||
);
|
||||
|
||||
if (null !== $this->compilationLevel) {
|
||||
$query['compilation_level'] = $this->compilationLevel;
|
||||
}
|
||||
|
||||
if (null !== $this->jsExterns) {
|
||||
$query['js_externs'] = $this->jsExterns;
|
||||
}
|
||||
|
||||
if (null !== $this->externsUrl) {
|
||||
$query['externs_url'] = $this->externsUrl;
|
||||
}
|
||||
|
||||
if (null !== $this->excludeDefaultExterns) {
|
||||
$query['exclude_default_externs'] = $this->excludeDefaultExterns ? 'true' : 'false';
|
||||
}
|
||||
|
||||
if (null !== $this->formatting) {
|
||||
$query['formatting'] = $this->formatting;
|
||||
}
|
||||
|
||||
if (null !== $this->useClosureLibrary) {
|
||||
$query['use_closure_library'] = $this->useClosureLibrary ? 'true' : 'false';
|
||||
}
|
||||
|
||||
if (null !== $this->warningLevel) {
|
||||
$query['warning_level'] = $this->warningLevel;
|
||||
}
|
||||
|
||||
$context = stream_context_create(array('http' => array(
|
||||
'method' => 'POST',
|
||||
'header' => 'Content-Type: application/x-www-form-urlencoded',
|
||||
'content' => http_build_query($query),
|
||||
)));
|
||||
|
||||
$response = file_get_contents('http://closure-compiler.appspot.com/compile', false, $context);
|
||||
$data = json_decode($response);
|
||||
|
||||
if (isset($data->serverErrors) && 0 < count($data->serverErrors)) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \RuntimeException(sprintf('The Google Closure Compiler API threw some server errors: '.print_r($data->serverErrors, true)));
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
if (isset($data->errors) && 0 < count($data->errors)) {
|
||||
// @codeCoverageIgnoreStart
|
||||
throw new \RuntimeException(sprintf('The Google Closure Compiler API threw some errors: '.print_r($data->errors, true)));
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
$asset->setContent($data->compiledCode);
|
||||
}
|
||||
}
|
|
@ -1,90 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter\GoogleClosure;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
use Assetic\Exception\FilterException;
|
||||
use Symfony\Component\Process\ProcessBuilder;
|
||||
|
||||
/**
|
||||
* Filter for the Google Closure Compiler JAR.
|
||||
*
|
||||
* @link https://developers.google.com/closure/compiler/
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class CompilerJarFilter extends BaseCompilerFilter
|
||||
{
|
||||
private $jarPath;
|
||||
private $javaPath;
|
||||
|
||||
public function __construct($jarPath, $javaPath = '/usr/bin/java')
|
||||
{
|
||||
$this->jarPath = $jarPath;
|
||||
$this->javaPath = $javaPath;
|
||||
}
|
||||
|
||||
public function filterDump(AssetInterface $asset)
|
||||
{
|
||||
$cleanup = array();
|
||||
|
||||
$pb = new ProcessBuilder(array(
|
||||
$this->javaPath,
|
||||
'-jar',
|
||||
$this->jarPath,
|
||||
));
|
||||
|
||||
if (null !== $this->compilationLevel) {
|
||||
$pb->add('--compilation_level')->add($this->compilationLevel);
|
||||
}
|
||||
|
||||
if (null !== $this->jsExterns) {
|
||||
$cleanup[] = $externs = tempnam(sys_get_temp_dir(), 'assetic_google_closure_compiler');
|
||||
file_put_contents($externs, $this->jsExterns);
|
||||
$pb->add('--externs')->add($externs);
|
||||
}
|
||||
|
||||
if (null !== $this->externsUrl) {
|
||||
$cleanup[] = $externs = tempnam(sys_get_temp_dir(), 'assetic_google_closure_compiler');
|
||||
file_put_contents($externs, file_get_contents($this->externsUrl));
|
||||
$pb->add('--externs')->add($externs);
|
||||
}
|
||||
|
||||
if (null !== $this->excludeDefaultExterns) {
|
||||
$pb->add('--use_only_custom_externs');
|
||||
}
|
||||
|
||||
if (null !== $this->formatting) {
|
||||
$pb->add('--formatting')->add($this->formatting);
|
||||
}
|
||||
|
||||
if (null !== $this->useClosureLibrary) {
|
||||
$pb->add('--manage_closure_dependencies');
|
||||
}
|
||||
|
||||
if (null !== $this->warningLevel) {
|
||||
$pb->add('--warning_level')->add($this->warningLevel);
|
||||
}
|
||||
|
||||
$pb->add('--js')->add($cleanup[] = $input = tempnam(sys_get_temp_dir(), 'assetic_google_closure_compiler'));
|
||||
file_put_contents($input, $asset->getContent());
|
||||
|
||||
$proc = $pb->getProcess();
|
||||
$code = $proc->run();
|
||||
array_map('unlink', $cleanup);
|
||||
|
||||
if (0 < $code) {
|
||||
throw FilterException::fromProcess($proc)->setInput($asset->getContent());
|
||||
}
|
||||
|
||||
$asset->setContent($proc->getOutput());
|
||||
}
|
||||
}
|
|
@ -1,142 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
use Assetic\Exception\FilterException;
|
||||
use Symfony\Component\Process\ProcessBuilder;
|
||||
|
||||
/**
|
||||
* Filter for the Google Closure Stylesheets Compiler JAR.
|
||||
*
|
||||
* @link http://code.google.com/p/closure-stylesheets/
|
||||
* @author Matthias Krauser <matthias@krauser.eu>
|
||||
*/
|
||||
class GssFilter implements FilterInterface
|
||||
{
|
||||
private $jarPath;
|
||||
private $javaPath;
|
||||
private $allowUnrecognizedFunctions;
|
||||
private $allowedNonStandardFunctions;
|
||||
private $copyrightNotice;
|
||||
private $define;
|
||||
private $gssFunctionMapProvider;
|
||||
private $inputOrientation;
|
||||
private $outputOrientation;
|
||||
private $prettyPrint;
|
||||
|
||||
public function __construct($jarPath, $javaPath = '/usr/bin/java')
|
||||
{
|
||||
$this->jarPath = $jarPath;
|
||||
$this->javaPath = $javaPath;
|
||||
}
|
||||
|
||||
public function setAllowUnrecognizedFunctions($allowUnrecognizedFunctions)
|
||||
{
|
||||
$this->allowUnrecognizedFunctions = $allowUnrecognizedFunctions;
|
||||
}
|
||||
|
||||
public function setAllowedNonStandardFunctions($allowNonStandardFunctions)
|
||||
{
|
||||
$this->allowedNonStandardFunctions = $allowNonStandardFunctions;
|
||||
}
|
||||
|
||||
public function setCopyrightNotice($copyrightNotice)
|
||||
{
|
||||
$this->copyrightNotice = $copyrightNotice;
|
||||
}
|
||||
|
||||
public function setDefine($define)
|
||||
{
|
||||
$this->define = $define;
|
||||
}
|
||||
|
||||
public function setGssFunctionMapProvider($gssFunctionMapProvider)
|
||||
{
|
||||
$this->gssFunctionMapProvider = $gssFunctionMapProvider;
|
||||
}
|
||||
|
||||
public function setInputOrientation($inputOrientation)
|
||||
{
|
||||
$this->inputOrientation = $inputOrientation;
|
||||
}
|
||||
|
||||
public function setOutputOrientation($outputOrientation)
|
||||
{
|
||||
$this->outputOrientation = $outputOrientation;
|
||||
}
|
||||
|
||||
public function setPrettyPrint($prettyPrint)
|
||||
{
|
||||
$this->prettyPrint = $prettyPrint;
|
||||
}
|
||||
|
||||
public function filterLoad(AssetInterface $asset)
|
||||
{
|
||||
$cleanup = array();
|
||||
|
||||
$pb = new ProcessBuilder(array(
|
||||
$this->javaPath,
|
||||
'-jar',
|
||||
$this->jarPath,
|
||||
));
|
||||
|
||||
if (null !== $this->allowUnrecognizedFunctions) {
|
||||
$pb->add('--allow-unrecognized-functions');
|
||||
}
|
||||
|
||||
if (null !== $this->allowedNonStandardFunctions) {
|
||||
$pb->add('--allowed_non_standard_functions')->add($this->allowedNonStandardFunctions);
|
||||
}
|
||||
|
||||
if (null !== $this->copyrightNotice) {
|
||||
$pb->add('--copyright-notice')->add($this->copyrightNotice);
|
||||
}
|
||||
|
||||
if (null !== $this->define) {
|
||||
$pb->add('--define')->add($this->define);
|
||||
}
|
||||
|
||||
if (null !== $this->gssFunctionMapProvider) {
|
||||
$pb->add('--gss-function-map-provider')->add($this->gssFunctionMapProvider);
|
||||
}
|
||||
|
||||
if (null !== $this->inputOrientation) {
|
||||
$pb->add('--input-orientation')->add($this->inputOrientation);
|
||||
}
|
||||
|
||||
if (null !== $this->outputOrientation) {
|
||||
$pb->add('--output-orientation')->add($this->outputOrientation);
|
||||
}
|
||||
|
||||
if (null !== $this->prettyPrint) {
|
||||
$pb->add('--pretty-print');
|
||||
}
|
||||
|
||||
$pb->add($cleanup[] = $input = tempnam(sys_get_temp_dir(), 'assetic_google_closure_stylesheets_compiler'));
|
||||
file_put_contents($input, $asset->getContent());
|
||||
|
||||
$proc = $pb->getProcess();
|
||||
$code = $proc->run();
|
||||
array_map('unlink', $cleanup);
|
||||
|
||||
if (0 < $code) {
|
||||
throw FilterException::fromProcess($proc)->setInput($asset->getContent());
|
||||
}
|
||||
|
||||
$asset->setContent($proc->getOutput());
|
||||
}
|
||||
|
||||
public function filterDump(AssetInterface $asset)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,81 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
use Assetic\Exception\FilterException;
|
||||
use Symfony\Component\Process\ProcessBuilder;
|
||||
|
||||
/**
|
||||
* Runs assets through Jpegoptim.
|
||||
*
|
||||
* @link http://www.kokkonen.net/tjko/projects.html
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class JpegoptimFilter implements FilterInterface
|
||||
{
|
||||
private $jpegoptimBin;
|
||||
private $stripAll;
|
||||
private $max;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $jpegoptimBin Path to the jpegoptim binary
|
||||
*/
|
||||
public function __construct($jpegoptimBin = '/usr/bin/jpegoptim')
|
||||
{
|
||||
$this->jpegoptimBin = $jpegoptimBin;
|
||||
}
|
||||
|
||||
public function setStripAll($stripAll)
|
||||
{
|
||||
$this->stripAll = $stripAll;
|
||||
}
|
||||
|
||||
public function setMax($max)
|
||||
{
|
||||
$this->max = $max;
|
||||
}
|
||||
|
||||
public function filterLoad(AssetInterface $asset)
|
||||
{
|
||||
}
|
||||
|
||||
public function filterDump(AssetInterface $asset)
|
||||
{
|
||||
$pb = new ProcessBuilder(array($this->jpegoptimBin));
|
||||
|
||||
if ($this->stripAll) {
|
||||
$pb->add('--strip-all');
|
||||
}
|
||||
|
||||
if ($this->max) {
|
||||
$pb->add('--max='.$this->max);
|
||||
}
|
||||
|
||||
$pb->add($input = tempnam(sys_get_temp_dir(), 'assetic_jpegoptim'));
|
||||
file_put_contents($input, $asset->getContent());
|
||||
|
||||
$proc = $pb->getProcess();
|
||||
$proc->run();
|
||||
|
||||
if (false !== strpos($proc->getOutput(), 'ERROR')) {
|
||||
unlink($input);
|
||||
throw FilterException::fromProcess($proc)->setInput($asset->getContent());
|
||||
}
|
||||
|
||||
$asset->setContent(file_get_contents($input));
|
||||
|
||||
unlink($input);
|
||||
}
|
||||
}
|
|
@ -1,103 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
use Assetic\Exception\FilterException;
|
||||
use Symfony\Component\Process\ProcessBuilder;
|
||||
|
||||
/**
|
||||
* Runs assets through jpegtran.
|
||||
*
|
||||
* @link http://jpegclub.org/jpegtran/
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class JpegtranFilter implements FilterInterface
|
||||
{
|
||||
const COPY_NONE = 'none';
|
||||
const COPY_COMMENTS = 'comments';
|
||||
const COPY_ALL = 'all';
|
||||
|
||||
private $jpegtranBin;
|
||||
private $optimize;
|
||||
private $copy;
|
||||
private $progressive;
|
||||
private $restart;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $jpegtranBin Path to the jpegtran binary
|
||||
*/
|
||||
public function __construct($jpegtranBin = '/usr/bin/jpegtran')
|
||||
{
|
||||
$this->jpegtranBin = $jpegtranBin;
|
||||
}
|
||||
|
||||
public function setOptimize($optimize)
|
||||
{
|
||||
$this->optimize = $optimize;
|
||||
}
|
||||
|
||||
public function setCopy($copy)
|
||||
{
|
||||
$this->copy = $copy;
|
||||
}
|
||||
|
||||
public function setProgressive($progressive)
|
||||
{
|
||||
$this->progressive = $progressive;
|
||||
}
|
||||
|
||||
public function setRestart($restart)
|
||||
{
|
||||
$this->restart = $restart;
|
||||
}
|
||||
|
||||
public function filterLoad(AssetInterface $asset)
|
||||
{
|
||||
}
|
||||
|
||||
public function filterDump(AssetInterface $asset)
|
||||
{
|
||||
$pb = new ProcessBuilder(array($this->jpegtranBin));
|
||||
|
||||
if ($this->optimize) {
|
||||
$pb->add('-optimize');
|
||||
}
|
||||
|
||||
if ($this->copy) {
|
||||
$pb->add('-copy')->add($this->copy);
|
||||
}
|
||||
|
||||
if ($this->progressive) {
|
||||
$pb->add('-progressive');
|
||||
}
|
||||
|
||||
if (null !== $this->restart) {
|
||||
$pb->add('-restart')->add($this->restart);
|
||||
}
|
||||
|
||||
$pb->add($input = tempnam(sys_get_temp_dir(), 'assetic_jpegtran'));
|
||||
file_put_contents($input, $asset->getContent());
|
||||
|
||||
$proc = $pb->getProcess();
|
||||
$code = $proc->run();
|
||||
unlink($input);
|
||||
|
||||
if (0 < $code) {
|
||||
throw FilterException::fromProcess($proc)->setInput($asset->getContent());
|
||||
}
|
||||
|
||||
$asset->setContent($proc->getOutput());
|
||||
}
|
||||
}
|
|
@ -1,114 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
use Assetic\Exception\FilterException;
|
||||
use Symfony\Component\Process\ProcessBuilder;
|
||||
|
||||
/**
|
||||
* Loads LESS files.
|
||||
*
|
||||
* @link http://lesscss.org/
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class LessFilter implements FilterInterface
|
||||
{
|
||||
private $nodeBin;
|
||||
private $nodePaths;
|
||||
private $compress;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $nodeBin The path to the node binary
|
||||
* @param array $nodePaths An array of node paths
|
||||
*/
|
||||
public function __construct($nodeBin = '/usr/bin/node', array $nodePaths = array())
|
||||
{
|
||||
$this->nodeBin = $nodeBin;
|
||||
$this->nodePaths = $nodePaths;
|
||||
}
|
||||
|
||||
public function setCompress($compress)
|
||||
{
|
||||
$this->compress = $compress;
|
||||
}
|
||||
|
||||
public function filterLoad(AssetInterface $asset)
|
||||
{
|
||||
static $format = <<<'EOF'
|
||||
var less = require('less');
|
||||
var sys = require(process.binding('natives').util ? 'util' : 'sys');
|
||||
|
||||
new(less.Parser)(%s).parse(%s, function(e, tree) {
|
||||
if (e) {
|
||||
less.writeError(e);
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
try {
|
||||
sys.print(tree.toCSS(%s));
|
||||
} catch (e) {
|
||||
less.writeError(e);
|
||||
process.exit(3);
|
||||
}
|
||||
});
|
||||
|
||||
EOF;
|
||||
|
||||
$root = $asset->getSourceRoot();
|
||||
$path = $asset->getSourcePath();
|
||||
|
||||
// parser options
|
||||
$parserOptions = array();
|
||||
if ($root && $path) {
|
||||
$parserOptions['paths'] = array(dirname($root.'/'.$path));
|
||||
$parserOptions['filename'] = basename($path);
|
||||
}
|
||||
|
||||
// tree options
|
||||
$treeOptions = array();
|
||||
if (null !== $this->compress) {
|
||||
$treeOptions['compress'] = $this->compress;
|
||||
}
|
||||
|
||||
$pb = new ProcessBuilder();
|
||||
$pb->inheritEnvironmentVariables();
|
||||
|
||||
// node.js configuration
|
||||
if (0 < count($this->nodePaths)) {
|
||||
$pb->setEnv('NODE_PATH', implode(':', $this->nodePaths));
|
||||
}
|
||||
|
||||
$pb->add($this->nodeBin)->add($input = tempnam(sys_get_temp_dir(), 'assetic_less'));
|
||||
file_put_contents($input, sprintf($format,
|
||||
json_encode($parserOptions),
|
||||
json_encode($asset->getContent()),
|
||||
json_encode($treeOptions)
|
||||
));
|
||||
|
||||
$proc = $pb->getProcess();
|
||||
$code = $proc->run();
|
||||
unlink($input);
|
||||
|
||||
if (0 < $code) {
|
||||
throw FilterException::fromProcess($proc)->setInput($asset->getContent());
|
||||
}
|
||||
|
||||
$asset->setContent($proc->getOutput());
|
||||
}
|
||||
|
||||
public function filterDump(AssetInterface $asset)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,48 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
|
||||
/**
|
||||
* Loads LESS files using the PHP implementation of less, lessphp.
|
||||
*
|
||||
* Less files are mostly compatible, but there are slight differences.
|
||||
*
|
||||
* To use this, you need to clone https://github.com/leafo/lessphp and make
|
||||
* sure to either include lessphp.inc.php or tell your autoloader that's where
|
||||
* lessc is located.
|
||||
*
|
||||
* @link http://leafo.net/lessphp/
|
||||
*
|
||||
* @author David Buchmann <david@liip.ch>
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class LessphpFilter implements FilterInterface
|
||||
{
|
||||
public function filterLoad(AssetInterface $asset)
|
||||
{
|
||||
$root = $asset->getSourceRoot();
|
||||
$path = $asset->getSourcePath();
|
||||
|
||||
$lc = new \lessc();
|
||||
if ($root && $path) {
|
||||
$lc->importDir = dirname($root.'/'.$path);
|
||||
}
|
||||
|
||||
$asset->setContent($lc->parse($asset->getContent()));
|
||||
}
|
||||
|
||||
public function filterDump(AssetInterface $asset)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,75 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
use Assetic\Exception\FilterException;
|
||||
use Symfony\Component\Process\ProcessBuilder;
|
||||
|
||||
/**
|
||||
* Runs assets through OptiPNG.
|
||||
*
|
||||
* @link http://optipng.sourceforge.net/
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class OptiPngFilter implements FilterInterface
|
||||
{
|
||||
private $optipngBin;
|
||||
private $level;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $optipngBin Path to the optipng binary
|
||||
*/
|
||||
public function __construct($optipngBin = '/usr/bin/optipng')
|
||||
{
|
||||
$this->optipngBin = $optipngBin;
|
||||
}
|
||||
|
||||
public function setLevel($level)
|
||||
{
|
||||
$this->level = $level;
|
||||
}
|
||||
|
||||
public function filterLoad(AssetInterface $asset)
|
||||
{
|
||||
}
|
||||
|
||||
public function filterDump(AssetInterface $asset)
|
||||
{
|
||||
$pb = new ProcessBuilder(array($this->optipngBin));
|
||||
|
||||
if (null !== $this->level) {
|
||||
$pb->add('-o')->add($this->level);
|
||||
}
|
||||
|
||||
$pb->add('-out')->add($output = tempnam(sys_get_temp_dir(), 'assetic_optipng'));
|
||||
unlink($output);
|
||||
|
||||
$pb->add($input = tempnam(sys_get_temp_dir(), 'assetic_optipng'));
|
||||
file_put_contents($input, $asset->getContent());
|
||||
|
||||
$proc = $pb->getProcess();
|
||||
$code = $proc->run();
|
||||
|
||||
if (0 < $code) {
|
||||
unlink($input);
|
||||
throw FilterException::fromProcess($proc)->setInput($asset->getContent());
|
||||
}
|
||||
|
||||
$asset->setContent(file_get_contents($output));
|
||||
|
||||
unlink($input);
|
||||
unlink($output);
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
|
||||
/**
|
||||
* Runs assets through Packager.
|
||||
*
|
||||
* @link https://github.com/kamicane/packager
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class PackagerFilter implements FilterInterface
|
||||
{
|
||||
private $packages;
|
||||
|
||||
public function __construct(array $packages = array())
|
||||
{
|
||||
$this->packages = $packages;
|
||||
}
|
||||
|
||||
public function addPackage($package)
|
||||
{
|
||||
$this->packages[] = $package;
|
||||
}
|
||||
|
||||
public function filterLoad(AssetInterface $asset)
|
||||
{
|
||||
static $manifest = <<<EOF
|
||||
name: Application%s
|
||||
sources: [source.js]
|
||||
|
||||
EOF;
|
||||
|
||||
$hash = substr(sha1(time().rand(11111, 99999)), 0, 7);
|
||||
$package = sys_get_temp_dir().'/assetic_packager_'.$hash;
|
||||
|
||||
mkdir($package);
|
||||
file_put_contents($package.'/package.yml', sprintf($manifest, $hash));
|
||||
file_put_contents($package.'/source.js', $asset->getContent());
|
||||
|
||||
$packager = new \Packager(array_merge(array($package), $this->packages));
|
||||
$content = $packager->build(array(), array(), array('Application'.$hash));
|
||||
|
||||
unlink($package.'/package.yml');
|
||||
unlink($package.'/source.js');
|
||||
rmdir($package);
|
||||
|
||||
$asset->setContent($content);
|
||||
}
|
||||
|
||||
public function filterDump(AssetInterface $asset)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,128 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
use Assetic\Exception\FilterException;
|
||||
use Symfony\Component\Process\ProcessBuilder;
|
||||
|
||||
/**
|
||||
* Runs assets through pngout.
|
||||
*
|
||||
* @link http://advsys.net/ken/utils.htm#pngout
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class PngoutFilter implements FilterInterface
|
||||
{
|
||||
// -c#
|
||||
const COLOR_GREY = '0';
|
||||
const COLOR_RGB = '2';
|
||||
const COLOR_PAL = '3';
|
||||
const COLOR_GRAY_ALPHA = '4';
|
||||
const COLOR_RGB_ALPHA = '6';
|
||||
|
||||
// -f#
|
||||
const FILTER_NONE = '0';
|
||||
const FILTER_X = '1';
|
||||
const FILTER_Y = '2';
|
||||
const FILTER_X_Y = '3';
|
||||
const FILTER_PAETH = '4';
|
||||
const FILTER_MIXED = '5';
|
||||
|
||||
// -s#
|
||||
const STRATEGY_XTREME = '0';
|
||||
const STRATEGY_INTENSE = '1';
|
||||
const STRATEGY_LONGEST_MATCH = '2';
|
||||
const STRATEGY_HUFFMAN_ONLY = '3';
|
||||
const STRATEGY_UNCOMPRESSED = '4';
|
||||
|
||||
private $pngoutBin;
|
||||
private $color;
|
||||
private $filter;
|
||||
private $strategy;
|
||||
private $blockSplitThreshold;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $pngoutBin Path to the pngout binary
|
||||
*/
|
||||
public function __construct($pngoutBin = '/usr/bin/pngout')
|
||||
{
|
||||
$this->pngoutBin = $pngoutBin;
|
||||
}
|
||||
|
||||
public function setColor($color)
|
||||
{
|
||||
$this->color = $color;
|
||||
}
|
||||
|
||||
public function setFilter($filter)
|
||||
{
|
||||
$this->filter = $filter;
|
||||
}
|
||||
|
||||
public function setStrategy($strategy)
|
||||
{
|
||||
$this->strategy = $strategy;
|
||||
}
|
||||
|
||||
public function setBlockSplitThreshold($blockSplitThreshold)
|
||||
{
|
||||
$this->blockSplitThreshold = $blockSplitThreshold;
|
||||
}
|
||||
|
||||
public function filterLoad(AssetInterface $asset)
|
||||
{
|
||||
}
|
||||
|
||||
public function filterDump(AssetInterface $asset)
|
||||
{
|
||||
$pb = new ProcessBuilder(array($this->pngoutBin));
|
||||
|
||||
if (null !== $this->color) {
|
||||
$pb->add('-c'.$this->color);
|
||||
}
|
||||
|
||||
if (null !== $this->filter) {
|
||||
$pb->add('-f'.$this->filter);
|
||||
}
|
||||
|
||||
if (null !== $this->strategy) {
|
||||
$pb->add('-s'.$this->strategy);
|
||||
}
|
||||
|
||||
if (null !== $this->blockSplitThreshold) {
|
||||
$pb->add('-b'.$this->blockSplitThreshold);
|
||||
}
|
||||
|
||||
$pb->add($input = tempnam(sys_get_temp_dir(), 'assetic_pngout'));
|
||||
file_put_contents($input, $asset->getContent());
|
||||
|
||||
$output = tempnam(sys_get_temp_dir(), 'assetic_pngout');
|
||||
unlink($output);
|
||||
$pb->add($output .= '.png');
|
||||
|
||||
$proc = $pb->getProcess();
|
||||
$code = $proc->run();
|
||||
|
||||
if (0 < $code) {
|
||||
unlink($input);
|
||||
throw FilterException::fromProcess($proc)->setInput($asset->getContent());
|
||||
}
|
||||
|
||||
$asset->setContent(file_get_contents($output));
|
||||
|
||||
unlink($input);
|
||||
unlink($output);
|
||||
}
|
||||
}
|
|
@ -1,169 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter\Sass;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
use Assetic\Filter\FilterInterface;
|
||||
use Assetic\Exception\FilterException;
|
||||
use Symfony\Component\Process\ProcessBuilder;
|
||||
|
||||
/**
|
||||
* Loads SASS files.
|
||||
*
|
||||
* @link http://sass-lang.com/
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class SassFilter implements FilterInterface
|
||||
{
|
||||
const STYLE_NESTED = 'nested';
|
||||
const STYLE_EXPANDED = 'expanded';
|
||||
const STYLE_COMPACT = 'compact';
|
||||
const STYLE_COMPRESSED = 'compressed';
|
||||
|
||||
private $sassPath;
|
||||
private $unixNewlines;
|
||||
private $scss;
|
||||
private $style;
|
||||
private $quiet;
|
||||
private $debugInfo;
|
||||
private $lineNumbers;
|
||||
private $loadPaths = array();
|
||||
private $cacheLocation;
|
||||
private $noCache;
|
||||
private $compass;
|
||||
|
||||
public function __construct($sassPath = '/usr/bin/sass')
|
||||
{
|
||||
$this->sassPath = $sassPath;
|
||||
$this->cacheLocation = realpath(sys_get_temp_dir());
|
||||
}
|
||||
|
||||
public function setUnixNewlines($unixNewlines)
|
||||
{
|
||||
$this->unixNewlines = $unixNewlines;
|
||||
}
|
||||
|
||||
public function setScss($scss)
|
||||
{
|
||||
$this->scss = $scss;
|
||||
}
|
||||
|
||||
public function setStyle($style)
|
||||
{
|
||||
$this->style = $style;
|
||||
}
|
||||
|
||||
public function setQuiet($quiet)
|
||||
{
|
||||
$this->quiet = $quiet;
|
||||
}
|
||||
|
||||
public function setDebugInfo($debugInfo)
|
||||
{
|
||||
$this->debugInfo = $debugInfo;
|
||||
}
|
||||
|
||||
public function setLineNumbers($lineNumbers)
|
||||
{
|
||||
$this->lineNumbers = $lineNumbers;
|
||||
}
|
||||
|
||||
public function addLoadPath($loadPath)
|
||||
{
|
||||
$this->loadPaths[] = $loadPath;
|
||||
}
|
||||
|
||||
public function setCacheLocation($cacheLocation)
|
||||
{
|
||||
$this->cacheLocation = $cacheLocation;
|
||||
}
|
||||
|
||||
public function setNoCache($noCache)
|
||||
{
|
||||
$this->noCache = $noCache;
|
||||
}
|
||||
|
||||
public function setCompass($compass)
|
||||
{
|
||||
$this->compass = $compass;
|
||||
}
|
||||
|
||||
public function filterLoad(AssetInterface $asset)
|
||||
{
|
||||
$pb = new ProcessBuilder(array($this->sassPath));
|
||||
|
||||
$root = $asset->getSourceRoot();
|
||||
$path = $asset->getSourcePath();
|
||||
|
||||
if ($root && $path) {
|
||||
$pb->add('--load-path')->add(dirname($root.'/'.$path));
|
||||
}
|
||||
|
||||
if ($this->unixNewlines) {
|
||||
$pb->add('--unix-newlines');
|
||||
}
|
||||
|
||||
if (true === $this->scss || (null === $this->scss && 'scss' == pathinfo($path, PATHINFO_EXTENSION))) {
|
||||
$pb->add('--scss');
|
||||
}
|
||||
|
||||
if ($this->style) {
|
||||
$pb->add('--style')->add($this->style);
|
||||
}
|
||||
|
||||
if ($this->quiet) {
|
||||
$pb->add('--quiet');
|
||||
}
|
||||
|
||||
if ($this->debugInfo) {
|
||||
$pb->add('--debug-info');
|
||||
}
|
||||
|
||||
if ($this->lineNumbers) {
|
||||
$pb->add('--line-numbers');
|
||||
}
|
||||
|
||||
foreach ($this->loadPaths as $loadPath) {
|
||||
$pb->add('--load-path')->add($loadPath);
|
||||
}
|
||||
|
||||
if ($this->cacheLocation) {
|
||||
$pb->add('--cache-location')->add($this->cacheLocation);
|
||||
}
|
||||
|
||||
if ($this->noCache) {
|
||||
$pb->add('--no-cache');
|
||||
}
|
||||
|
||||
if ($this->compass) {
|
||||
$pb->add('--compass');
|
||||
}
|
||||
|
||||
// input
|
||||
$pb->add($input = tempnam(sys_get_temp_dir(), 'assetic_sass'));
|
||||
file_put_contents($input, $asset->getContent());
|
||||
|
||||
$proc = $pb->getProcess();
|
||||
$code = $proc->run();
|
||||
unlink($input);
|
||||
|
||||
if (0 < $code) {
|
||||
throw FilterException::fromProcess($proc)->setInput($asset->getContent());
|
||||
}
|
||||
|
||||
$asset->setContent($proc->getOutput());
|
||||
}
|
||||
|
||||
public function filterDump(AssetInterface $asset)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter\Sass;
|
||||
|
||||
/**
|
||||
* Loads SCSS files.
|
||||
*
|
||||
* @link http://sass-lang.com/
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class ScssFilter extends SassFilter
|
||||
{
|
||||
public function __construct($sassPath = '/usr/bin/sass')
|
||||
{
|
||||
parent::__construct($sassPath);
|
||||
|
||||
$this->setScss(true);
|
||||
}
|
||||
}
|
|
@ -1,148 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
use Assetic\Exception\FilterException;
|
||||
use Symfony\Component\Process\ProcessBuilder;
|
||||
|
||||
/**
|
||||
* Runs assets through Sprockets.
|
||||
*
|
||||
* Requires Sprockets 1.0.x.
|
||||
*
|
||||
* @link http://getsprockets.org/
|
||||
* @link http://github.com/sstephenson/sprockets/tree/1.0.x
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class SprocketsFilter implements FilterInterface
|
||||
{
|
||||
private $sprocketsLib;
|
||||
private $rubyBin;
|
||||
private $includeDirs;
|
||||
private $assetRoot;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @param string $sprocketsLib Path to the Sprockets lib/ directory
|
||||
* @param string $rubyBin Path to the ruby binary
|
||||
*/
|
||||
public function __construct($sprocketsLib = null, $rubyBin = '/usr/bin/ruby')
|
||||
{
|
||||
$this->sprocketsLib = $sprocketsLib;
|
||||
$this->rubyBin = $rubyBin;
|
||||
$this->includeDirs = array();
|
||||
}
|
||||
|
||||
public function addIncludeDir($directory)
|
||||
{
|
||||
$this->includeDirs[] = $directory;
|
||||
}
|
||||
|
||||
public function setAssetRoot($assetRoot)
|
||||
{
|
||||
$this->assetRoot = $assetRoot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hack around a bit, get the job done.
|
||||
*/
|
||||
public function filterLoad(AssetInterface $asset)
|
||||
{
|
||||
static $format = <<<'EOF'
|
||||
#!/usr/bin/env ruby
|
||||
|
||||
require %s
|
||||
%s
|
||||
options = { :load_path => [],
|
||||
:source_files => [%s],
|
||||
:expand_paths => false }
|
||||
|
||||
%ssecretary = Sprockets::Secretary.new(options)
|
||||
secretary.install_assets if options[:asset_root]
|
||||
print secretary.concatenation
|
||||
|
||||
EOF;
|
||||
|
||||
$more = '';
|
||||
|
||||
foreach ($this->includeDirs as $directory) {
|
||||
$more .= 'options[:load_path] << '.var_export($directory, true)."\n";
|
||||
}
|
||||
|
||||
if (null !== $this->assetRoot) {
|
||||
$more .= 'options[:asset_root] = '.var_export($this->assetRoot, true)."\n";
|
||||
}
|
||||
|
||||
if ($more) {
|
||||
$more .= "\n";
|
||||
}
|
||||
|
||||
$tmpAsset = tempnam(sys_get_temp_dir(), 'assetic_sprockets');
|
||||
file_put_contents($tmpAsset, $asset->getContent());
|
||||
|
||||
$input = tempnam(sys_get_temp_dir(), 'assetic_sprockets');
|
||||
file_put_contents($input, sprintf($format,
|
||||
$this->sprocketsLib
|
||||
? sprintf('File.join(%s, \'sprockets\')', var_export($this->sprocketsLib, true))
|
||||
: '\'sprockets\'',
|
||||
$this->getHack($asset),
|
||||
var_export($tmpAsset, true),
|
||||
$more
|
||||
));
|
||||
|
||||
$pb = new ProcessBuilder(array(
|
||||
$this->rubyBin,
|
||||
$input,
|
||||
));
|
||||
|
||||
$proc = $pb->getProcess();
|
||||
$code = $proc->run();
|
||||
unlink($tmpAsset);
|
||||
unlink($input);
|
||||
|
||||
if (0 < $code) {
|
||||
throw FilterException::fromProcess($proc)->setInput($asset->getContent());
|
||||
}
|
||||
|
||||
$asset->setContent($proc->getOutput());
|
||||
}
|
||||
|
||||
public function filterDump(AssetInterface $asset)
|
||||
{
|
||||
}
|
||||
|
||||
private function getHack(AssetInterface $asset)
|
||||
{
|
||||
static $format = <<<'EOF'
|
||||
|
||||
module Sprockets
|
||||
class Preprocessor
|
||||
protected
|
||||
def pathname_for_relative_require_from(source_line)
|
||||
Sprockets::Pathname.new(@environment, File.join(%s, location_from(source_line)))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
EOF;
|
||||
|
||||
$root = $asset->getSourceRoot();
|
||||
$path = $asset->getSourcePath();
|
||||
|
||||
if ($root && $path) {
|
||||
return sprintf($format, var_export(dirname($root.'/'.$path), true));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,117 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
use Assetic\Exception\FilterException;
|
||||
use Symfony\Component\Process\ProcessBuilder;
|
||||
|
||||
/**
|
||||
* Loads STYL files.
|
||||
*
|
||||
* @link http://learnboost.github.com/stylus/
|
||||
* @author Konstantin Kudryashov <ever.zet@gmail.com>
|
||||
*/
|
||||
class StylusFilter implements FilterInterface
|
||||
{
|
||||
private $nodeBin;
|
||||
private $nodePaths;
|
||||
private $compress;
|
||||
|
||||
/**
|
||||
* Constructs filter.
|
||||
*
|
||||
* @param string $nodeBin The path to the node binary
|
||||
* @param array $nodePaths An array of node paths
|
||||
*/
|
||||
public function __construct($nodeBin = '/usr/bin/node', array $nodePaths = array())
|
||||
{
|
||||
$this->nodeBin = $nodeBin;
|
||||
$this->nodePaths = $nodePaths;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable output compression.
|
||||
*
|
||||
* @param boolean $compress
|
||||
*/
|
||||
public function setCompress($compress)
|
||||
{
|
||||
$this->compress = $compress;
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function filterLoad(AssetInterface $asset)
|
||||
{
|
||||
static $format = <<<'EOF'
|
||||
var stylus = require('stylus');
|
||||
var sys = require(process.binding('natives').util ? 'util' : 'sys');
|
||||
|
||||
stylus(%s, %s).render(function(e, css){
|
||||
if (e) {
|
||||
throw e;
|
||||
}
|
||||
|
||||
sys.print(css);
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
EOF;
|
||||
|
||||
$root = $asset->getSourceRoot();
|
||||
$path = $asset->getSourcePath();
|
||||
|
||||
// parser options
|
||||
$parserOptions = array();
|
||||
if ($root && $path) {
|
||||
$parserOptions['paths'] = array(dirname($root.'/'.$path));
|
||||
$parserOptions['filename'] = basename($path);
|
||||
}
|
||||
|
||||
if (null !== $this->compress) {
|
||||
$parserOptions['compress'] = $this->compress;
|
||||
}
|
||||
|
||||
$pb = new ProcessBuilder();
|
||||
$pb->inheritEnvironmentVariables();
|
||||
|
||||
// node.js configuration
|
||||
if (0 < count($this->nodePaths)) {
|
||||
$pb->setEnv('NODE_PATH', implode(':', $this->nodePaths));
|
||||
}
|
||||
|
||||
$pb->add($this->nodeBin)->add($input = tempnam(sys_get_temp_dir(), 'assetic_stylus'));
|
||||
file_put_contents($input, sprintf($format,
|
||||
json_encode($asset->getContent()),
|
||||
json_encode($parserOptions)
|
||||
));
|
||||
|
||||
$proc = $pb->getProcess();
|
||||
$code = $proc->run();
|
||||
unlink($input);
|
||||
|
||||
if (0 < $code) {
|
||||
throw FilterException::fromProcess($proc)->setInput($asset->getContent());
|
||||
}
|
||||
|
||||
$asset->setContent($proc->getOutput());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function filterDump(AssetInterface $asset)
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,108 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter\Yui;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
use Assetic\Filter\FilterInterface;
|
||||
use Assetic\Exception\FilterException;
|
||||
use Symfony\Component\Process\ProcessBuilder;
|
||||
|
||||
/**
|
||||
* Base YUI compressor filter.
|
||||
*
|
||||
* @link http://developer.yahoo.com/yui/compressor/
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
abstract class BaseCompressorFilter implements FilterInterface
|
||||
{
|
||||
private $jarPath;
|
||||
private $javaPath;
|
||||
private $charset;
|
||||
private $lineBreak;
|
||||
|
||||
public function __construct($jarPath, $javaPath = '/usr/bin/java')
|
||||
{
|
||||
$this->jarPath = $jarPath;
|
||||
$this->javaPath = $javaPath;
|
||||
}
|
||||
|
||||
public function setCharset($charset)
|
||||
{
|
||||
$this->charset = $charset;
|
||||
}
|
||||
|
||||
public function setLineBreak($lineBreak)
|
||||
{
|
||||
$this->lineBreak = $lineBreak;
|
||||
}
|
||||
|
||||
public function filterLoad(AssetInterface $asset)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Compresses a string.
|
||||
*
|
||||
* @param string $content The content to compress
|
||||
* @param string $type The type of content, either "js" or "css"
|
||||
* @param array $options An indexed array of additional options
|
||||
*
|
||||
* @return string The compressed content
|
||||
*/
|
||||
protected function compress($content, $type, $options = array())
|
||||
{
|
||||
$pb = new ProcessBuilder(array(
|
||||
$this->javaPath,
|
||||
'-jar',
|
||||
$this->jarPath,
|
||||
));
|
||||
|
||||
foreach ($options as $option) {
|
||||
$pb->add($option);
|
||||
}
|
||||
|
||||
if (null !== $this->charset) {
|
||||
$pb->add('--charset')->add($this->charset);
|
||||
}
|
||||
|
||||
if (null !== $this->lineBreak) {
|
||||
$pb->add('--line-break')->add($this->lineBreak);
|
||||
}
|
||||
|
||||
// input and output files
|
||||
$tempDir = realpath(sys_get_temp_dir());
|
||||
$hash = substr(sha1(time().rand(11111, 99999)), 0, 7);
|
||||
$input = $tempDir.DIRECTORY_SEPARATOR.$hash.'.'.$type;
|
||||
$output = $tempDir.DIRECTORY_SEPARATOR.$hash.'-min.'.$type;
|
||||
file_put_contents($input, $content);
|
||||
$pb->add('-o')->add($output)->add($input);
|
||||
|
||||
$proc = $pb->getProcess();
|
||||
$code = $proc->run();
|
||||
unlink($input);
|
||||
|
||||
if (0 < $code) {
|
||||
if (file_exists($output)) {
|
||||
unlink($output);
|
||||
}
|
||||
|
||||
throw FilterException::fromProcess($proc)->setInput($content);
|
||||
} elseif (!file_exists($output)) {
|
||||
throw new \RuntimeException('Error creating output file.');
|
||||
}
|
||||
|
||||
$retval = file_get_contents($output);
|
||||
unlink($output);
|
||||
|
||||
return $retval;
|
||||
}
|
||||
}
|
|
@ -1,28 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter\Yui;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
|
||||
/**
|
||||
* CSS YUI compressor filter.
|
||||
*
|
||||
* @link http://developer.yahoo.com/yui/compressor/
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class CssCompressorFilter extends BaseCompressorFilter
|
||||
{
|
||||
public function filterDump(AssetInterface $asset)
|
||||
{
|
||||
$asset->setContent($this->compress($asset->getContent(), 'css'));
|
||||
}
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic\Filter\Yui;
|
||||
|
||||
use Assetic\Asset\AssetInterface;
|
||||
|
||||
/**
|
||||
* Javascript YUI compressor filter.
|
||||
*
|
||||
* @link http://developer.yahoo.com/yui/compressor/
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class JsCompressorFilter extends BaseCompressorFilter
|
||||
{
|
||||
private $nomunge;
|
||||
private $preserveSemi;
|
||||
private $disableOptimizations;
|
||||
|
||||
public function setNomunge($nomunge = true)
|
||||
{
|
||||
$this->nomunge = $nomunge;
|
||||
}
|
||||
|
||||
public function setPreserveSemi($preserveSemi)
|
||||
{
|
||||
$this->preserveSemi = $preserveSemi;
|
||||
}
|
||||
|
||||
public function setDisableOptimizations($disableOptimizations)
|
||||
{
|
||||
$this->disableOptimizations = $disableOptimizations;
|
||||
}
|
||||
|
||||
public function filterDump(AssetInterface $asset)
|
||||
{
|
||||
$options = array();
|
||||
|
||||
if ($this->nomunge) {
|
||||
$options[] = '--nomunge';
|
||||
}
|
||||
|
||||
if ($this->preserveSemi) {
|
||||
$options[] = '--preserve-semi';
|
||||
}
|
||||
|
||||
if ($this->disableOptimizations) {
|
||||
$options[] = '--disable-optimizations';
|
||||
}
|
||||
|
||||
$asset->setContent($this->compress($asset->getContent(), 'js', $options));
|
||||
}
|
||||
}
|
|
@ -1,64 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
* This file is part of the Assetic package, an OpenSky project.
|
||||
*
|
||||
* (c) 2010-2011 OpenSky Project Inc
|
||||
*
|
||||
* For the full copyright and license information, please view the LICENSE
|
||||
* file that was distributed with this source code.
|
||||
*/
|
||||
|
||||
namespace Assetic;
|
||||
|
||||
use Assetic\Filter\FilterInterface;
|
||||
|
||||
/**
|
||||
* Manages the available filters.
|
||||
*
|
||||
* @author Kris Wallsmith <kris.wallsmith@gmail.com>
|
||||
*/
|
||||
class FilterManager
|
||||
{
|
||||
private $filters = array();
|
||||
|
||||
public function set($alias, FilterInterface $filter)
|
||||
{
|
||||
$this->checkName($alias);
|
||||
|
||||
$this->filters[$alias] = $filter;
|
||||
}
|
||||
|
||||
public function get($alias)
|
||||
{
|
||||
if (!isset($this->filters[$alias])) {
|
||||
throw new \InvalidArgumentException(sprintf('There is no "%s" filter.', $alias));
|
||||
}
|
||||
|
||||
return $this->filters[$alias];
|
||||
}
|
||||
|
||||
public function has($alias)
|
||||
{
|
||||
return isset($this->filters[$alias]);
|
||||
}
|
||||
|
||||
public function getNames()
|
||||
{
|
||||
return array_keys($this->filters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks that a name is valid.
|
||||
*
|
||||
* @param string $name An asset name candidate
|
||||
*
|
||||
* @throws InvalidArgumentException If the asset name is invalid
|
||||
*/
|
||||
protected function checkName($name)
|
||||
{
|
||||
if (!ctype_alnum(str_replace('_', '', $name))) {
|
||||
throw new \InvalidArgumentException(sprintf('The name "%s" is invalid.', $name));
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,31 +0,0 @@
|
|||
<?php
|
||||
|
||||
namespace Assetic\Util;
|
||||
|
||||
/**
|
||||
* Path Utils.
|
||||
*
|
||||
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
|
||||
*/
|
||||
abstract class PathUtils
|
||||
{
|
||||
public static function resolvePath($path, array $vars, array $values)
|
||||
{
|
||||
$map = array();
|
||||
foreach ($vars as $var) {
|
||||
if (false === strpos($path, '{'.$var.'}')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!isset($values[$var])) {
|
||||
throw new \InvalidArgumentException(sprintf('The path "%s" contains the variable "%s", but was not given any value for it.', $path, $var));
|
||||
}
|
||||
|
||||
$map['{'.$var.'}'] = $values[$var];
|
||||
}
|
||||
|
||||
return strtr($path, $map);
|
||||
}
|
||||
|
||||
private final function __construct() { }
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue