diff --git a/.gitignore b/.gitignore index a60ccb0..a632a8b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,33 +1,3 @@ -.foundation -library/Zend/ -library/Symfony/ -.buildpath -.project -.DS_Store -.settings/ -.foundation-tmp -phar -*.phar -tests/reports -pirum -nbproject -*.7z -*.jar -*.rar -*.zip -*.gz -*.bzip -*.xz -*.lzma -*.iso -*.tar -*.dmg -*.xpi -*.gem -*.egg -*.deb -*.rpm -*.tgz composer.lock +Makefile vendor/ -Rest.kdev4 diff --git a/.scrutinizer.yml b/.scrutinizer.yml new file mode 100644 index 0000000..ff12014 --- /dev/null +++ b/.scrutinizer.yml @@ -0,0 +1,21 @@ +filter: + excluded_paths: + - bin/* + - public/* + - tests/* + +checks: + php: + code_rating: true + +tools: + external_code_coverage: true + php_analyzer: true + php_changetracking: true + php_code_sniffer: + config: + standard: "PSR2" + php_cpd: true + php_mess_detector: true + php_pdepend: true + sensiolabs_security_checker: true diff --git a/.travis.yml b/.travis.yml index 4207f05..ab5f644 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,23 +1,32 @@ -# a Courtesy of Respect/Foundation +sudo: + false -language: php - -env: FOUNDATION_NO_WAIT=1 +language: + php php: - 5.3 - 5.4 - 5.5 + - 5.6 + - hhvm + - hhvm-nightly + +cache: + directories: + - vendor before_script: - - make composer-install-dev - - phpenv rehash + - composer install --dev --no-interaction --prefer-source script: - - make testdox + - vendor/bin/phpunit --configuration phpunit.xml.dist --colors --coverage-clover=coverage.clover + +after_script: + - wget https://scrutinizer-ci.com/ocular.phar + - php ocular.phar code-coverage:upload --format=php-clover coverage.clover -notifications: - irc: - channels: - - "irc.freenode.org#php-respect" - use_notice: true +matrix: + allow_failures: + - php: hhvm + - php: hhvm-nightly diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..5cf4e69 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,58 @@ +# Contributing to Respect\Rest + +Contributions to Respect\Rest are always welcome. You make our lives easier by +sending us your contributions through GitHub pull requests. + +Pull requests for bug fixes must be based on the current stable branch whereas +pull requests for new features must be based on `master`. + +Due to time constraints, we are not always able to respond as quickly as we +would like. Please do not take delays personal and feel free to remind us here, +on IRC, or on Gitter if you feel that we forgot to respond. + +## Using Respect\Rest From a Git Checkout + +The following commands can be used to perform the initial checkout of Respect\Rest: + +```shell +git clone git://github.com/Respect/Rest.git +cd Rest +``` + +Retrieve Respect\Rest's dependencies using [Composer](http://getcomposer.org/): + +```shell +composer install +``` + +## Running Tests + +After run `composer install` on the library's root directory you must run PHPUnit. + +### Linux + +You can test the project using the commands: +```shell +$ vendor/bin/phpunit +``` + +### Windows + +You can test the project using the commands: +```shell +> vendor\bin\phpunit +``` + +No test should fail. + +You can tweak the PHPUnit's settings by copying `phpunit.xml.dist` to `phpunit.xml` +and changing it according to your needs. + +## Standards + +We are trying to follow the [PHP-FIG](http://www.php-fig.org)'s standards, so +when you send us a pull request, be sure you are following them. + +## Sending your code to us + +Please see http://help.github.com/pull-requests/. diff --git a/LICENSE b/LICENSE index 05b7b55..4b241ad 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2009-2014, Alexandre Gomes Gaigalas. +Copyright (c) 2009-2015, Alexandre Gomes Gaigalas. All rights reserved. Redistribution and use in source and binary forms, with or without modification, diff --git a/Makefile b/Makefile deleted file mode 100644 index 1a25222..0000000 --- a/Makefile +++ /dev/null @@ -1,856 +0,0 @@ -VERSION = 0.1.13 -FOUNDATION_HOME = $(shell pwd)/.foundation -CONFIG_TOOL = ${FOUNDATION_HOME}/repo/bin/project-config.php -GENERATE_TOOL = ${FOUNDATION_HOME}/repo/bin/project-generate.php -PACKAGES_PEAR = pear config-get php_dir -SHELL := $(shell which bash) -.SHELLFLAGS = -c - -.SILENT: ; # no need for @ -.ONESHELL: ; # recipes execute in same shell -.NOTPARALLEL: ; # wait for this target to finish -.EXPORT_ALL_VARIABLES: ; # send all vars to shell -default: help-default; # default target -Makefile: ; # skip prerequisite discovery - -.title: - @echo -e "Respect/Foundation: $(VERSION)\n" - -.check-foundation: .title - @test -d ${FOUNDATION_HOME} || make -f Makefile foundation - @make -v|grep -qi GNU || echo -e "\nWARNING: Foundation Makefile was developed for use with GNU Make, \ - using other flavoured binaries may have unwanted consequences.\n" - @make -v|grep -q 'built for .*apple' && echo -e "\nWARNING: The apple built edition of GNU Make have several \ - known quirks and is not recommended. For best results, install make with homebrew and link it in out of \ - "keg only" or create an alias to the non apple distributed version of GNU Make instead.\n" || true - -# Help is not the default target cause its mainly used as the main -# build command. We're reserving it. -help-default help: .title - @echo " =====================================================================" - @echo " Respect/Foundation Menu" - @echo " =====================================================================" - @echo " help: Shows Respect/Foundation Help Menu: type: make help" - @echo " foundation: Installs and updates Foundation" - @echo " =====================================================================" - @echo " Other Targets Menus" - @echo " =====================================================================" - @echo " menu-project: Project Scripts Menu" - @echo " menu-package: Show Packaging Toolbox Menu" - @echo " menu-dev: Show Dev Toolbox Menu" - @echo " menu-deploy: Show Deploy & Release" - @echo "" - -menu-project: .title - @echo " =====================================================================" - @echo " Respect/Foundation Menu 1" - @echo " =====================================================================" - @echo " Project Scripts" - @echo " =====================================================================" - @echo " : INFO & SCAFFOLDING" - @echo " project-info: Shows project configuration" - @echo " project-init: Initialize current folder and create boilerplate project structure" - @echo " : TESTING" - @echo " test: Run project tests" - @echo " testdox: Run project tests - output in testdox format" - @echo " coverage: Run project tests and report coverage status" - @echo " clean: Removes code coverage reports" - @echo " bootstrap-php: (Re)create all purpose bootstrap.php for phpunit in test folder" - @echo " bootstrap-php-opt: Optimized all purpose bootstrap.php with static pear path in test folder" - @echo " phpunit-xml: (Re)create phpunit.xml in test folder" - @echo " travis-yml: (Re)create .travis.yml in root folder" - @echo " travis-lint: Validate your .travis.yml configuration" - @echo " gitignore: (Re)create .gitignore file" - @echo " test-skelgen: Generate boilerplate PHPUnit skeleton tests per class see help-skelgen" - @echo " test-skelgen-all: Generate tests for all classes and it's overwrite safe of course" - @echo " phantomjs-snapshot: Take a snapshot of that page with the webkit headless browser" - @echo " phantomjs-inject: Inject javascript/jquery into pages for output to stdout." - @echo "phantomjs-inject-verbose: Verbose output of script injection to help see whats going on." - @echo " : CLEANUP UTILITIES" - @echo " clean-all-whitespace: All in one does tabs2spaces, unix-line-ends and trailing_spaces" - @echo " clean-tabs2spaces: Turns tabs into 4 spaces properly handling mixed tab/spaces" - @echo " clean-unix-line-ends: Fixes unix line endings" - @echo " clean-trailing_spaces: Removes trailing whitespace" - @echo "clean-single-blank-lines: Removes multiple blank lines adds blank line at end of file" - @echo "clean-remove-eof-php-tag: Removes php tag at the end of a file if exists" - @echo " clean-up-makefile-baks: Delete all Makefile.bak files" - @echo " : CODE CONTENT UTILITIES" - @echo " cs-fixer: Run PHP Coding Standards Fixer to ensure your cs-style is correct" - @echo " codesniff: Run PHP Code Sniffer to generate a report of code analysis" - @echo " phpcpd: Run PHP Copy Paste detector" - @echo " phpdcd: Run PHP Dead Code detector" - @echo " phploc: Run PHP Lines Of Code analyzer for project code statistics" - @echo " phpdoc: Run PhpDocumentor2 to generate the project API documentation" - @echo " : CONFIGURATION" - @echo " package-ini: Creates the basic package.ini file" - @echo " package-xml: Propagates changes from package.ini to package.xml" - @echo " composer-json: Propagates changes from package.ini to composer.json" - @echo " package: Generates package.ini, package.xml and composer.json files" - @echo " pear: Generates a PEAR package" - @echo "" - - - -menu-package: .title - @echo " =====================================================================" - @echo " Respect/Foundation Menu 2" - @echo " =====================================================================" - @echo " Toolbox - Packaging" - @echo " =====================================================================" - @echo " composer-validate: Validate composer.json for syntax and other problems" - @echo " composer-install: Install this project with composer which will create vendor folder" - @echo " composer-install-dev: Install this development project with composer using --dev" - @echo " composer-update: Update an exiting composer installation and refresh repositories" - @echo " : COMPOSER & PACKAGES: use argument ex. package=vendor/package" - @echo " composer-create-project: Create a project from a package into its default directory" - @echo " composer-require: Add required package to composer.json and install it" - @echo " composer-search: Search for a package ksown to composer" - @echo " install: Install this project and its dependencies in the local PEAR" - @echo " info-php: Show information about your PHP" - @echo " config-php: Locate your PHP configuration file aka. php.ini" - @echo " include-php: Show the PHP configured (php.ini) include path" - @echo " info-pear: Show information about your PEAR" - @echo " locate-pear: Locate the PEAR packages installation folder" - @echo " install-pear: PEAR installation instructions" - @echo " updated-pear: See if there are any updates for PEAR and the installed packages" - @echo " update-all-pear: Update all packages if any updates are available" - @echo " packages-pear: Show the list of PEAR installed packages and their version numbers" - @echo " verify-pear: Verify that we can include System.php in PHP script" - @echo " info-check-pear: PEAR installation verification checklist instructions" - @echo " info-pyrus: Show information about your PEAR2_Pyrus - PEAR2 Installer" - @echo " install-pyrus: Download and install PEAR2_Pyrus" - @echo " info-composer: Show information about your composer" - @echo " install-composer: Download and install composer" - @echo "" - - - -menu-dev: .title - @echo " =====================================================================" - @echo " Respect/Foundation Menu 3" - @echo " =====================================================================" - @echo " Toolbox - Development" - @echo " =====================================================================" - @echo " info-git-extras: Show information about your installed git extras" - @echo " install-git-extras: Install git extras" - @echo " info-cs-fixer: Show information about your installed PHP Coding Standards Fixer" - @echo " install-cs-fixer: Install PHP Coding Standards Fixer" - @echo " info-codesniff: Show information about your installed PHP_CodeSniffer" - @echo " install-codesniff: Install PHP_CodeSniffer" - @echo " install-psr-sniff: Install Code Sniffer PSR sniffs to allow for PSR 0-3 compliancy checks" - @echo " info-phpunit: Show information about your installed PHPUnit" - @echo " install-phpunit: Install PHPUnit" - @echo " info-phpcpd: Show information about your installed PHP Copy Paste detector" - @echo " install-phpcpd: Install PHPcpd" - @echo " info-phpdcd: Show information about your installed PHP Dead Code detector" - @echo " install-phpdcd: Install PHPdcd" - @echo " info-phploc: Show information about your installed PHP LOC analyzer" - @echo " install-phploc: Install PHPloc" - @echo " info-skelgen: Show information about your installed PHPUnit Skeleton Generator" - @echo " install-skelgen: Install PHPUnit Skeleton Generator" - @echo " info-test-helpers: Show information about your installed PHPUnit Test Helpers extension" - @echo " install-test-helpers: Install PHPUnit Test Helpers extension" - @echo " info-phpdoc: Show information about your installed PhpDocumentor2" - @echo " install-phpdoc: Install PhpDocumentor2" - @echo " info-phd: Show information about your installed PhD" - @echo " install-phd: Install PhD is a PHP based Docbook renderer to build the PHP.net documentation" - @echo " info-phpsh: Show information about your installed PHP Shell (phpsh)" - @echo " install-phpsh: Install PHP Shell (phpsh) - Requires Python" - @echo " info-phantomjs: Show information about your installed phantomjs headless webkit browser" - @echo " install-phantomjs: Install phantomjs - headless webkit browser" - @echo " install-travis-lint: Install travis-lint configuration checker - Requires ruby gems" - @echo " install-uri-template: Install uri_template a php extension. Might require sudo." - @echo "" - - - -menu-deploy: .title - @echo " =====================================================================" - @echo " Respect/Foundation Menu 4" - @echo " =====================================================================" - @echo " Deploy & Release" - @echo " =====================================================================" - @echo " patch: Increases the patch version of the project (X.X.++)" - @echo " minor: Increases the minor version of the project (X.++.0)" - @echo " major: Increases the major version of the project (++.0.0)" - @echo " alpha: Changes the stability of the current version to alpha" - @echo " beta: Changes the stability of the current version to beta" - @echo " stable: Changes the stability of the current version to stable" - @echo " tag: Makes a git tag of the current project version/stability" - @echo " pear-push: Pushes the latest PEAR package. Custom pear_repo='' and pear_package='' available." - @echo " release: Runs tests, coverage reports, tag the build and pushes to package repositories" - @echo "" - - - -# Foundation puts its files into .foundation inside your project folder. -# You can delete .foundation anytime and then run make foundation again if you need -foundation: .title - make .foundation-backup-makefile - curl -LO git.io/Makefile - @echo "Creating ${FOUNDATION_HOME} folder" - -rm -Rf ${FOUNDATION_HOME} - -mkdir ${FOUNDATION_HOME} - git clone --depth 1 git://github.com/Respect/Foundation.git ${FOUNDATION_HOME}/repo - @make -f Makefile .gitignore-foundation - @echo "Downloading Onion" - -curl -L https://github.com/c9s/Onion/raw/master/onion > ${FOUNDATION_HOME}/onion;chmod +x ${FOUNDATION_HOME}/onion - @echo "Done." - -.foundation-backup-makefile: - @echo "Updating Makefile" - [[ -f "Makefile.bak" ]] && { export list=( $$(ls Makefile.bak*) ); \ - cp Makefile "Makefile.bak.$${#list[@]}"; } || \ - cp Makefile Makefile.bak - -clean-up-makefile-baks: - @if make .prompt-yesno message="Do you want to delete Makefile backups?" 2> /dev/null; then \ - rm -f Makefile.bak*; \ - fi - -# Target for Respect/Foundation development and internal use only. This target will not appear on the menus. -foundation-develop: - @if make .prompt-yesno message="Do you want to update your Makefile?" 2> /dev/null; then \ - make .foundation-backup-makefile; \ - curl -LO https://raw.github.com/Respect/Foundation/develop/Makefile; \ - fi - @echo "Creating ${FOUNDATION_HOME} folder" - -rm -Rf ${FOUNDATION_HOME} - -mkdir ${FOUNDATION_HOME} - git clone --depth 1 git://github.com/Respect/Foundation.git ${FOUNDATION_HOME}/repo - cd ${FOUNDATION_HOME}/repo/ && git fetch && git checkout develop && cd - - @make -f Makefile .gitignore-foundation - @echo "Downloading Onion" - -curl -L https://github.com/c9s/Onion/raw/master/onion > ${FOUNDATION_HOME}/onion;chmod +x ${FOUNDATION_HOME}/onion - @echo "Done." - -.gitignore-foundation: - @test -f .gitignore || make -f Makefile .gen-gitignore - @grep -q .foundation .gitignore || echo .foundation >> .gitignore - -.gen-gitignore: - @echo "(Re)create .gitignore" - @$(GENERATE_TOOL) config-template gitignore > gitignore.tmp && mv -f gitignore.tmp .gitignore - -gitignore: .title .gen-gitignore - -project-info: .check-foundation - @echo -e "\nProject Information\n" - @echo " php-version:" `$(CONFIG_TOOL) php-version ` - @echo " project-repository:" `$(CONFIG_TOOL) project-repository ` - @echo " library-folder:" `$(CONFIG_TOOL) library-folder ` - @echo " test-folder:" `$(CONFIG_TOOL) test-folder ` - @echo " config-folder:" `$(CONFIG_TOOL) config-folder ` - @echo " public-folder:" `$(CONFIG_TOOL) public-folder ` - @echo " vendor-folder:" `$(CONFIG_TOOL) vendor-folder ` - @echo " sandbox-folder:" `$(CONFIG_TOOL) sandbox-folder ` - @echo " documentation-folder:" `$(CONFIG_TOOL) documentation-folder ` - @echo " executables-folder:" `$(CONFIG_TOOL) executables-folder ` - @echo " vendor-name:" `$(CONFIG_TOOL) vendor-name ` - @echo " package-name:" `$(CONFIG_TOOL) package-name ` - @echo " project-name:" `$(CONFIG_TOOL) project-name ` - @echo " one-line-summary:" `$(CONFIG_TOOL) one-line-summary ` - @echo " package-description:" `$(CONFIG_TOOL) package-description ` - @echo " package-version:" `$(CONFIG_TOOL) package-version ` - @echo " package-stability:" `$(CONFIG_TOOL) package-stability ` - @echo -e "\r project-authors: "`$(CONFIG_TOOL) package-authors` \ - |tr ',' "\n"| awk -F' <' '{printf "%25s%-25s <%15s \n","",$$1,$$2}' - @echo -e "\r project-contributors: "`$(CONFIG_TOOL) package-contributors ` \ - |tr ',' "\n"| awk -F' <' '{printf "%25s%-25s <%15s \n","",$$1,$$2}' - @echo " package-date-time:" `$(CONFIG_TOOL) package-date-time ` - @echo " pear-path:" `$(CONFIG_TOOL) pear-path ` - @echo " pear-channel:" `$(CONFIG_TOOL) pear-channel ` - @echo " pear-repository:" `$(CONFIG_TOOL) pear-repository ` - @echo " phar-repository:" `$(CONFIG_TOOL) phar-repository ` - @echo " pear-dependencies:" `$(CONFIG_TOOL) pear-dependencies ` - @echo " extension-dependencies:" `$(CONFIG_TOOL) extension-dependencies ` - @echo " readme-file:" `$(CONFIG_TOOL) readme-file ` - @echo " project-license:" `$(CONFIG_TOOL) project-license ` - @echo " project-homepage:" `$(CONFIG_TOOL) project-homepage ` - @echo " user-name:" `$(CONFIG_TOOL) user-name ` - @echo " user-email:" `$(CONFIG_TOOL) user-email ` - @echo " user-home:" `$(CONFIG_TOOL) user-home ` - @echo "" - - - -test-skelgen: .check-foundation - @test -f $(shell $(CONFIG_TOOL) test-folder)/bootstrap.php || make bootstrap-php > /dev/null - @$(eval source-folder=$(shell $(CONFIG_TOOL) library-folder)) - -@if test "$(class)"; then \ - cd $(shell $(CONFIG_TOOL) test-folder) && ${FOUNDATION_HOME}/repo/bin/phpunit-skelgen-classname "${class}" $(source-folder); \ - else \ - echo "Usage:"; \ - echo " make test-skelgen class=\"My\\Awesome\\Class\""; \ - echo; \ - fi; \ - -test-skelgen-all: - @$(eval source-folder=$(shell $(CONFIG_TOOL) library-folder)) - @find $(source-folder) -type f -name "*.php" \ - | sed -E 's%$(source-folder)/(.*).php%class=\\"\1\\"%' \ - | sed 's%/%\\\\\\\\%g' \ - | xargs -L 1 make test-skelgen; - -# Re-usable target for yes no prompt. Usage: make .prompt-yesno message="Is it yes or no?" -# Will exit with error if not yes -.prompt-yesno: - @exec 9<&0 0&2 || (echo N >&2 && exit 1) - -info-phantomjs: .check-foundation - @echo "This is what I know about your phantomjs." - @/usr/bin/env PATH=$$PATH:${FOUNDATION_HOME} phantomjs -v 2> /dev/null || (echo "No phantomjs installed." && false) - -install-phantomjs: .check-foundation - @echo -e "Phantomjs Installation,\ndue to frequent releases (based on webkit) we are not able to install this package for you at this time." - @echo "Detailed installation instructions are available at http://phantomjs.org/download.html." - make .prompt-yesno message="Would you like to have the url opened?" && open http://phantomjs.org/download.html - -.check-phantomjs: - @make -f Makefile info-phantomjs &> /dev/null \ - || make -f Makefile install-phantomjs 2> /dev/null \ - || (echo "Unable to install phantomjs. Aborting..." && false) - -phantomjs-inject phantomjs-inject-verbose: .check-foundation .check-phantomjs - $(eval VERBOSE := $(patsubst phantomjs-inject%,%,$(@))) - [[ -z "$(url)" ]] && echo -e "Usage: make phantomjs-snapshot url= [code=jQuery Script] or use stdin\n\n \ - Example:\n \ - As command line argument:\n \ - make phantomjs-inject url=respect.li code='alert(\$$\$$(\"title\").text());'\n \ - note: requires dollar escaped as double dollar \$$\$$\n \ - From stdin:\n \ - echo 'console.log(\$$(\"title\").text());' | make phantomjs-inject url=respect.li \n \ - note: stdin allows for raw input so \$$ doesn't get processed\n \ - Tips: \n \ - Use single quotes to avoid shell interpretation.\n \ - Both alert and/or console.log will echo to stdout.\n \ - Use target phantom-inject-verbose for detailed output while debugging.\n" \ - && exit || true - if [ -z '$(code)' ]; then - while read -r; do \ - lines="$${lines} $${REPLY}"; \ - done <&0; - phantomjs ${FOUNDATION_HOME}/repo/bin/jquery-console-phantom.js "$(url)" "$${lines}" "${VERBOSE}" - else - phantomjs ${FOUNDATION_HOME}/repo/bin/jquery-console-phantom.js "$(url)" '$(code)' "${VERBOSE}" - fi - -phantomjs-snapshot: .check-foundation .check-phantomjs - [[ -z "$(url)" ]] && echo -e "Usage: make phantomjs-snapshot url=\n" && exit 11 || true - mkdir -p `$(CONFIG_TOOL) sandbox-folder `/snapshots - image=`phantomjs ${FOUNDATION_HOME}/repo/bin/snapshot.phantom.js "$(url)"` - echo $$image - mv -f "$${image}" `$(CONFIG_TOOL) sandbox-folder `/snapshots/. - open `$(CONFIG_TOOL) sandbox-folder `/snapshots/"$${image}" - -project-init: .check-foundation - @if test -d .git; then \ - echo; \ - echo "It appears you already have a git repository configured."; \ - echo "This target, will run git init and auto add + commit."; \ - if ! make .prompt-yesno message="Do you want to continue?" 2> /dev/null; then \ - echo "Aborted on request."; \ - exit; \ - fi; \ - fi; \ - make -f Makefile .project-init - -.open-document: - @[[ -n "$(url)" ]] && which open &> /dev/null && open "$(url)" - -.project-init: git-init project-folders phpunit-xml bootstrap-php package git-add-all - sleep 1 - git add -A - git commit -a -m"Project initialized." - -project-folders: .check-foundation - @$(GENERATE_TOOL) project-folders createFolders - -info-git-extras: - @echo "This is what I know about your git extras:" - git extras --version - -install-git-extras: .check-foundation - @make -f Makefile info-git-extras > /dev/null || (cd ${FOUNDATION_HOME} && curl https://raw.github.com/visionmedia/git-extras/master/bin/git-extras | INSTALL=y sh) - -git-init: .check-foundation git-init-only git-add-all - @git commit -a -m"Initial commit." - -git-init-only: .check-foundation - @git init --shared=all - -git-add-all: .check-foundation - @git add -A - -codesniff: .check-foundation - @echo "Running PHP Codesniffer to assess PSR compliancy" - phpcs -p --report-full=`$(CONFIG_TOOL) documentation-folder `/full2.out `$(CONFIG_TOOL) library-folder ` - -phpunit-codesniff: .check-foundation - @echo "Running PHP Codesniffer to assess PHPUnit compliancy" - phpcs -p --extensions=PHPUnit --report-full=`$(CONFIG_TOOL) documentation-folder `/full2.out `$(CONFIG_TOOL) library-folder ` - -phpcb: .check-foundation - @echo Running PHP Code Browser on library folder - @phpcb -s `$(CONFIG_TOOL) library-folder ` -o `$(CONFIG_TOOL) documentation-folder ` - @make .open-document url=`$(CONFIG_TOOL) documentation-folder `/index.html - -phpmd: .check-foundation - @echo Running PHP Mess Detector on library folder - @phpmd `$(CONFIG_TOOL) library-folder ` html codesize,unusedcode,naming,design,controversial > url=`$(CONFIG_TOOL) documentation-folder `/phpmd.html - @make .open-document url=`$(CONFIG_TOOL) documentation-folder `/phpmd.html - -phpdepend: - @echo Running PHP_Depend for on library folder - @pdepend --coderank-mode=inheritance,property,method \ - --jdepend-chart=`$(CONFIG_TOOL) documentation-folder `/jdepend-chart \ - --jdepend-xml=`$(CONFIG_TOOL) documentation-folder `/jdepend-xml \ - --overview-pyramid=`$(CONFIG_TOOL) documentation-folder `/overview-pyramid \ - --summary-xml=`$(CONFIG_TOOL) documentation-folder `/summary-xml \ - `$(CONFIG_TOOL) library-folder ` - - - -phpcpd: .check-foundation - @echo Running PHP Copy paste detection on library folder - phpcpd --verbose `$(CONFIG_TOOL) library-folder ` - -phpdcd: .check-foundation - @echo Running PHP Dead Code detection on library folder - phpdcd --verbose `$(CONFIG_TOOL) library-folder ` - -phploc: .check-foundation - @echo Running PHP Lines of code statistics on library folder - phploc --verbose `$(CONFIG_TOOL) library-folder ` - -phpdoc: .check-foundation - @echo generating documentation with PhpDocumentor2. - phpdoc -d `$(CONFIG_TOOL) library-folder ` -t `$(CONFIG_TOOL) documentation-folder ` -p - -phpunit-xml: .check-foundation - @$(GENERATE_TOOL) config-template phpunit.xml > phpunit.xml.tmp && mkdir -p $(shell $(CONFIG_TOOL) test-folder) && mv -f phpunit.xml.tmp $(shell $(CONFIG_TOOL) test-folder)/phpunit.xml - -bootstrap-php: .check-foundation - @$(GENERATE_TOOL) config-template bootstrap.php > bootstrap.php.tmp && mkdir -p $(shell $(CONFIG_TOOL) test-folder) && mv -f bootstrap.php.tmp $(shell $(CONFIG_TOOL) test-folder)/bootstrap.php - -bootstrap-php-opt: .check-foundation - @$(GENERATE_TOOL) config-template bootstrap.php.opt > bootstrap.php.tmp && mkdir -p $(shell $(CONFIG_TOOL) test-folder) && mv -f bootstrap.php.tmp $(shell $(CONFIG_TOOL) test-folder)/bootstrap.php - -package-ini: .check-foundation - @$(GENERATE_TOOL) package-ini > package.ini.tmp && mv -f package.ini.tmp package.ini - -travis-yml: .check-foundation - @$(GENERATE_TOOL) config-template travis.yml > travis.yml.tmp && mv -f travis.yml.tmp .travis.yml - -# Generates a package.xml from the package.ini -package-xml: .check-foundation - @${FOUNDATION_HOME}/onion build; echo - @if test -f package.xml; then \ - echo Respect/Foundation:; \ - echo; echo " $$ make pear"; echo; \ - fi; - - -composer-json: .check-foundation - @$(GENERATE_TOOL) composer-json > composer.json.tmp && mv -f composer.json.tmp composer.json - -# Generates all package files -package: .check-foundation package-ini package-xml composer-json - -# Phony target so the test folder don't conflict -.PHONY: test -test: .check-foundation - @cd `$(CONFIG_TOOL) test-folder`;phpunit $$([[ -n "$(filter)" ]] && echo "-v --debug --filter $(filter)") . - -testdox: .check-foundation - @cd `$(CONFIG_TOOL) test-folder`;phpunit --testdox . - -coverage: .check-foundation - @cd `$(CONFIG_TOOL) test-folder`;phpunit --testdox --coverage-html=reports/coverage --coverage-text . - @echo "Done. Reports also available on `$(CONFIG_TOOL) test-folder`/reports/coverage/index.html" - @make .open-document url=reports/coverage/index.html - -cs-fixer: .check-foundation - @cd `$(CONFIG_TOOL) library-folder`;${FOUNDATION_HOME}/php-cs-fixer -v fix --level=all --fixers=indentation,linefeed,trailing_spaces,unused_use,return,php_closing_tag,short_tag,visibility,braces,extra_empty_lines,phpdoc_params,eof_ending,include,controls_spaces,elseif . - @echo "Library folder done. `$(CONFIG_TOOL) library-folder`" - @cd `$(CONFIG_TOOL) test-folder`;${FOUNDATION_HOME}/php-cs-fixer -v fix --level=all --fixers=indentation,linefeed,trailing_spaces,unused_use,return,php_closing_tag,short_tag,visibility,braces,extra_empty_lines,phpdoc_params,eof_ending,include,controls_spaces,elseif . - @echo "Test folder done. `$(CONFIG_TOOL) test-folder` " - @echo "Done. You may verify the changes and commit if you are happy." - -# Any cleaning mechanism should be here -clean: .check-foundation - @rm -Rf `$(CONFIG_TOOL) test-folder`/reports - -# Targets below use the same rationale. They change the package.ini file, so you'll need a -# package-sync after them -patch: .check-foundation - @$(GENERATE_TOOL) package-ini patch > package.ini.tmp && mv -f package.ini.tmp package.ini - -minor: .check-foundation - @$(GENERATE_TOOL) package-ini minor > package.ini.tmp && mv -f package.ini.tmp package.ini - -major: .check-foundation - @$(GENERATE_TOOL) package-ini major > package.ini.tmp && mv -f package.ini.tmp package.ini - -alpha: .check-foundation - @$(GENERATE_TOOL) package-ini alpha > package.ini.tmp && mv -f package.ini.tmp package.ini - -beta: .check-foundation - @$(GENERATE_TOOL) package-ini beta > package.ini.tmp && mv -f package.ini.tmp package.ini - -stable: .check-foundation - @$(GENERATE_TOOL) package-ini stable > package.ini.tmp && mv -f package.ini.tmp package.ini - -tag: .check-foundation - -git tag `$(CONFIG_TOOL) package-version ` -m 'Tagging.' - -# Runs on the current package.xml file -pear: .check-foundation - @$(eval count=$(shell grep -c dir package.xml)) \ - if test $(count) -gt 1; then \ - pear package; \ - else \ - echo "There are no defined in package.xml"; \ - echo "Nothing to build"; \ - fi; - -info: - @pear info $(shell $(CONFIG_TOOL) package-name)|egrep 'Version|Name|Summary|Description|-' - -# On root PEAR installarions, this need to run as sudo -install: .check-foundation - @if ! test -f package.xml; then \ - echo "No package.xml found."; \ - echo "Nothing to install"; \ - elif ! make info 2> /dev/null; then \ - echo "You may need to run this as sudo."; \ - echo "Discovering channel"; \ - pear channel-info $(shell $(CONFIG_TOOL) pear-channel) || pear channel-discover $(shell $(CONFIG_TOOL) pear-channel); \ - pear install package.xml; \ - fi; - -info-php: .check-foundation - @echo "This is what I know about your PHP." - php --version - -config-php: .check-foundation - @echo "The location of your PHP configuration file." - php --ini - -include-php: .check-foundation - @echo "The PHP configured include path where external packages can be found, like PEAR packages for example." - php -r 'echo get_include_path()."\n";' - -info-pear: .check-foundation - @echo "This is what I know about your PEAR." - pear -V - -updated-pear: .check-foundation - @echo "Fetching possible upgrade information from all channels." - pear list-upgrades - -update-all-pear: .check-foundation - @echo "Updating all PEAR packages if any updates are available." - pear upgrade-all - -packages-pear: .check-foundation - @echo "The following PEAR packages are currently installed." - pear list - -locate-pear: .check-foundation - @echo "The PEAR installed package can be found at:" - pear config-get php_dir - -verify-pear: .check-foundation - @echo "If the following PHP script:" - @echo "" - @echo "" - @echo "Executes without any error and answers true to our question then you may safely assume that the PEAR installation is sound." - @php -r "require_once 'System.php'; echo PHP_EOL, 'Can we include PEAR System.php? : ', var_export(class_exists('System', false), true), PHP_EOL;" - -install-pear: .check-foundation - @echo "Because we rely so extensively on a proper PEAR installation it is pertinent that PEAR is installed properly." - @echo "Unfortunately I am not confident that I am capable, at this point, to successfully install PEAR on every system," - @echo "yours in particular, without making a complete mess of things." - @echo "" - @echo "Don't worry this is not difficult and I am sure you will succeed by following the detailed instructions at the" - @echo "following URL: http://pear.php.net/manual/en/installation.getting.php" - @echo "" - @echo "Once you're done you are welcome to return so I may assist you with the installation verification process." - @echo "You can start the verification with $ make verify" - @echo "Good luck!" - -info-check-pear: .check-foundation - @echo "At the address: http://pear.php.net/manual/en/guide.users.commandline.packageinfo.php PEAR lists a comprehensive" - @echo "list of instructions to execute and verify that the installation is sound." - @echo "" - -info-cs-fixer: .check-foundation - @echo "This is what I know about your PHP Coding Standards Fixer." - ${FOUNDATION_HOME}/php-cs-fixer -V - -install-cs-fixer: .check-foundation - @echo "Attempting to download PHP Coding Standards Fixer." - curl http://cs.sensiolabs.org/get/php-cs-fixer.phar -o ${FOUNDATION_HOME}/php-cs-fixer && chmod a+x ${FOUNDATION_HOME}/php-cs-fixer - -install-travis-lint: .check-foundation - @echo "Attempting to install travis-lint. Requires ruby gem..." - @gem install travis-lint - -travis-lint: .check-foundation - @echo "Checking your .travis.yml" - @travis-lint ./.travis.yml - -info-composer: .check-foundation - @echo "This is what I know about your composer." - @/usr/bin/env PATH=$$PATH:${FOUNDATION_HOME} composer about 2> /dev/null || (echo "No composer installed." && false) - -install-composer: .check-foundation - @echo "Attempting to download and install composer packager." - @curl -s http://getcomposer.org/installer | php -d detect_unicode=0 - @mv composer.phar ${FOUNDATION_HOME}/composer && chmod a+x ${FOUNDATION_HOME}/composer && exit 0 - -.check-composer: - @make -f Makefile info-composer &> /dev/null || make -f Makefile install-composer &> /dev/null || (echo "Unable to install composer. Aborting..." && false) - -composer-validate: .check-foundation .check-composer - @echo "Running composer validate, be brave." - @/usr/bin/env PATH=$$PATH:${FOUNDATION_HOME} composer validate -v - -composer-install: .check-foundation .check-composer - @echo "Running composer install, this will create a vendor folder and configure autoloader." - @/usr/bin/env PATH=$$PATH:${FOUNDATION_HOME} composer install -v - -composer-install-dev: .check-foundation .check-composer - @echo "Running composer install --dev, this will create a vendor folder and configure autoloader." - @/usr/bin/env PATH=$$PATH:${FOUNDATION_HOME} composer install -v --dev - -composer-update: .check-foundation .check-composer - @echo "Running composer update, which updates your existing installation." - @/usr/bin/env PATH=$$PATH:${FOUNDATION_HOME} composer update -v - -composer-create-project: .check-foundation .check-composer - @[[ -z "$(package)" ]] && echo -e "Usage: make composer-require package=vendor/package\n" && exit 11 || true - @echo "Running composer create project for package: $(package)" - @/usr/bin/env PATH=$$PATH:${FOUNDATION_HOME} composer -v create-project "$(package)" - -composer-require: .check-foundation .check-composer - @[[ -z "$(package)" ]] && echo -e "Usage: make composer-require package=vendor/package\n" && exit 1 || true - @echo "Running composer require, adding and installing as required package: $(package)" - @/usr/bin/env PATH=$$PATH:${FOUNDATION_HOME} composer -v require "$(package)" - -composer-search: .check-foundation .check-composer - @[[ -z "$(package)" ]] && echo -e "Usage: make composer-search package=search-package\n" && exit 1 || true - @echo "Running composer search, seeing if we can find a package called: $(package)" - @/usr/bin/env PATH=$$PATH:${FOUNDATION_HOME} composer -v search "$(package)" - -info-pyrus: .check-foundation - @echo "This is what I know about your PEAR2_Pyrus." - ${FOUNDATION_HOME}/pyrus --version - -install-pyrus: .check-foundation - @echo "Attempting to download and install PEAR2_Pyrus." - curl http://pear2.php.net/pyrus.phar -o ${FOUNDATION_HOME}/pyrus && chmod a+x ${FOUNDATION_HOME}/pyrus - ${FOUNDATION_HOME}/pyrus mypear `$(CONFIG_TOOL) vendor-folder` - ${FOUNDATION_HOME}/pyrus install PEAR2_Pyrus_Developer-alpha - ${FOUNDATION_HOME}/pyrus install PEAR2_Autoload-alpha - ${FOUNDATION_HOME}/pyrus install PEAR2_Templates_Savant-alpha - -info-codesniff: .check-foundation - @echo "This is what I know about your PHP_CodeSniffer." - phpcs --version - @echo "The following PHP_CodeSniffer coding standard sniffs are installed." - phpcs -i - -install-codesniff: install-phpqatools -install-phpunit: install-phpqatools -install-phpcpd: install-phpqatools -install-phpdcd: install-phpqatools -install-phploc: install-phpqatools -install-skelgen: install-phpqatools - -install-phpcb: install-phpqatools -install-phpmd: install-phpqatools - -install-vfsstreams: install-phpqatools -install-bytekit-cli: install-phpqatools -install-hphpa: install-phpqatools -install-behat: install-phpqatools - -install-pdepend: install-phpqatools -install-jenkins: install-phpqatools - -install-phpqatools: .check-foundation - @echo "Attempting to download and install the PHP Quality Assurance Toolchain. http://phpqatools.org/" - @pear config-set auto_discover 1 - @pear channel-info pear.phpqatools.org > /dev/null || pear channel-discover pear.phpqatools.org || pear channel-update pear.phpqatools.org - @pear install --alldeps --soft phpqatools/phpqatools PHP_CodeSniffer - @pear install --alldeps --soft phpqatools/PHP_CodeBrowser - -install-psr-sniff: .check-foundation - @echo "Attempting to download and install PHP_CodeSniffer sniffs for PSR's. This will likely require sudo." - @cd `$(PACKAGES_PEAR)`/PHP/CodeSniffer/Standards && git clone https://github.com/klaussilveira/phpcs-psr PSR - @phpcs --config-set default_standard PSR - -install-phpunit-sniff: .check-foundation - @echo "Attempting to download and install PHPUnit_CodeSniffer sniffs for PHPUnit standards. This will likely require sudo." - @cd `$(PACKAGES_PEAR)`/PHPUnit/ && git clone https://github.com/elblinkin/PHPUnit-CodeSniffer.git && cp -R PHPUnit-CodeSniffer/PHPUnitStandard ../PHP/CodeSniffer/Standards/PHPUnit - -info-phpunit: .check-foundation - @echo "This is what I know about your PHPUnit." - @phpunit --version - -info-phpcpd: .check-foundation - @echo "This is what I know about your PHPcpd." - @phpcpd --version - -info-phpdcd: .check-foundation - @echo "This is what I know about your PHPdcd." - @phpdcd --version - -info-phploc: .check-foundation - @echo "This is what I know about your PHPloc." - @phploc --version - -install-phpcov: .check-foundation - @echo "Attempting to download and install PHPcov. This will likely require sudo." - @pear channel-info pear.phpunit.de > /dev/null || pear channel-discover pear.phpunit.de || pear channel-update pear.phpunit.de - @pear install --alldeps --soft pear.phpunit.de/phpcov - -info-skelgen: - @echo "This is what I know about your PHPUnit_SkeletonGenerator.\n" - @phpunit-skelgen --version - -info-test-helpers: .check-foundation - @pecl info phpunit/test_helpers|egrep 'Version|Name|Summary|Description|-' - -install-test-helpers: - @if make info-test-helpers 2> /dev/null; then \ - exit; \ - fi; \ - echo "Attempting to download and install PHPUnit Test Helpers. This will likely require sudo." \ - pear channel-info pear.phpunit.de > /dev/null || pear channel-discover pear.phpunit.de || pear channel-update pear.phpunit.de; \ - pecl install --alldeps --soft phpunit/test_helpers - -info-phpdoc: .check-foundation - @echo "This is what I know about your PhpDocumentor." - @echo "The command is piped through more, press spacebar to page or q to abort." - @pear info phpdoc/phpDocumentor-alpha - -install-phpdoc: .check-foundation - @echo "Attempting to download and install PhpDocumentor2. This will likely require sudo." - @pear channel-info pear.phpdoc.org > /dev/null || pear channel-discover pear.phpdoc.org || pear channel-update pear.phpdoc.org - @pear install --alldeps --soft phpdoc/phpDocumentor-alpha - -info-phd: .check-foundation - @echo "This is what I know about your PhD." - @pear info doc.php.net/phd - -install-phd: .check-foundation - @echo "Attempting to download and install PhD. This will likely require sudo." - @pear channel-info doc.php.net > /dev/null || pear channel-discover doc.php.net || pear channel-update doc.php.net - @pear install --alldeps --soft doc.php.net/phd-beta - -info-phpsh: .check-foundation - @echo "This is what I know about your phpsh." - @phpsh --version - -install-phpsh: .check-foundation - @echo "Attempting to download and install phpsh." - git clone --progress -v https://github.com/facebook/phpsh.git ${FOUNDATION_HOME}/phpshsrc - sudo easy_install readline - cd ${FOUNDATION_HOME}/phpshsrc && python setup.py build && sudo python setup.py install - -install-uri-template: .check-foundation - @git clone --progress -v git://github.com/ioseb/uri-template.git ${FOUNDATION_HOME}/uri-template - @cd ${FOUNDATION_HOME}/uri-template && phpize && ./configure && make && make test && make install - @echo - @echo If all went well and you saw no errors or FAILs then congratulations! - @echo all that is left is to ensure that extension=uri_template.so is in your php.ini - @echo - -# Clean up utils - -clean-tabs2spaces: - @printf "." - @if test "$(file)"; then \ - expand -t 4 "$(file)" > "$(file).tmp" && cp -f "$(file).tmp" "$(file)"; rm -f "$(file).tmp"; \ - else \ - find . -type f -name "*.php" -exec make clean-tabs2spaces file="{}" \;; \ - echo; echo "Done converting tabs to spaces."; \ - fi; - -clean-trailing-spaces: - @printf "." - @if test "$(file)"; then \ - awk '{sub(/[ \t]+$$/, "")};1' "$(file)" > "$(file).tmp" && cp -f "$(file).tmp" "$(file)"; rm -f "$(file).tmp"; \ - else \ - find . -type f -name "*.php" -exec make clean-trailing-spaces file="{}" \;; \ - echo; echo "Done removing trailing spaces."; \ - fi; - -clean-unix-line-ends: - @printf "." - @if test "$(file)"; then \ - awk '{sub(/\r$$/,"")};1' "$(file)" > "$(file).tmp" && cp -f "$(file).tmp" "$(file)"; rm -f "$(file).tmp"; \ - else \ - find . -type f -name "*.php" -exec make clean-unix-line-ends file="{}" \;; \ - echo; echo "Done converting line endings."; \ - fi; - -clean-single-blank-lines: - @printf "." - @if test "$(file)"; then \ - awk '!NF{x="\n"};NF{print x $$0;x=""};END{print EOF}' "$(file)" > "$(file).tmp" && cp -f "$(file).tmp" "$(file)"; rm -f "$(file).tmp"; \ - else \ - find . -type f -name "*.php" -exec make clean-single-blank-lines file="{}" \;; \ - echo; echo "Done converting to single blank lines."; \ - fi; - -clean-all-whitespace: .check-foundation - @if test "$(file)"; then \ - make clean-tabs2spaces file="$(file)"; \ - make clean-unix-line-ends file="$(file)"; \ - make clean-trailing-spaces file="$(file)"; \ - make clean-single-blank-lines file="$(file)"; \ - else \ - make clean-tabs2spaces; make clean-unix-line-ends; make clean-trailing-spaces; make clean-single-blank-lines; \ - fi; - -clean-remove-eof-php-tag: - @printf "." - @if test "$(file)"; then \ - awk '{c=c $$0 "\n"};END{sub(/\n$$/,"",c); sub(/[[:space:]]*\n\?\>[[:space:]]*$$/,"\n",c); print c}' "$(file)" > "$(file).tmp" && cp -f "$(file).tmp" "$(file)"; rm -f "$(file).tmp"; \ - else \ - find . -type f -name "*.php" -exec make clean-remove-eof-php-tag file="{}" \;; \ - echo; echo "Done removing php closing tags ?> at end of file."; \ - fi; - -# Install pirum, clones the PEAR Repository, make changes there and push them. -pear-push: .check-foundation - @echo "Installing Pirum" - @sudo pear install --soft --force pear.pirum-project.org/Pirum - @echo "Cloning channel from git" `$(CONFIG_TOOL) pear-repository` - -rm -Rf ${FOUNDATION_HOME}/pirum - git clone --depth 1 `$(CONFIG_TOOL) pear-repository`.git ${FOUNDATION_HOME}/pirum - pirum add ${FOUNDATION_HOME}/pirum `$(CONFIG_TOOL) package-name`-`$(CONFIG_TOOL) package-version`.tgz;pirum build ${FOUNDATION_HOME}/pirum; - cd ${FOUNDATION_HOME}/pirum;git add .;git commit -m "Added " `$(CONFIG_TOOL) package-version`;git push - -packagecommit: - @git add package.ini package.xml composer.json - @git commit -m "Updated package files" - -# Uses other targets to complete the build -release: test package packagecommit pear pear-push tag - @echo "Release done. Pushing to GitHub" - @git push - @git push --tags - @echo "Done. " `$(CONFIG_TOOL) package-name`-`$(CONFIG_TOOL) package-version` diff --git a/README.md b/README.md index 9126dec..0489d05 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ -Respect\Rest -============ - -[![Build Status](https://secure.travis-ci.org/Respect/Rest.png)](http://travis-ci.org/Respect/Rest) [![Latest Stable Version](https://poser.pugx.org/respect/rest/v/stable.png)](https://packagist.org/packages/respect/rest) [![Total Downloads](https://poser.pugx.org/respect/rest/downloads.png)](https://packagist.org/packages/respect/rest) [![Latest Unstable Version](https://poser.pugx.org/respect/rest/v/unstable.png)](https://packagist.org/packages/respect/rest) [![License](https://poser.pugx.org/respect/rest/license.png)](https://packagist.org/packages/respect/rest) +# Respect\Rest +[![Build Status](https://img.shields.io/travis/Respect/Rest.svg?style=flat-square)](http://travis-ci.org/Respect/Rest) +[![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/Respect/Rest.svg?style=flat-square)](https://scrutinizer-ci.com/g/Respect/Rest) +[![Latest Version](https://img.shields.io/packagist/v/respect/rest.svg?style=flat-square)](https://packagist.org/packages/respect/rest) +[![Total Downloads](https://img.shields.io/packagist/dt/respect/rest.svg?style=flat-square)](https://packagist.org/packages/respect/rest) +[![License](https://img.shields.io/packagist/l/respect/rest.svg?style=flat-square)](https://packagist.org/packages/respect/rest) Thin controller for RESTful applications and APIs. @@ -10,13 +12,17 @@ Thin controller for RESTful applications and APIs. * Completely RESTful, the right way to build apps. -Installation ------------- +## Installation + +The package is available on [Packagist](https://packagist.org/packages/respect/rest). +You can install it using [Composer](http://getcomposer.org). -Packages available on [PEAR](http://respect.li/pear) and [Composer](http://packagist.org/packages/Respect/Rest). Autoloading is [PSR-0](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-0.md) compatible. +```bash +composer require respect/rest +``` + +## Feature Guide -Feature Guide -------------- ### Navigation [Configuration][] | [Dispatching][] | [Simple Routing][] | [Parameters][] | [Catch-all][] | [Matching][] | [Methods][] | [Controllers][] | [Streams][] | [Static][] | [Forwarding][] | [When][] | [By][] | [Through][] | [Controller Splitting][] | [Conneg][] | [Basic Auth][] | [User-Agent][] | [Content-Type][] | [HTTP Errors][] | [RESTful Extras][] | [Anti-Patterns][] | [Own Routines][] | [Error Handling][] @@ -25,9 +31,9 @@ Feature Guide Bootstrapping is easy. Just create an instance of Respect\Rest\Router. ```php - use Respect\Rest\Router; +use Respect\Rest\Router; - $r3 = new Router; +$r3 = new Router; ``` This assumes you have a `.htaccess` file that redirects every request to this PHP file and @@ -35,7 +41,7 @@ you're running this from the domain root (http://example.com/ without any subfol If you want to use it from a subfolder, you can pass the virtual root to the Router: ```php - $r3 = new Router('/myapp'); +$r3 = new Router('/myapp'); ``` This will instruct the router to work from http://example.com/myapp/. @@ -43,12 +49,12 @@ This will instruct the router to work from http://example.com/myapp/. You can also use the Router without a `.htaccess` file. This uses the CGI `PATH_INFO` variable, and can be declared as: ```php - $r3 = new Router('/index.php/'); +$r3 = new Router('/index.php/'); ``` The same goes for folders: ```php - $r3 = new Router('/myapp/index.php/'); +$r3 = new Router('/myapp/index.php/'); ``` This assumes that every URL in the project will begin with these namespaces. @@ -59,7 +65,7 @@ This assumes that every URL in the project will begin with these namespaces. The Router is auto-dispatched, which means that you don't have to call anything more than declaring routes to run it. If you want to omit this behavior, you can set: ```php - $r3->isAutoDispatched = false; +$r3->isAutoDispatched = false; ``` Note that you need the following step in order to see uncaught Exceptions in your application @@ -67,7 +73,7 @@ output. Standard error output on logs is untouched. You can then dispatch it yourself at the end of the proccess: ```php - print $r3->run(); +print $r3->run(); ``` You can print the output or store in a variable if you want. This allows you to better @@ -78,17 +84,17 @@ test and integrate the Router into existing applications. The Hello World route goes something like this: ```php - $r3->get('/', function() { - return 'Hello World'; - }); +$r3->get('/', function() { + return 'Hello World'; +}); ``` Hitting `http://localhost/` (consider your local configuration for this) will print "Hello World" in the browser. You can declare as many routes as you want: ```php - $r3->get('/hello', function() { - return 'Hello from Path'; - }); +$r3->get('/hello', function() { + return 'Hello from Path'; +}); ``` Hitting `http://localhost/hello` will now print "Hello from Path". @@ -99,9 +105,9 @@ Hitting `http://localhost/hello` will now print "Hello from Path". You can declare routes that receives parameters from the URL. For this, every parameter is a `/*` on the route path. Considering the previous sample model: ```php - $r3->get('/users/*', function($screenName) { - echo "User {$screenName}"; - }); +$r3->get('/users/*', function($screenName) { + echo "User {$screenName}"; +}); ``` Accessing `http://localhost/users/alganet` or any other username besides `alganet` will @@ -109,9 +115,9 @@ now print "User alganet" (or the username of your choosing). Multiple parameters can be defined: ```php - $r3->get('/users/*/lists/*', function($user, $list) { - return "List {$list} from user {$user}."; - }); +$r3->get('/users/*/lists/*', function($user, $list) { + return "List {$list} from user {$user}."; +}); ``` Last parameters on the route path are optional by default, so declaring just @@ -120,9 +126,9 @@ parameter. You can declare a second `->get('/posts'`, now the Router will match it properly, or treat the missing parameter yourself by making them `null`able on the passed function: ```php - $r3->get('/posts/*/*/*', function($year,$month=null,$day=null) { - /** list posts, month and day are optional */ - }); +$r3->get('/posts/*/*/*', function($year,$month=null,$day=null) { + /** list posts, month and day are optional */ +}); ``` 1. This will match /posts/2010/10/10, /posts/2011/01 and /posts/2010 @@ -135,9 +141,9 @@ match it properly, or treat the missing parameter yourself by making them Sometimes you need to catch an undefined number of parameters. You can use Routes with catch-all parameters like this: ```php - $r3->get('/users/*/documents/**', function($user, $documentPath) { - return readfile(PATH_STORAGE. implode('/', $documentPath)); - }); +$r3->get('/users/*/documents/**', function($user, $documentPath) { + return readfile(PATH_STORAGE. implode('/', $documentPath)); +}); ``` 1. The above sample will match `/users/alganet/documents/foo/bar/baz/anything`. @@ -152,7 +158,7 @@ Routes with catch-all parameters like this: ### Route Matching [Top][] -Things can became very complex quick. We have simple routes, routes with parameters, optional +Things can became very complex quick. We have simple routes, routes with parameters, optional parameters and catch-all parameters. A simple rule to keep in mind is that Respect\Rest matches the routes from the most specific to the most generic. @@ -172,9 +178,9 @@ maintainability of the code. You may want to have multiple routes perform the same action. Pluralization is the most common reason for this. This can be done like so: ```php - $r3->get(array('/user/*', '/users/*'), function($userName) { - return 'Hello '. $userName; - }); +$r3->get(array('/user/*', '/users/*'), function($userName) { + return 'Hello '. $userName; +}); ``` ### Matching any HTTP Method @@ -184,9 +190,9 @@ Sometimes you need to use a router to proxy requests to some other router or map requests to a class. By using the magic method `any`, you can pass any HTTP method to a given function. ```php - $r3->any('/users/*', function($userName) { - /** do anything */ - }); +$r3->any('/users/*', function($userName) { + /** do anything */ +}); ``` 1. Any HTTP method will match this same route. @@ -195,18 +201,18 @@ function. ### Class Controllers [Top][] -The `any` method is extremely useful to bind classes to controllers, one of Respect\Rest's most +The `any` method is extremely useful to bind classes to controllers, one of Respect\Rest's most awesome features: ```php - use Respect\Rest\Routable; +use Respect\Rest\Routable; - class MyArticle implements Routable { - public function get($id) { } - public function delete($id) { } - public function put($id) { } - } +class MyArticle implements Routable { + public function get($id) { } + public function delete($id) { } + public function put($id) { } +} - $r3->any('/article/*', 'MyArticle'); +$r3->any('/article/*', 'MyArticle'); ``` 1. This route will bind the class methods to the HTTP methods for the given path. @@ -220,7 +226,7 @@ awesome features: Passing constructor arguments to the class is also possible: ```php - $r3->any('/images/*', 'ImageController', array($myImageHandler, $myDb)); +$r3->any('/images/*', 'ImageController', array($myImageHandler, $myDb)); ``` 1. This will pass `$myImageHandler` and `$myDb` as parameters for the @@ -228,7 +234,7 @@ Passing constructor arguments to the class is also possible: You can also instantiate the class yourself if you want: ```php - $r3->any('/downloads/*', $myDownloadManager); +$r3->any('/downloads/*', $myDownloadManager); ``` 1. Sample above will assign the existent `$myDownloadManager` as a controller. @@ -236,7 +242,7 @@ You can also instantiate the class yourself if you want: And you can even use a factory or DI container to build the controller class: ```php - $r3->any('/downloads/*', 'MyControllerClass', array('Factory', 'getController')); +$r3->any('/downloads/*', 'MyControllerClass', array('Factory', 'getController')); ``` 1. Sample above will use the MyController class returned by Factory::getController @@ -250,17 +256,17 @@ And you can even use a factory or DI container to build the controller class: Sometimes you need to route users to streams. The Router doesn't have to first handle large files or wait for streams to finish before serving them. ```php - $r3->get('/images/*/hi-res', function($imageName) { - header('Content-type: image/jpg'); - return fopen("/path/to/hi/images/{$imageName}.jpg", 'r'); - }); +$r3->get('/images/*/hi-res', function($imageName) { + header('Content-type: image/jpg'); + return fopen("/path/to/hi/images/{$imageName}.jpg", 'r'); +}); ``` This will redirect the file directly to the browser without keeping it in memory. CAUTION: We created a possible security vulnerability in the sample: passing a parameter -directly to a `fopen` handle. Please validate user input parameters before using them. +directly to a `fopen` handle. Please validate user input parameters before using them. This is for demonstrational purposes only. ### Routing Static Values @@ -268,7 +274,7 @@ This is for demonstrational purposes only. No surprises here, you can make a route return a plain string: ```php - $r3->get('/greetings', 'Hello!'); +$r3->get('/greetings', 'Hello!'); ``` ### Forwarding Routes @@ -277,19 +283,19 @@ No surprises here, you can make a route return a plain string: Respect\Rest has an internal forwarding mechanism. First you'll need to understand that every route declaration returns an instance: ```php - $usersRoute = $r3->any('/users', 'UsersController'); +$usersRoute = $r3->any('/users', 'UsersController'); ``` Then you can `use` and `return` this route in another one: ```php - $r3->any('/premium', function($user) use ($db, $usersRoute) { - if (!$db->userPremium($user)) { - return $usersRoute; - } - }); +$r3->any('/premium', function($user) use ($db, $usersRoute) { + if (!$db->userPremium($user)) { + return $usersRoute; + } +}); ``` -Illustrative sample above will redirect internally when an user is not privileged to +Illustrative sample above will redirect internally when an user is not privileged to another route that handle normal users. ### When Routine (if) @@ -297,16 +303,16 @@ another route that handle normal users. Respect\Rest uses a different approach to validate route parameters: ```php - $r3->get('/documents/*', function($documentId) { - /** do something */ - })->when(function($documentId) { - return is_numeric($documentId) && $documentId > 0; - }); - // Routines can also be called using class and method names. - $r3->get('/documents/*', function($documentId) { - /** do something */ - })->when('SomeClass_name', 'someMethod_name'); - // You can also pass any instance that implements the __invoke() magic method to any routine. +$r3->get('/documents/*', function($documentId) { + /** do something */ +})->when(function($documentId) { + return is_numeric($documentId) && $documentId > 0; +}); +// Routines can also be called using class and method names. +$r3->get('/documents/*', function($documentId) { + /** do something */ +})->when('SomeClass_name', 'someMethod_name'); +// You can also pass any instance that implements the __invoke() magic method to any routine. ``` 1. This will match the route only if the callback on *when* is matched. @@ -323,27 +329,27 @@ not just data types such as `int` or `string`. We highly recommend that you use a strong validation library when using this. Consider [Respect\Validation](http://github.com/Respect/Validation). ```php - $r3->get('/images/*/hi-res', function($imageName) { - header('Content-type: image/jpg'); - return fopen("/path/to/hi/images/{$imageName}.jpg", 'r'); - })->when(function($imageName) { - /** Using Respect Validation alias to `V` */ - return V::alphanum(".")->length(5,155) - ->noWhitespace()->validate($imageName); - }); +$r3->get('/images/*/hi-res', function($imageName) { + header('Content-type: image/jpg'); + return fopen("/path/to/hi/images/{$imageName}.jpg", 'r'); +})->when(function($imageName) { + /** Using Respect Validation alias to `V` */ + return V::alphanum(".")->length(5,155) + ->noWhitespace()->validate($imageName); +}); ``` ### By Routine (before) [Top][] -Sometimes you need to run something before a route does its job. This is +Sometimes you need to run something before a route does its job. This is useful for logging, authentication and similar purposes. ```php - $r3->get('/artists/*/albums/*', function($artistName, $albumName) { - /** do something */ - })->by(function($albumName) use ($myLogger) { - $myLogger->logAlbumVisit($albumName); - }); +$r3->get('/artists/*/albums/*', function($artistName, $albumName) { + /** do something */ +})->by(function($albumName) use ($myLogger) { + $myLogger->logAlbumVisit($albumName); +}); ``` 1. This will execute the callback defined with *by* before the route action @@ -367,11 +373,11 @@ Similar to `->by`, but runs after the route did its job. In the sample below we're showing something similar to invalidating a cache after saving some new information. ```php - $r3->post('/artists/*/albums/*', function($artistName, $albumName) { - /** save some artist info */ - })->through(function() use($myCache) { - $myCache->clear($artistName, $albumName); - }); +$r3->post('/artists/*/albums/*', function($artistName, $albumName) { + /** save some artist info */ +})->through(function() use($myCache) { + $myCache->clear($artistName, $albumName); +}); ``` 1. `by` proxies will be executed before the route action, `through proxies` @@ -383,14 +389,14 @@ Sample above allows you to do something based on the route parameters, but when procesing something after the route has run, its desirable to process its output as well. This can be achieved with a nested closure: ```php - $r3->any('/settings', 'SetingsController')->through(function(){ - return function($data) { - if (isset($settings['admin_user'])) { - unset($settings['admin_user']); - } - return $data; - }; - }); +$r3->any('/settings', 'SetingsController')->through(function(){ + return function($data) { + if (isset($settings['admin_user'])) { + unset($settings['admin_user']); + } + return $data; + }; +}); ``` The illustrative sample above removes sensitive keys from a settings controller before @@ -399,34 +405,34 @@ outputing the result. ### Controller Splitting [Top][] -When using routines you are encouraged to separate the controller logic into components. You can +When using routines you are encouraged to separate the controller logic into components. You can reuse them: ```php - $logRoutine = function() use ($myLogger, $r3) { - $myLogger->logVisit($r3->request->path); - }; +$logRoutine = function() use ($myLogger, $r3) { + $myLogger->logVisit($r3->request->path); +}; - $r3->any('/users', 'UsersController')->by($logRoutine); - $r3->any('/products', 'ProductsController')->by($logRoutine); +$r3->any('/users', 'UsersController')->by($logRoutine); +$r3->any('/products', 'ProductsController')->by($logRoutine); ``` A simple way of applying routines to every route on the router is: ```php - $r3->always('By', $logRoutine); +$r3->always('By', $logRoutine); ``` You can use the param sync to take advantage of this: ```php - $r3->always('When', function($user=null) { - if ($user) { - return strlen($user) > 3; - } - }); - - $r3->any('/products', function () { /***/ }); - $r3->any('/users/*', function ($user) { /***/ }); - $r3->any('/users/*/products', function ($user) { /***/ }); - $r3->any('/listeners/*', function ($user) { /***/ }); +$r3->always('When', function($user=null) { + if ($user) { + return strlen($user) > 3; + } +}); + +$r3->any('/products', function () { /***/ }); +$r3->any('/users/*', function ($user) { /***/ }); +$r3->any('/users/*/products', function ($user) { /***/ }); +$r3->any('/listeners/*', function ($user) { /***/ }); ``` Since there are three routes with the `$user` parameter, `when` will @@ -435,21 +441,21 @@ verify them all automatically by its name. ### Content Negotiation [Top][] -Respect/Rest currently supports the four distinct types of Accept header content-negotiation: +Respect/Rest currently supports the four distinct types of Accept header content-negotiation: Mimetype, Encoding, Language and Charset. Usage sample: ```php - $r3->get('/about', function() { - return array('v' => 2.0); - })->acceptLanguage(array( - 'en' => function($data) { return array("Version" => $data['v']); }, - 'pt' => function($data) { return array("VersĆ£o" => $data['v']); } - ))->accept(array( - 'text/html' => function($data) { - list($k,$v)=each($data); - return "$k: $v"; - }, - 'application/json' => 'json_encode' - )); +$r3->get('/about', function() { + return array('v' => 2.0); +})->acceptLanguage(array( + 'en' => function($data) { return array("Version" => $data['v']); }, + 'pt' => function($data) { return array("VersĆ£o" => $data['v']); } +))->accept(array( + 'text/html' => function($data) { + list($k,$v)=each($data); + return "$k: $v"; + }, + 'application/json' => 'json_encode' +)); ``` As in every routine, conneg routines are executed in the same order in which @@ -460,14 +466,14 @@ Please note that when returning streams, conneg routines are also called. You may take advantage of this when processing streams. The hardcore example below serves text, using the deflate encoding, directly to the browser: ```php - $r3->get('/text/*', function($filename) { - return fopen('data/'.$filename, 'r+'); - })->acceptEncoding(array( - 'deflate' => function($stream) { - stream_filter_append($stream, 'zlib.deflate', STREAM_FILTER_READ); - return $stream; /** now deflated on demand */ - } - )); +$r3->get('/text/*', function($filename) { + return fopen('data/'.$filename, 'r+'); +})->acceptEncoding(array( + 'deflate' => function($stream) { + stream_filter_append($stream, 'zlib.deflate', STREAM_FILTER_READ); + return $stream; /** now deflated on demand */ + } +)); ``` When applying conneg routines to multiple routes that can return streams you @@ -478,9 +484,9 @@ When applying conneg routines to multiple routes that can return streams you Support for Basic HTTP Authentication is already implemented as a routine: ```php - $r3->get('/home', 'HomeController')->authBasic('My Realm', function($user, $pass) { - return $user === 'admin' && $pass === 'p4ss'; - }); +$r3->get('/home', 'HomeController')->authBasic('My Realm', function($user, $pass) { + return $user === 'admin' && $pass === 'p4ss'; +}); ``` You'll receive an username and password provided by the user, and you just need @@ -495,12 +501,12 @@ act as an internal forward (see the section on forwarding above). Below is an illustrative sample of how to block requests from mobile devices: ```php - $r3->get('/videos/*', 'VideosController')->userAgent(array( - 'iphone|android' => function(){ - header('HTTP/1.1 403 Forbidden'); - return false; /** do not process the route. */ - } - )); +$r3->get('/videos/*', 'VideosController')->userAgent(array( + 'iphone|android' => function(){ + header('HTTP/1.1 403 Forbidden'); + return false; /** do not process the route. */ + } +)); ``` You can pass several items in the array, like any conneg routine. The array @@ -515,20 +521,20 @@ By default, HTML forms send POST data as `multipart/form-data`, but API clients may send any other format. PUT requests often send other mime types. You can pre-process this data before doing anything: ```php - $r3->post('/timeline', function() { - return file_get_contents('php://input'); - })->contentType(array( - 'multipart/form-data' => function($input) { - parse_str($input, $output); - return $output; - }, - 'application/json' => function($input) { - return my_json_converter($input); - }, - 'text/xml' => function($input) { - return my_xml_converter($input); - }, - )); +$r3->post('/timeline', function() { + return file_get_contents('php://input'); +})->contentType(array( + 'multipart/form-data' => function($input) { + parse_str($input, $output); + return $output; + }, + 'application/json' => function($input) { + return my_json_converter($input); + }, + 'text/xml' => function($input) { + return my_xml_converter($input); + }, +)); ``` ### HTTP Errors @@ -545,7 +551,7 @@ Respect\Rest currently handle the following errors by default: ### RESTful Extras [Top][] - * A HEAD request automatically works sending all GET headers without body. You can override + * A HEAD request automatically works sending all GET headers without body. You can override this behavior declaring custom `head` routes. * An OPTIONS request to `*` or any route path returns the `Allow` headers properly. * When returning 405, `Allow` headers are also set properly. @@ -566,7 +572,7 @@ own routines by instance using: ``` In the sample above, `MyRoutine` is a user provided routine declared as a class and -appended to the router. Custom routines have the option of several different interfaces +appended to the router. Custom routines have the option of several different interfaces which can be implemented: * IgnorableFileExtension - Instructs the router to ignore the file extension in requests @@ -586,9 +592,9 @@ Respect\Rest provides two special ways to handle errors. The first one is using Routes: ```php - $r3->exceptionRoute('InvalidArgumentException', function (InvalidArgumentException $e) { - return 'Sorry, this error happened: '.$e->getMessage(); - }); +$r3->exceptionRoute('InvalidArgumentException', function (InvalidArgumentException $e) { + return 'Sorry, this error happened: '.$e->getMessage(); +}); ``` Whenever an uncaught exception appears on any route, it will be caught and forwarded to @@ -596,9 +602,9 @@ this side route. Similarly, there is a route for PHP errors: ```php - $r3->errorRoute(function (array $err) { - return 'Sorry, this errors happened: '.var_dump($err); - }); +$r3->errorRoute(function (array $err) { + return 'Sorry, this errors happened: '.var_dump($err); +}); ``` [Top]: #navigation diff --git a/composer.json b/composer.json index e3c1bc5..b9dc526 100644 --- a/composer.json +++ b/composer.json @@ -2,64 +2,32 @@ "name": "respect/rest", "description": "Thin controller for RESTful applications", "type": "library", - "license": "BSD-3-Clause", - "autoload": { - "psr-0": { - "Respect\\Rest": "library/" - } - }, + "homepage": "http://respect.li/", + "license": "BSD Style", "authors": [ { "name": "Alexandre Gaigalas", "email": "alexandre@gaigalas.net" }, { - "name": "Anderson Casimiro", - "email": "duodraco@duo.draco" - }, - { - "name": "Augusto Pascutti", - "email": "contato@augustopascutti.com" - }, - { - "name": "Ben Ramsey", - "email": "ben@benramsey.com" - }, - { - "name": "eduardomarcate", - "email": "eduardo@marcate.info" - }, - { - "name": "Eduardo M. Garcia", - "email": "eduardo@debian.elam" - }, - { - "name": "Henrique Moody", - "email": "henriquemoody@gmail.com" - }, - { - "name": "kleberhs007", - "email": "kleberhs007@yahoo.com" - }, - { - "name": "Leandro", - "email": "lleitep3@gmail.com" - }, - { - "name": "Nick Rawe", - "email": "nickrawe2@gmail.com" - }, - { - "name": "Pablo Lacerda de Miranda", - "email": "pablolmiranda@gmail.com" - }, - { - "name": "Rogerio Prado de Jesus", - "email": "rogeriopradoj@gmail.com" - }, - { - "name": "wesleyvicthor", - "email": "w.v.mendes.s@gmail.com" + "name": "Respect/Data Contributors", + "homepage": "https://github.com/Respect/Data/graphs/contributors" + } + ], + "require": { + "php": ">=5.3.0" + }, + "require-dev": { + "phpunit/phpunit": "~4.4.0" + }, + "autoload": { + "psr-4": { + "Respect\\": "library/Respect" + } + }, + "autoload-dev": { + "psr-4": { + "Stubs\\": "tests/src/Stubs" } - ] + } } diff --git a/bin/nginx-dev-runner b/example/bin/nginx-dev-runner similarity index 100% rename from bin/nginx-dev-runner rename to example/bin/nginx-dev-runner diff --git a/public/README.md b/example/public/README.md similarity index 100% rename from public/README.md rename to example/public/README.md diff --git a/public/basic.htaccess b/example/public/basic.htaccess similarity index 100% rename from public/basic.htaccess rename to example/public/basic.htaccess diff --git a/public/index.php b/example/public/index.php similarity index 76% rename from public/index.php rename to example/public/index.php index 84e6585..1db73b6 100644 --- a/public/index.php +++ b/example/public/index.php @@ -1,5 +1,7 @@ route->sideRoutes as $sideRoute) { if ($sideRoute instanceof Routes\Error) { return set_error_handler( - function() use ($sideRoute) { + function () use ($sideRoute) { $sideRoute->errors[] = func_get_args(); } ); @@ -167,8 +169,8 @@ protected function processPosRoutines($response) * Restores the previous error handler if present then check error routes * for logged errors, forwarding them or returning null silently * - * @param mixed $errorHandler Some error handler (internal or external to - * Respect) + * @param mixed $errorHandler Some error handler (internal or external to + * Respect) * * @return mixed A route forwarding or a silent null */ @@ -193,9 +195,9 @@ protected function forwardErrors($errorHandler) * Does a catch-like operation on an exception based on previously * declared instances from Router::exceptionRoute * - * @param Exception $e Any exception + * @param Exception $e Any exception * - * @return mixed A route forwarding or a silent null + * @return mixed A route forwarding or a silent null */ protected function catchExceptions($e) { @@ -207,6 +209,7 @@ protected function catchExceptions($e) || $sideRoute->class === '\Exception' ) { $sideRoute->exception = $e; + return $this->forward($sideRoute); } } @@ -222,7 +225,7 @@ public function response() try { //No routes, get out if (!$this->route instanceof AbstractRoute) { - return null; + return; } $errorHandler = $this->prepareForErrorForwards(); @@ -271,7 +274,6 @@ public function response() public function routineCall($type, $method, Routinable $routine, &$params) { $reflection = $this->route->getReflection( - //GET and HEAD are the same for routines $method == 'HEAD' ? 'GET' : $method ); @@ -321,7 +323,7 @@ protected function extractRouteParam( return $routeParam->getDefaultValue(); } - return null; + return; } /** @@ -334,7 +336,7 @@ protected function extractRouteParam( public function forward(AbstractRoute $route) { $this->route = $route; + return $this->response(); } - } diff --git a/library/Respect/Rest/Routable.php b/library/Respect/Rest/Routable.php index 2de5fe8..d202198 100644 --- a/library/Respect/Rest/Routable.php +++ b/library/Respect/Rest/Routable.php @@ -1,9 +1,14 @@ $method($p, $routeTarget); - return $this->$method($lastPath, $routeTarget); + foreach ($path as $p) { + $this->$method($p, $routeTarget); + } + + return $this->$method($lastPath, $routeTarget); } - + //closures, func names, callbacks if (is_callable($routeTarget)) { - //raw callback if (!isset($args[2])) { return $this->callbackRoute($method, $path, $routeTarget); @@ -185,7 +187,6 @@ public function __call($method, $args) //classes } else { - //raw classnames if (!isset($args[2])) { return $this->classRoute($method, $path, $routeTarget); @@ -215,7 +216,7 @@ public function __call($method, $args) * @param mixed $virtualHost null for no virtual host or a string prefix * for every URI */ - public function __construct($virtualHost=null) + public function __construct($virtualHost = null) { $this->virtualHost = $virtualHost; } @@ -256,11 +257,11 @@ public function __toString() * * @return Router the router itself. */ - public function always($routineName, $param1=null, $param2=null, $etc=null) + public function always($routineName, $param1 = null, $param2 = null, $etc = null) { $params = func_get_args(); $routineName = array_shift($params); - $routineClassName = 'Respect\\Rest\\Routines\\' . $routineName; + $routineClassName = 'Respect\\Rest\\Routines\\'.$routineName; $routineClass = new ReflectionClass($routineClassName); $routineInstance = $routineClass->newInstanceArgs($params); $this->globalRoutines[] = $routineInstance; @@ -328,23 +329,25 @@ public function callbackRoute( ) { $route = new Routes\Callback($method, $path, $callback, $arguments); $this->appendRoute($route); + return $route; } /** * Creates and returns a class-based route * - * @param string $method The HTTP method - * @param string $path The URI pattern for this route - * @param string $class Some class name - * @param array $arguments The class constructor arguments + * @param string $method The HTTP method + * @param string $path The URI pattern for this route + * @param string $class Some class name + * @param array $arguments The class constructor arguments * * @return Respect\Rest\Routes\ClassName The route instance */ - public function classRoute($method, $path, $class, array $arguments=array()) + public function classRoute($method, $path, $class, array $arguments = array()) { $route = new Routes\ClassName($method, $path, $class, $arguments); $this->appendRoute($route); + return $route; } @@ -356,7 +359,7 @@ public function classRoute($method, $path, $class, array $arguments=array()) * * @return mixed Whatever you returned from your model */ - public function dispatch($method=null, $uri=null) + public function dispatch($method = null, $uri = null) { return $this->dispatchRequest(new Request($method, $uri)); } @@ -368,7 +371,7 @@ public function dispatch($method=null, $uri=null) * * @return mixed Whatever the dispatched route returns */ - public function dispatchRequest(Request $request=null) + public function dispatchRequest(Request $request = null) { if ($this->isRoutelessDispatch($request)) { return $this->request; @@ -386,10 +389,11 @@ public function dispatchRequest(Request $request=null) * * @return Respect\Rest\Routes\Exception */ - public function exceptionRoute($className, $callback=null) + public function exceptionRoute($className, $callback = null) { $route = new Routes\Exception($className, $callback); $this->appendSideRoute($route); + return $route; } @@ -404,16 +408,17 @@ public function errorRoute($callback) { $route = new Routes\Error($callback); $this->appendSideRoute($route); + return $route; } /** * Creates and returns an factory-based route * - * @param string $method The HTTP metod (GET, POST, etc) - * @param string $path The URI Path (/foo/bar...) - * @param string $className The class name of the factored instance - * @param string $factory Any callable + * @param string $method The HTTP metod (GET, POST, etc) + * @param string $path The URI Path (/foo/bar...) + * @param string $className The class name of the factored instance + * @param string $factory Any callable * * @return Respect\Rest\Routes\Factory The route created */ @@ -447,7 +452,7 @@ public function getAllowedMethods(array $routes) * Checks if router overrides the method with _method hack * * @return bool true if the router overrides current request method, false - * otherwise + * otherwise */ public function hasDispatchedOverridenMethod() { @@ -460,9 +465,9 @@ public function hasDispatchedOverridenMethod() /** * Creates and returns an instance-based route * - * @param string $method The HTTP metod (GET, POST, etc) - * @param string $path The URI Path (/foo/bar...) - * @param string $intance An instance of Routinable + * @param string $method The HTTP metod (GET, POST, etc) + * @param string $path The URI Path (/foo/bar...) + * @param string $intance An instance of Routinable * * @return Respect\Rest\Routes\Instance The route created */ @@ -497,7 +502,7 @@ public function isRoutelessDispatch(Request $request = null) $this->isAutoDispatched = false; if (!$request) { - $request = new Request; + $request = new Request(); } $this->request = $request; @@ -549,7 +554,7 @@ public function routeDispatch() * * @return string the response string */ - public function run(Request $request=null) + public function run(Request $request = null) { $route = $this->dispatchRequest($request); if ( @@ -557,18 +562,18 @@ public function run(Request $request=null) || (isset($request->method) && $request->method === 'HEAD') ) { - return null; + return; } $response = $route->response(); if (is_resource($response)) { fpassthru($response); + return ''; } return (string) $response; - } /** @@ -588,13 +593,12 @@ public function staticRoute($method, $path, $staticValue) return $route; } - /** Appliesthe virtualHost prefix on the current request */ protected function applyVirtualHost() { if ($this->virtualHost) { $this->request->uri = preg_replace( - '#^' . preg_quote($this->virtualHost) . '#', + '#^'.preg_quote($this->virtualHost).'#', '', $this->request->uri ); @@ -615,10 +619,11 @@ protected function applyVirtualHost() protected function configureRequest( Request $request, AbstractRoute $route, - array $params=array() + array $params = array() ) { $request->route = $route; $request->params = $params; + return $request; } @@ -629,7 +634,7 @@ protected function configureRequest( */ protected function getMatchedRoutesByPath() { - $matched = new \SplObjectStorage; + $matched = new \SplObjectStorage(); foreach ($this->routes as $route) { if ($this->matchRoute($this->request, $route, $params)) { @@ -672,7 +677,6 @@ protected function informMethodNotAllowed(array $allowedMethods) $this->request->route = null; } - /** * Checks if a route matches a method * @@ -706,15 +710,15 @@ protected function matchesMethod(AbstractRoute $route, $methodName) protected function matchRoute( Request $request, AbstractRoute $route, - &$params=array() + &$params = array() ) { if ($route->match($request, $params)) { $request->route = $route; + return true; } } - /** * Checks if a route matches its routines * @@ -747,7 +751,9 @@ protected function routineMatch(\SplObjectStorage $matchedByPath) /** Sorts current routes according to path and parameters */ protected function sortRoutesByComplexity() { - usort($this->routes, function($a, $b) { + usort( + $this->routes, + function ($a, $b) { $a = $a->pattern; $b = $b->pattern; $pi = AbstractRoute::PARAM_IDENTIFIER; diff --git a/library/Respect/Rest/Routes/AbstractRoute.php b/library/Respect/Rest/Routes/AbstractRoute.php index 3f60d91..f863840 100644 --- a/library/Respect/Rest/Routes/AbstractRoute.php +++ b/library/Respect/Rest/Routes/AbstractRoute.php @@ -1,4 +1,10 @@ appendRoutine($reflection->newInstanceArgs($arguments)); @@ -140,6 +146,7 @@ public function appendRoutine(Routinable $routine) : spl_object_hash($routine); $this->routines[$key] = $routine; + return $this; } @@ -154,15 +161,14 @@ public function appendRoutine(Routinable $routine) * * @return string the created URI */ - public function createUri($param1=null, $etc=null) + public function createUri($param1 = null, $etc = null) { $params = func_get_args(); array_unshift($params, $this->regexForReplace); $params = preg_replace('#(?virtualHost, ' /') . - call_user_func_array('sprintf', $params); + + return rtrim($this->virtualHost, ' /').call_user_func_array('sprintf', $params); } /** @@ -176,17 +182,16 @@ public function createUri($param1=null, $etc=null) * * @return bool always true \,,/ */ - public function matchRoutines(Request $request, $params=array()) + public function matchRoutines(Request $request, $params = array()) { foreach ($this->routines as $routine) { - if ( - $routine instanceof ProxyableWhen + if ($routine instanceof ProxyableWhen && !$request->routineCall( 'when', $request->method, $routine, - $params) - ) { + $params + )) { return false; } } @@ -204,7 +209,7 @@ public function matchRoutines(Request $request, $params=array()) * * @return bool as true as xkcd (always true) */ - public function match(Request $request, &$params=array()) + public function match(Request $request, &$params = array()) { $params = array(); $matchUri = $request->uri; @@ -250,17 +255,17 @@ public function match(Request $request, &$params=array()) */ protected function createRegexPatterns($pattern) { - $extra = $this->extractCatchAllPattern($pattern); - + $extra = $this->extractCatchAllPattern($pattern); + $matchPattern = str_replace( static::QUOTED_PARAM_IDENTIFIER, static::REGEX_SINGLE_PARAM, preg_quote(rtrim($pattern, ' /')), $paramCount ); - + $pattern = rtrim($pattern); - + $replacePattern = str_replace( static::PARAM_IDENTIFIER, '/%s', @@ -268,6 +273,7 @@ protected function createRegexPatterns($pattern) ); $matchPattern = $this->fixOptionalParams($matchPattern); $matchRegex = "#^{$matchPattern}{$extra}$#"; + return array($matchRegex, $replacePattern); } @@ -297,6 +303,7 @@ protected function extractCatchAllPattern(&$pattern) static::PARAM_IDENTIFIER, $pattern ); + return $extra; } @@ -327,5 +334,4 @@ protected function fixOptionalParams($quotedPattern) return $quotedPattern; } - } diff --git a/library/Respect/Rest/Routes/Callback.php b/library/Respect/Rest/Routes/Callback.php index 8ac2939..800c6de 100644 --- a/library/Respect/Rest/Routes/Callback.php +++ b/library/Respect/Rest/Routes/Callback.php @@ -1,4 +1,10 @@ callback = $callback; $this->arguments = $arguments; parent::__construct($method, $pattern); } - /** - * Returns an appropriate Reflection for any callable object + /** + * Returns an appropriate Reflection for any callable object * * @return ReflectionFunctionAbstract The returned reflection object */ @@ -79,9 +84,8 @@ public function getReflection($method) public function runTarget($method, &$params) { return call_user_func_array( - $this->callback, + $this->callback, array_merge($params, $this->arguments) ); } - } diff --git a/library/Respect/Rest/Routes/ClassName.php b/library/Respect/Rest/Routes/ClassName.php index 1bfea0c..4a622c0 100644 --- a/library/Respect/Rest/Routes/ClassName.php +++ b/library/Respect/Rest/Routes/ClassName.php @@ -1,23 +1,27 @@ class = $class; $this->constructorParams = $params; @@ -50,26 +54,25 @@ protected function createInstance() { $className = $this->class; $reflection = new ReflectionClass($className); - + if (!$reflection->implementsInterface('Respect\\Rest\\Routable')) { throw new InvalidArgumentException( 'Routed classes must implement Respect\\Rest\\Routable' - ); + ); } if ( - empty($this->constructorParams) + empty($this->constructorParams) || !method_exists($this->class, '__construct') ) { - return new $className; + return new $className(); } $reflection = new ReflectionClass($this->class); - + return $reflection->newInstanceArgs($this->constructorParams); } - /** * Gets the reflection for a specific method. For this route, the reflection * is given for the class method having the same name as the HTTP method. @@ -81,7 +84,7 @@ protected function createInstance() public function getReflection($method) { $mirror = new ReflectionClass($this->class); - + if ($mirror->hasMethod($method)) { return new ReflectionMethod($this->class, $method); } @@ -104,9 +107,8 @@ public function runTarget($method, &$params) } return call_user_func_array( - array($this->instance, $method), + array($this->instance, $method), $params ); } - } diff --git a/library/Respect/Rest/Routes/Error.php b/library/Respect/Rest/Routes/Error.php index 061efa8..32995e6 100644 --- a/library/Respect/Rest/Routes/Error.php +++ b/library/Respect/Rest/Routes/Error.php @@ -1,7 +1,12 @@ reflection)) + if (empty($this->reflection)) { $this->reflection = new ReflectionMethod( - $this->class, $method + $this->class, + $method ); + } return $this->reflection; } public function runTarget($method, &$params) { - if (is_null($this->instance)) + if (is_null($this->instance)) { $this->instance = call_user_func_array($this->factory, array($method, &$params)); + } - if (!$this->instance instanceof Routable) + if (!$this->instance instanceof Routable) { throw new InvalidArgumentException('Routed classes must implement the Respect\\Rest\\Routable interface'); + } return call_user_func_array( - array($this->instance, $method), $params + array($this->instance, $method), + $params ); } - } diff --git a/library/Respect/Rest/Routes/Instance.php b/library/Respect/Rest/Routes/Instance.php index ae2123a..e9aed1e 100644 --- a/library/Respect/Rest/Routes/Instance.php +++ b/library/Respect/Rest/Routes/Instance.php @@ -1,4 +1,10 @@ reflection)) + if (empty($this->reflection)) { $this->reflection = new ReflectionMethod( - $this->instance, $method + $this->instance, + $method ); + } return $this->reflection; } public function runTarget($method, &$params) { - if (!$this->instance instanceof Routable) + if (!$this->instance instanceof Routable) { throw new InvalidArgumentException('Route target must be an instance of Respect\Rest\Routable'); + } - return call_user_func_array( - array($this->instance, $method), $params + return call_user_func_array( + array($this->instance, $method), + $params ); } - } diff --git a/library/Respect/Rest/Routes/StaticValue.php b/library/Respect/Rest/Routes/StaticValue.php index d63ab52..1dce2aa 100644 --- a/library/Respect/Rest/Routes/StaticValue.php +++ b/library/Respect/Rest/Routes/StaticValue.php @@ -1,4 +1,10 @@ reflection = new ReflectionMethod($this, 'returnValue'); } - + public function getReflection($method) { return $this->reflection; @@ -28,10 +33,9 @@ public function runTarget($method, &$params) { return $this->returnValue($method, $params); } - - public function returnValue() + + public function returnValue() { return $this->value; } - -} \ No newline at end of file +} diff --git a/library/Respect/Rest/Routines/AbstractAccept.php b/library/Respect/Rest/Routines/AbstractAccept.php index 79f35f8..48d2754 100644 --- a/library/Respect/Rest/Routines/AbstractAccept.php +++ b/library/Respect/Rest/Routines/AbstractAccept.php @@ -1,16 +1,23 @@ request_uri = $request->uri; - if (!isset($_SERVER[static::ACCEPT_HEADER])) - return array(); + if (!isset($_SERVER[static::ACCEPT_HEADER])) { + return array(); + } $acceptHeader = $_SERVER[static::ACCEPT_HEADER]; $acceptParts = explode(',', $acceptHeader); $acceptList = array(); foreach ($acceptParts as $k => &$acceptPart) { $parts = explode(';q=', trim($acceptPart)); $provided = array_shift($parts); - $quality = array_shift($parts) ? : (10000 - $k) / 10000; + $quality = array_shift($parts) ?: (10000 - $k) / 10000; $acceptList[$provided] = $quality; } arsort($acceptList); @@ -39,26 +47,29 @@ protected function considerProvisions($requested) } protected function notifyApproved($requested, $provided, Request $request, $params) { - $this->negotiated = new SplObjectStorage;; + $this->negotiated = new SplObjectStorage(); $this->negotiated[$request] = $this->getCallback($provided); if (false === strpos($provided, '.')) { - $header_type = preg_replace( - array( - '/(^.*)(?=\w*$)/U', // select namespace to strip - '/(?!^)([A-Z]+)/' // select camels to add - - ), - array('','-$1'), get_class($this)); - - $content_header = 'Content-Type'; - - if (false !== strpos($header_type, '-')) - $content_header = str_replace('Accept', 'Content', $header_type); - - header("$content_header: $provided"); // RFC 2616 - header("Vary: negotiate,".strtolower($header_type)); // RFC 2616/2295 - header("Content-Location: {$_SERVER['REQUEST_URI']}"); // RFC 2616 - header('Expires: Thu, 01 Jan 1980 00:00:00 GMT'); // RFC 2295 - header('Cache-Control: max-age=86400'); // RFC 2295 + $header_type = preg_replace( + array( + '/(^.*)(?=\w*$)/U', // select namespace to strip + '/(?!^)([A-Z]+)/', // select camels to add - + ), + array('', '-$1'), + get_class($this) + ); + + $content_header = 'Content-Type'; + + if (false !== strpos($header_type, '-')) { + $content_header = str_replace('Accept', 'Content', $header_type); + } + + header("$content_header: $provided"); // RFC 2616 + header("Vary: negotiate,".strtolower($header_type)); // RFC 2616/2295 + header("Content-Location: {$_SERVER['REQUEST_URI']}"); // RFC 2616 + header('Expires: Thu, 01 Jan 1980 00:00:00 GMT'); // RFC 2295 + header('Cache-Control: max-age=86400'); // RFC 2295 } } protected function notifyDeclined($requested, $provided, Request $request, $params) @@ -70,26 +81,29 @@ protected function notifyDeclined($requested, $provided, Request $request, $para protected function authorize($requested, $provided) { // negotiate on file extension - if (false !== strpos($provided, '.')) - if (false !== stripos($this->request_uri, $provided)) - return true; + if (false !== strpos($provided, '.')) { + if (false !== stripos($this->request_uri, $provided)) { + return true; + } + } // normal matching requirements return $requested == $provided; } - - public function by(Request $request, $params) { $unsyncedParams = $request->params; $extensions = $this->filterKeysContain('.'); - if (empty($extensions) || empty($unsyncedParams)) + if (empty($extensions) || empty($unsyncedParams)) { return; + } $unsyncedParams[] = str_replace( - $extensions, '', array_pop($unsyncedParams) + $extensions, + '', + array_pop($unsyncedParams) ); $request->params = $unsyncedParams; } @@ -97,8 +111,9 @@ public function by(Request $request, $params) public function through(Request $request, $params) { if (!isset($this->negotiated[$request]) - || false === $this->negotiated[$request]) - return; + || false === $this->negotiated[$request]) { + return; + } return $this->negotiated[$request]; } diff --git a/library/Respect/Rest/Routines/AbstractCallbackList.php b/library/Respect/Rest/Routines/AbstractCallbackList.php index aebbd57..f9886a3 100644 --- a/library/Respect/Rest/Routines/AbstractCallbackList.php +++ b/library/Respect/Rest/Routines/AbstractCallbackList.php @@ -1,9 +1,15 @@ setFlags(self::ARRAY_AS_PROPS); - if (!($callbackList = array_filter($list, 'is_callable'))) - throw new UnexpectedValueException('Invalid setting: Not a single callable argument for callback routines: '. get_class($this)); + if (!($callbackList = array_filter($list, 'is_callable'))) { + $message = 'Invalid setting: Not a single callable argument for callback routines: '.get_class($this); + throw new UnexpectedValueException($message); + } - foreach ($callbackList as $acceptSpec => $callback) - if (true === is_callable($callback)) + foreach ($callbackList as $acceptSpec => $callback) { + if (true === is_callable($callback)) { $this[$acceptSpec] = $callback; - else + } else { error_log("The $acceptSpec enry does not have a valid callback configured, it has been ignored.\n", 1); + } + } } /** @@ -41,6 +51,7 @@ public function getKeys() public function hasKey($key) { return isset($this->$key); + return array_key_exists($key, $this); } public function filterKeysContain($needle) @@ -71,5 +82,4 @@ protected function executeCallback($key, $params) { return call_user_func_array($this->$key, $params); } - } diff --git a/library/Respect/Rest/Routines/AbstractCallbackMediator.php b/library/Respect/Rest/Routines/AbstractCallbackMediator.php index ff08784..d621cba 100644 --- a/library/Respect/Rest/Routines/AbstractCallbackMediator.php +++ b/library/Respect/Rest/Routines/AbstractCallbackMediator.php @@ -1,8 +1,15 @@ mediate($requested, $provided, $request, $params))) - $this->notifyApproved($requested, $provided, $request, $params); - else - $this->notifyDeclined($requested, $provided, $request, $params); + ($decision = $this->mediate($requested, $provided, $request, $params))) { + $this->notifyApproved($requested, $provided, $request, $params); + } else { + $this->notifyDeclined($requested, $provided, $request, $params); + } + return $decision; } @@ -43,21 +52,25 @@ public function when(Request $request, $params) * supplied. * The implementation gets to authorize against each possibility or the * request will be declined if no satisfactory requirements are reached. - **/ + **/ private function mediate(&$requested, &$provided, Request $request, $params) { - if (is_array($requests = $this->identifyRequested($request, $params))) + if (is_array($requests = $this->identifyRequested($request, $params))) { foreach ($requests as $requested) { - if (is_array($provisions = $this->considerProvisions($requested))) + if (is_array($provisions = $this->considerProvisions($requested))) { foreach ($provisions as $provided) { - if ($this->authorize($requested, $provided, $request)) - return true; + if ($this->authorize($requested, $provided, $request)) { + return true; } - else + } + } else { throw new UnexpectedValueException('Provisions must be an array of 0 to many.'); + } } - else + } else { throw new UnexpectedValueException('Requests must be an array of 0 to many.'); + } + return false; } @@ -66,6 +79,4 @@ protected function authorize($requested, $provided) { return $requested == $provided; } - } - diff --git a/library/Respect/Rest/Routines/AbstractRoutine.php b/library/Respect/Rest/Routines/AbstractRoutine.php index 2952c01..4fc774e 100644 --- a/library/Respect/Rest/Routines/AbstractRoutine.php +++ b/library/Respect/Rest/Routines/AbstractRoutine.php @@ -1,4 +1,10 @@ callback = $callback; + } - if (!is_callable($callback)) + if (!is_callable($callback)) { throw new InvalidArgumentException('Routine callback must be... guess what... callable!'); + } $this->callback = $callback; } diff --git a/library/Respect/Rest/Routines/AbstractSyncedRoutine.php b/library/Respect/Rest/Routines/AbstractSyncedRoutine.php index f9203d6..9351d8f 100644 --- a/library/Respect/Rest/Routines/AbstractSyncedRoutine.php +++ b/library/Respect/Rest/Routines/AbstractSyncedRoutine.php @@ -1,15 +1,19 @@ getReflection(); - if (!$reflection instanceof ReflectionObject && !$reflection instanceof ReflectionClass) + if (!$reflection instanceof ReflectionObject && !$reflection instanceof ReflectionClass) { return $this->getReflection()->getParameters(); + } return array(); } @@ -37,7 +42,7 @@ public function getParameters() * Executes the routine and return its result. * * @param Respect\Rest\Request $request - * @param array $params + * @param array $params * @return mixed */ public function execute(Request $request, $params) @@ -46,8 +51,10 @@ public function execute(Request $request, $params) if (is_string($callback)) { $reflection = $this->getReflection(); $routineInstance = $reflection->newInstanceArgs($params); + return $routineInstance(); } + return call_user_func_array($callback, $params); } @@ -59,14 +66,14 @@ public function execute(Request $request, $params) protected function getReflection() { $callback = $this->getCallback(); - if (is_array($callback)) + if (is_array($callback)) { return new ReflectionMethod($callback[0], $callback[1]); - else if ($callback instanceof Closure) + } elseif ($callback instanceof Closure) { return new ReflectionFunction($callback); - else if (is_string($callback)) + } elseif (is_string($callback)) { return new ReflectionClass($callback); - else + } else { return new ReflectionObject($callback); + } } - } diff --git a/library/Respect/Rest/Routines/Accept.php b/library/Respect/Rest/Routines/Accept.php index bbd646a..182be69 100644 --- a/library/Respect/Rest/Routines/Accept.php +++ b/library/Respect/Rest/Routines/Accept.php @@ -1,9 +1,13 @@ realm = $realm; - parent::__construct($callback); - } - - public function by(Request $request, $params) - { - $callbackResponse = false; - - if (isset($_SERVER['HTTP_AUTHORIZATION'])) - $callbackResponse = call_user_func_array( - $this->callback, - array_merge(explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6))), $params) - ); - elseif (isset($_SERVER['PHP_AUTH_USER'])) - $callbackResponse = call_user_func_array( - $this->callback, - array_merge(array($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']), $params)); - - if ($callbackResponse === false) { - header('HTTP/1.1 401'); - header("WWW-Authenticate: Basic realm=\"{$this->realm}\""); - return call_user_func($this->callback, null, null); - } - - return $callbackResponse; - } - + public $realm; + + public function __construct($realm, $callback) + { + $this->realm = $realm; + parent::__construct($callback); + } + + public function by(Request $request, $params) + { + $callbackResponse = false; + + if (isset($_SERVER['HTTP_AUTHORIZATION'])) { + $callbackResponse = call_user_func_array( + $this->callback, + array_merge(explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6))), $params) + ); + } elseif (isset($_SERVER['PHP_AUTH_USER'])) { + $callbackResponse = call_user_func_array( + $this->callback, + array_merge(array($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']), $params) + ); + } + + if ($callbackResponse === false) { + header('HTTP/1.1 401'); + header("WWW-Authenticate: Basic realm=\"{$this->realm}\""); + + return call_user_func($this->callback, null, null); + } + + return $callbackResponse; + } } diff --git a/library/Respect/Rest/Routines/By.php b/library/Respect/Rest/Routines/By.php index 338caf6..889e5d8 100644 --- a/library/Respect/Rest/Routines/By.php +++ b/library/Respect/Rest/Routines/By.php @@ -1,4 +1,10 @@ execute($request, $params); } - } diff --git a/library/Respect/Rest/Routines/ContentType.php b/library/Respect/Rest/Routines/ContentType.php index f9548ec..3e10705 100644 --- a/library/Respect/Rest/Routines/ContentType.php +++ b/library/Respect/Rest/Routines/ContentType.php @@ -1,21 +1,25 @@ negotiated = new SplObjectStorage;; + $this->negotiated = new SplObjectStorage(); $this->negotiated[$request] = $this->getCallback($provided); } protected function notifyDeclined($requested, $provided, Request $request, $params) @@ -33,7 +37,8 @@ protected function notifyDeclined($requested, $provided, Request $request, $para public function by(Request $request, $params) { - if (false !== $this->negotiated) + if (false !== $this->negotiated) { return call_user_func($this->negotiated[$request]); + } } } diff --git a/library/Respect/Rest/Routines/IgnorableFileExtension.php b/library/Respect/Rest/Routines/IgnorableFileExtension.php index 1465d27..1abd691 100644 --- a/library/Respect/Rest/Routines/IgnorableFileExtension.php +++ b/library/Respect/Rest/Routines/IgnorableFileExtension.php @@ -1,5 +1,13 @@ callback, $params); @@ -20,9 +25,8 @@ public function by(Request $request, $params) header('Last-Modified: '.$lastModifiedOn->format(DateTime::RFC2822)); if ($lastModifiedOn <= $ifModifiedSince) { header('HTTP/1.1 304 Not Modified'); + return false; } - } - } diff --git a/library/Respect/Rest/Routines/ParamSynced.php b/library/Respect/Rest/Routines/ParamSynced.php index 1fc8824..859fb13 100644 --- a/library/Respect/Rest/Routines/ParamSynced.php +++ b/library/Respect/Rest/Routines/ParamSynced.php @@ -1,4 +1,10 @@ setFlags(self::ARRAY_AS_PROPS); $this->exchangeArray($list); - } - - public function extractLinks($data, $relSpec, $deep=true) - { - if (is_callable($relSpec)) { - return call_user_func($relSpec, $data); - } else if ($deep && is_array($relSpec)) { - foreach ($relSpec as &$r) { - $r = $this->extractLinks($data, $r, false); - } - return $relSpec; - } - - return $relSpec; - } - - public function through(Request $request, $params) - { - $rels = $this; - return function ($data) use ($rels) { - foreach ($rels as &$r) { - $r = $rels->extractLinks($data, $r); - } - - if (!isset($data['links'])) { - $data['links'] = array(); - } - - $data['links'] = array_merge_recursive($data['links'], $rels->getArrayCopy()); - - return $data; - }; - } + } + + public function extractLinks($data, $relSpec, $deep = true) + { + if (is_callable($relSpec)) { + return call_user_func($relSpec, $data); + } elseif ($deep && is_array($relSpec)) { + foreach ($relSpec as &$r) { + $r = $this->extractLinks($data, $r, false); + } + + return $relSpec; + } + + return $relSpec; + } + + public function through(Request $request, $params) + { + $rels = $this; + + return function ($data) use ($rels) { + foreach ($rels as &$r) { + $r = $rels->extractLinks($data, $r); + } + + if (!isset($data['links'])) { + $data['links'] = array(); + } + + $data['links'] = array_merge_recursive($data['links'], $rels->getArrayCopy()); + + return $data; + }; + } } diff --git a/library/Respect/Rest/Routines/Routinable.php b/library/Respect/Rest/Routines/Routinable.php index dc5534a..94fcf31 100644 --- a/library/Respect/Rest/Routines/Routinable.php +++ b/library/Respect/Rest/Routines/Routinable.php @@ -1,4 +1,10 @@ execute($request, $params); } - } - diff --git a/library/Respect/Rest/Routines/Unique.php b/library/Respect/Rest/Routines/Unique.php index b703b19..55323ee 100644 --- a/library/Respect/Rest/Routines/Unique.php +++ b/library/Respect/Rest/Routines/Unique.php @@ -1,9 +1,14 @@ negotiated = new SplObjectStorage;; + $this->negotiated = new SplObjectStorage(); $this->negotiated[$request] = $this->getCallback($provided); } protected function notifyDeclined($requested, $provided, Request $request, $params) @@ -31,16 +37,17 @@ protected function notifyDeclined($requested, $provided, Request $request, $para protected function authorize($requested, $provided) { - if ($provided === '*' || preg_match("#$provided#", $requested)) + if ($provided === '*' || preg_match("#$provided#", $requested)) { return true; + } return false; } public function through(Request $request, $params) { - if (false !== $this->negotiated) - return $this->negotiated[$request]; + if (false !== $this->negotiated) { + return $this->negotiated[$request]; + } } - } diff --git a/library/Respect/Rest/Routines/When.php b/library/Respect/Rest/Routines/When.php index 8b1d4a4..0ac55bb 100644 --- a/library/Respect/Rest/Routines/When.php +++ b/library/Respect/Rest/Routines/When.php @@ -1,4 +1,10 @@ execute($request, $params); - if (!$valid) + if (!$valid) { header('HTTP/1.1 400'); + } return $valid; } - } diff --git a/package.ini b/package.ini deleted file mode 100644 index 248f39b..0000000 --- a/package.ini +++ /dev/null @@ -1,69 +0,0 @@ -[package] -name = "Rest" -summary = "Thin controller for RESTful applications" -desc = "Thin controller for RESTful applications" -version = "0.5.1" -stability = "alpha" -channel = "respect.li/pear" -homepage = "" -license = "BSD Style" -author = "Alexandre " -authors[] = "Alexandre Gaigalas " -authors[] = "Alexandre Gaigalas " -authors[] = "Alexandre Gaigalas " -authors[] = "Alexandre Gomes Gaigalas " -authors[] = "Alexandre Gomes Gaigalas " -authors[] = "Anderson Casimiro " -authors[] = "Anderson Casimiro " -authors[] = "augustohp " -authors[] = "Augusto Pascutti " -authors[] = "Augusto Pascutti " -authors[] = "Ben Ramsey " -authors[] = "eduardomarcate " -authors[] = "Eduardo M. Garcia " -authors[] = "Henrique Moody " -authors[] = "kleberhs007 " -authors[] = "Leandro " -authors[] = "Nick Rawe " -authors[] = "Pablo Lacerda de Miranda " -authors[] = "Rogerio Prado de Jesus " -authors[] = "wesleyvicthor " -contributors[] = "Alexandre " -contributors[] = "Alexandre Gaigalas " -contributors[] = "Alexandre Gaigalas " -contributors[] = "Alexandre Gaigalas " -contributors[] = "Alexandre Gomes Gaigalas " -contributors[] = "Alexandre Gomes Gaigalas " -contributors[] = "Anderson Casimiro " -contributors[] = "Anderson Casimiro " -contributors[] = "augustohp " -contributors[] = "Augusto Pascutti " -contributors[] = "Augusto Pascutti " -contributors[] = "Ben Ramsey " -contributors[] = "Daniel Costa " -contributors[] = "eduardomarcate " -contributors[] = "Eduardo M. Garcia " -contributors[] = "Henrique Moody " -contributors[] = "Kinn Coelho JuliĆ£o " -contributors[] = "kleberhs007 " -contributors[] = "Leandro " -contributors[] = "Moritz Schmidt " -contributors[] = "nickl- " -contributors[] = "nickl- " -contributors[] = "Nick Lombard " -contributors[] = "Nick Rawe " -contributors[] = "Pablo Lacerda de Miranda " -contributors[] = "Rogerio Prado de Jesus " -contributors[] = "thiagophx " -contributors[] = "wesleyvicthor " - -[require] -php = "5.3" -pearinstaller = "1.4.1" - -[roles] -library = "php" -config = "cfg" -bin = "script" -public = "www" - diff --git a/package.xml b/package.xml deleted file mode 100644 index fc66353..0000000 --- a/package.xml +++ /dev/null @@ -1,291 +0,0 @@ - - - Rest - respect.li/pear - Thin controller for RESTful applications - Thin controller for RESTful applications - - Alexandre - - alexandre@gaigalas.net - yes - - - Alexandre Gaigalas - - alexandre@gaiaglas.net - yes - - - Alexandre Gaigalas - - alexandre@gaigalas.net - yes - - - Alexandre Gaigalas - - alganet@alganet-workstation.(none) - yes - - - Alexandre Gomes Gaigalas - - alexandre@gaigalas.net - yes - - - Alexandre Gomes Gaigalas - - alganet@alganet-workstation.(none) - yes - - - Anderson Casimiro - - duodraco@duo.draco - yes - - - Anderson Casimiro - - duodraco@gmail.com - yes - - - augustohp - - augusto@phpsp.org.br - yes - - - Augusto Pascutti - - augusto@phpsp.org.br - yes - - - Augusto Pascutti - - contato@augustopascutti.com - yes - - - Ben Ramsey - - ben@benramsey.com - yes - - - eduardomarcate - - eduardo@marcate.info - yes - - - Eduardo M. Garcia - - eduardo@debian.elam - yes - - - Henrique Moody - - henriquemoody@gmail.com - yes - - - kleberhs007 - - kleberhs007@yahoo.com - yes - - - Leandro - - lleitep3@gmail.com - yes - - - Nick Rawe - - nickrawe2@gmail.com - yes - - - Pablo Lacerda de Miranda - - pablolmiranda@gmail.com - yes - - - Rogerio Prado de Jesus - - rogeriopradoj@gmail.com - yes - - - wesleyvicthor - - w.v.mendes.s@gmail.com - yes - - 2012-09-16 - - - 0.5.1 - 0.5.1 - - - alpha - alpha - - BSD Style - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 5.3 - - - 1.4.1 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/tests/phpunit.xml b/phpunit.xml.dist similarity index 54% rename from tests/phpunit.xml rename to phpunit.xml.dist index 00efb2f..200e2e8 100644 --- a/tests/phpunit.xml +++ b/phpunit.xml.dist @@ -1,8 +1,6 @@ + + + tests + + - - ../library/Respect/ + + library/ - - . - - diff --git a/tests/bootstrap.php b/tests/bootstrap.php deleted file mode 100644 index 2cc147a..0000000 --- a/tests/bootstrap.php +++ /dev/null @@ -1,42 +0,0 @@ -