mirror of
https://github.com/skipperbent/simple-php-router.git
synced 2026-06-18 17:26:28 +00:00
Compare commits
320 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 032a2ae7e0 | |||
| c2e2d3bb5d | |||
| 5dd0690009 | |||
| ee61eda1e8 | |||
| 471bbe137f | |||
| b17ba06a8c | |||
| 69494265a5 | |||
| 0d8915b206 | |||
| b54a25804a | |||
| 4b8dbdc9e5 | |||
| 7fe66ac938 | |||
| e5552a88cf | |||
| 7d80517c2f | |||
| b3c135c723 | |||
| e990b95c50 | |||
| a35400b7a0 | |||
| 22606dfc12 | |||
| 5cd6cab801 | |||
| 319ce7a569 | |||
| 4dff4006bf | |||
| eea30d0f59 | |||
| ece9d30905 | |||
| d4de7fc3df | |||
| 03ef9dfb74 | |||
| 4c5f825c97 | |||
| b7c31ae434 | |||
| 0c329e4c5b | |||
| e057a76153 | |||
| f7f1f1e3de | |||
| f93621fa02 | |||
| 5ab8826bfb | |||
| f863f931d8 | |||
| 0d6326dfbb | |||
| 448a423d5d | |||
| df9a855579 | |||
| d6bd9bbd72 | |||
| 569b3a8760 | |||
| 79a075ef49 | |||
| c66d7f7df7 | |||
| c6d0ff3c0e | |||
| 718d60c53b | |||
| 2a573f27fe | |||
| ecbb0825e0 | |||
| b94dc4355f | |||
| 52c6c226c0 | |||
| 982fb9fab4 | |||
| ca8fbf2b27 | |||
| e4584a451d | |||
| 8b11377fe8 | |||
| eccda10169 | |||
| d92d50ecdc | |||
| dca0389115 | |||
| 7adb4e8597 | |||
| b0e4becbba | |||
| 3b8e92b406 | |||
| 0e393fdc5f | |||
| 56c73640b7 | |||
| f91f280975 | |||
| 40f9b72963 | |||
| 245b909ab6 | |||
| 50b7129cab | |||
| 57047d23ea | |||
| a98b5ba842 | |||
| b3d28e9432 | |||
| d0c34255b5 | |||
| 5a917a6905 | |||
| be2d45f0ad | |||
| dd9a6eab7d | |||
| 5621ffc724 | |||
| 438193ef59 | |||
| adc879bb13 | |||
| 06ee78a48f | |||
| 4b992f0a2f | |||
| c423172c23 | |||
| d6d83ac5bd | |||
| b05bbccc28 | |||
| d6bc713e5b | |||
| 8eba5ab3d5 | |||
| c4cf878e97 | |||
| 5b99e98a24 | |||
| c916a1dd2e | |||
| 9ed2d2b8d1 | |||
| caf30cb056 | |||
| 6ccd06911e | |||
| e5eb966780 | |||
| 9e19cbfb71 | |||
| 073479f9dd | |||
| 39ee1bb7cd | |||
| cf1c59aee0 | |||
| d9cfa71534 | |||
| cf6750aaf3 | |||
| 11313a31dc | |||
| 4cb2fa521f | |||
| 8835aca02e | |||
| 86bb88a41f | |||
| fdf11bbc9c | |||
| 2b9403db28 | |||
| 0ec7c0d960 | |||
| d9c63699f5 | |||
| 3e1333ccd4 | |||
| fef65313e5 | |||
| 5624c4b2bb | |||
| 543e550daf | |||
| 22d531178a | |||
| 0892f5b6f3 | |||
| 1d48034910 | |||
| 61fee760b0 | |||
| cfc8b5db43 | |||
| 619a8d00b4 | |||
| 42633ec453 | |||
| dbd8d381e7 | |||
| 57936b7857 | |||
| c466af556e | |||
| db63aff668 | |||
| df52ec3df7 | |||
| 7920188956 | |||
| 635b127357 | |||
| b9af44299e | |||
| a070af2145 | |||
| a33f2f7e7a | |||
| 2689486e64 | |||
| dfc12d07b0 | |||
| 3ebe1a8af2 | |||
| 680e0256c3 | |||
| a8068f76a3 | |||
| 7ba864420e | |||
| 8670af356b | |||
| 6be9d1003c | |||
| 5095b1abc9 | |||
| 5275653606 | |||
| 62f5e5cbbd | |||
| 08008ca847 | |||
| 9f0373938d | |||
| c408f79d8a | |||
| 69fdfb3560 | |||
| a103c71163 | |||
| d3000775d6 | |||
| 824ee86652 | |||
| 495cfba613 | |||
| 5eadb79c64 | |||
| 4725b330fe | |||
| 537d607b9f | |||
| 9029a84fdd | |||
| 87985841de | |||
| 37228d2bac | |||
| 26a1659734 | |||
| 554d562e56 | |||
| 577c87c527 | |||
| d7a295cb5c | |||
| 656946fbb2 | |||
| aa8211a273 | |||
| 90b0747dbd | |||
| e721a92156 | |||
| 67211e5332 | |||
| a44a93d705 | |||
| 4adfa4f322 | |||
| f9c0c83b70 | |||
| eebd537749 | |||
| 0e58d556f0 | |||
| 791ba3199d | |||
| 3c8740769a | |||
| 029739f241 | |||
| c67c6759a8 | |||
| 21710c083c | |||
| 7013822358 | |||
| deb6922d0c | |||
| cb2cb91a0a | |||
| 533dd08217 | |||
| 5508c73e85 | |||
| d5dc81e26e | |||
| 6686de46b9 | |||
| 5c8ff17aec | |||
| 1d2e5f47d9 | |||
| f74252e8cc | |||
| 2fb59854be | |||
| 801f1e68cc | |||
| fa83d2f74b | |||
| fd585e8b9d | |||
| 11fffd9a7b | |||
| 87e9c19edb | |||
| 8a0f30c05e | |||
| 1e0417b249 | |||
| 24f7e3ab13 | |||
| d2b3ea4f54 | |||
| 90a0ca2ee8 | |||
| 9897f66a25 | |||
| e77b723db3 | |||
| 0aeefa1cba | |||
| 8254c5b100 | |||
| 4639879a67 | |||
| 14fe889298 | |||
| dfcbbb4033 | |||
| e8a1eac167 | |||
| 2ff278baef | |||
| 388be3d870 | |||
| f45e0bd12a | |||
| 31b4b4673e | |||
| 05e5461acb | |||
| 3970ad85c4 | |||
| 38ce2e6bba | |||
| 2306ab47db | |||
| 4674dbef1a | |||
| f50ed6cd27 | |||
| d70b153189 | |||
| 21d180ebc9 | |||
| e78040aabd | |||
| 252cc4a75d | |||
| 24ef438334 | |||
| 6fc0241bab | |||
| 19b1a14dec | |||
| fb726c3613 | |||
| 11a69c2f72 | |||
| ff8ef9d412 | |||
| ca88e86c3d | |||
| 5a24dfd4a1 | |||
| 891c2092eb | |||
| 845ef9db69 | |||
| 00c9f9cafd | |||
| 0fe2733c85 | |||
| ce3a2014d1 | |||
| 27cd8b8a1f | |||
| 93c0622b9d | |||
| 572ba1695b | |||
| 1c5701a297 | |||
| 11df7ca18c | |||
| b21feca1fc | |||
| 2a3238f30a | |||
| cb141314f7 | |||
| 153f8630f2 | |||
| b715c48415 | |||
| d601e8eca3 | |||
| 4a8b71a0b5 | |||
| bd01a8a802 | |||
| 55bcd4e030 | |||
| d4a6d504b1 | |||
| 9e3b1b6baa | |||
| 1395527cc6 | |||
| ac594ebde2 | |||
| 064154f27f | |||
| 0ac7fd559a | |||
| da8dfdb135 | |||
| 57c9da2c42 | |||
| 6bdfe06223 | |||
| 5c2a973214 | |||
| a7cbacbde7 | |||
| f0c851e49d | |||
| 45a5176b3c | |||
| 2d042391aa | |||
| 4d842d0583 | |||
| 7c54d319e6 | |||
| 9ccff91287 | |||
| 8653bfa86f | |||
| e51290dfd8 | |||
| 13501b3f88 | |||
| b8cfc4eb0b | |||
| 5db4621831 | |||
| d4bbb6641d | |||
| ca1e2ef94b | |||
| 0fc40f2a82 | |||
| c5c63671ef | |||
| 781fab48cc | |||
| 6e247f811f | |||
| 486d7c3a5b | |||
| 559a65859e | |||
| 8111de48fd | |||
| 8b46d97418 | |||
| 0dbc4e6ba2 | |||
| 38910ea9b6 | |||
| a4dfa59a66 | |||
| d40eaba3e7 | |||
| 2c9d996437 | |||
| 8b6a6864a7 | |||
| 98ce5f7635 | |||
| 6b22632141 | |||
| 69bb570c73 | |||
| ed320e2f87 | |||
| c80b23e9d4 | |||
| 76589e9d92 | |||
| 9d88bf10d2 | |||
| dfa4a9aa6c | |||
| 7c789ea0f8 | |||
| 3ba9dd01f0 | |||
| 14360b6779 | |||
| bbb81333b4 | |||
| 161fbf6ccf | |||
| 9a7b598880 | |||
| 1486095e9f | |||
| 2db20dce6b | |||
| 7cb416cfc8 | |||
| c6341960d7 | |||
| a570322e25 | |||
| 85cf925793 | |||
| feb6c8bd41 | |||
| 7c0a20115e | |||
| 276f213ccc | |||
| 877e0aa937 | |||
| 56457448e4 | |||
| 3e7767d978 | |||
| 8ce1540771 | |||
| 5ef9349b18 | |||
| 3b305ceb00 | |||
| 264f0a7b0f | |||
| 1f00cf50e6 | |||
| 5197ae2990 | |||
| 32bc46be81 | |||
| 9c701aabee | |||
| 2b0821a557 | |||
| 1ee71b9ec3 | |||
| afc81d7005 | |||
| 0b8931a2e1 | |||
| 496d3e7182 | |||
| 2472079642 | |||
| 1fd13ed2aa | |||
| 4409fbcf4e | |||
| 9d5c4a2ed1 | |||
| b8634bcf79 | |||
| 6ad22a3816 | |||
| ed41cd55af | |||
| ebeca952cf | |||
| 0672e85fd7 |
@@ -1,22 +0,0 @@
|
||||
engines:
|
||||
phpmd:
|
||||
enabled: true
|
||||
checks:
|
||||
Design/TooManyPublicMethods:
|
||||
enabled: true
|
||||
Naming/ShortVariable:
|
||||
enabled: true
|
||||
CleanCode/StaticAccess:
|
||||
enabled: true
|
||||
Controversial/CamelCaseMethodName:
|
||||
enabled: true
|
||||
fixme:
|
||||
enabled: true
|
||||
duplication:
|
||||
enabled: true
|
||||
config:
|
||||
languages:
|
||||
- php:
|
||||
ratings:
|
||||
paths:
|
||||
- src/**
|
||||
@@ -0,0 +1,59 @@
|
||||
name: CI
|
||||
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
build-test:
|
||||
runs-on: ${{ matrix.os }}
|
||||
|
||||
env:
|
||||
PHP_EXTENSIONS: json
|
||||
PHP_INI_VALUES: assert.exception=1, zend.assertions=1
|
||||
|
||||
strategy:
|
||||
fail-fast: false
|
||||
matrix:
|
||||
os:
|
||||
- ubuntu-latest
|
||||
- windows-latest
|
||||
php-version:
|
||||
- 7.1
|
||||
- 7.4
|
||||
phpunit-version:
|
||||
- 7.5.20
|
||||
dependencies:
|
||||
- lowest
|
||||
- highest
|
||||
name: PHPUnit Tests
|
||||
steps:
|
||||
- name: Configure git to avoid issues with line endings
|
||||
if: matrix.os == 'windows-latest'
|
||||
run: git config --global core.autocrlf false
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v2
|
||||
- name: Setup PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php-version }}
|
||||
tools: composer:v5, phpunit:${{ matrix.phpunit-versions }}
|
||||
coverage: xdebug
|
||||
extensions: ${{ env.PHP_EXTENSIONS }}
|
||||
ini-values: ${{ env.PHP_INI_VALUES }}
|
||||
- name: Get composer cache directory
|
||||
id: composer-cache
|
||||
run: echo "::set-output name=dir::$(composer config cache-files-dir)"
|
||||
- name: Cache dependencies
|
||||
uses: actions/cache@v2
|
||||
with:
|
||||
path: ${{ steps.composer-cache.outputs.dir }}
|
||||
key: php${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-${{ hashFiles('**/composer.json') }}
|
||||
restore-keys: |
|
||||
php${{ matrix.php-version }}-composer-${{ matrix.dependencies }}-
|
||||
- name: Install lowest dependencies with composer
|
||||
if: matrix.dependencies == 'lowest'
|
||||
run: composer update --no-ansi --no-interaction --no-progress --prefer-lowest
|
||||
- name: Install highest dependencies with composer
|
||||
if: matrix.dependencies == 'highest'
|
||||
run: composer update --no-ansi --no-interaction --no-progress
|
||||
- name: Run tests with phpunit
|
||||
run: composer test
|
||||
+2
-1
@@ -1,3 +1,4 @@
|
||||
composer.lock
|
||||
vendor/
|
||||
tests/tmp/*
|
||||
.idea/
|
||||
.phpunit.result.cache
|
||||
Generated
-5
@@ -1,5 +0,0 @@
|
||||
<component name="ProjectCodeStyleConfiguration">
|
||||
<state>
|
||||
<option name="PREFERRED_PROJECT_CODE_STYLE" value="Simon" />
|
||||
</state>
|
||||
</component>
|
||||
Generated
-12
@@ -1,12 +0,0 @@
|
||||
<component name="ProjectDictionaryState">
|
||||
<dictionary name="simon">
|
||||
<words>
|
||||
<w>bootmanager</w>
|
||||
<w>bootmanagers</w>
|
||||
<w>csrf</w>
|
||||
<w>middlewares</w>
|
||||
<w>pecee</w>
|
||||
<w>urldecode</w>
|
||||
</words>
|
||||
</dictionary>
|
||||
</component>
|
||||
Generated
-72
@@ -1,72 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="MarkdownProjectSettings">
|
||||
<PreviewSettings splitEditorLayout="SPLIT" splitEditorPreview="PREVIEW" useGrayscaleRendering="false" zoomFactor="1.25" maxImageWidth="0" showGitHubPageIfSynced="false" allowBrowsingInPreview="false" synchronizePreviewPosition="true" highlightPreviewType="NONE" highlightFadeOut="5" highlightOnTyping="true" synchronizeSourcePosition="true" verticallyAlignSourceAndPreviewSyncPosition="true" showSearchHighlightsInPreview="false" showSelectionInPreview="true">
|
||||
<PanelProvider>
|
||||
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.panel" providerName="Default - Swing" />
|
||||
</PanelProvider>
|
||||
</PreviewSettings>
|
||||
<ParserSettings gitHubSyntaxChange="false">
|
||||
<PegdownExtensions>
|
||||
<option name="ABBREVIATIONS" value="false" />
|
||||
<option name="ANCHORLINKS" value="true" />
|
||||
<option name="ASIDE" value="false" />
|
||||
<option name="ATXHEADERSPACE" value="true" />
|
||||
<option name="AUTOLINKS" value="true" />
|
||||
<option name="DEFINITIONS" value="false" />
|
||||
<option name="DEFINITION_BREAK_DOUBLE_BLANK_LINE" value="false" />
|
||||
<option name="FENCED_CODE_BLOCKS" value="true" />
|
||||
<option name="FOOTNOTES" value="false" />
|
||||
<option name="HARDWRAPS" value="false" />
|
||||
<option name="HTML_DEEP_PARSER" value="false" />
|
||||
<option name="INSERTED" value="false" />
|
||||
<option name="QUOTES" value="false" />
|
||||
<option name="RELAXEDHRULES" value="true" />
|
||||
<option name="SMARTS" value="false" />
|
||||
<option name="STRIKETHROUGH" value="true" />
|
||||
<option name="SUBSCRIPT" value="false" />
|
||||
<option name="SUPERSCRIPT" value="false" />
|
||||
<option name="SUPPRESS_HTML_BLOCKS" value="false" />
|
||||
<option name="SUPPRESS_INLINE_HTML" value="false" />
|
||||
<option name="TABLES" value="true" />
|
||||
<option name="TASKLISTITEMS" value="true" />
|
||||
<option name="TOC" value="false" />
|
||||
<option name="WIKILINKS" value="true" />
|
||||
</PegdownExtensions>
|
||||
<ParserOptions>
|
||||
<option name="COMMONMARK_LISTS" value="true" />
|
||||
<option name="DUMMY" value="false" />
|
||||
<option name="EMOJI_SHORTCUTS" value="true" />
|
||||
<option name="FLEXMARK_FRONT_MATTER" value="false" />
|
||||
<option name="GFM_LOOSE_BLANK_LINE_AFTER_ITEM_PARA" value="false" />
|
||||
<option name="GFM_TABLE_RENDERING" value="true" />
|
||||
<option name="GITBOOK_URL_ENCODING" value="false" />
|
||||
<option name="GITHUB_EMOJI_URL" value="false" />
|
||||
<option name="GITHUB_LISTS" value="false" />
|
||||
<option name="GITHUB_WIKI_LINKS" value="true" />
|
||||
<option name="JEKYLL_FRONT_MATTER" value="false" />
|
||||
<option name="SIM_TOC_BLANK_LINE_SPACER" value="true" />
|
||||
</ParserOptions>
|
||||
</ParserSettings>
|
||||
<HtmlSettings headerTopEnabled="false" headerBottomEnabled="false" bodyTopEnabled="false" bodyBottomEnabled="false" embedUrlContent="false" addPageHeader="true">
|
||||
<GeneratorProvider>
|
||||
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.generator" providerName="Default Swing HTML Generator" />
|
||||
</GeneratorProvider>
|
||||
<headerTop />
|
||||
<headerBottom />
|
||||
<bodyTop />
|
||||
<bodyBottom />
|
||||
</HtmlSettings>
|
||||
<CssSettings previewScheme="UI_SCHEME" cssUri="" isCssUriEnabled="false" isCssTextEnabled="false" isDynamicPageWidth="true">
|
||||
<StylesheetProvider>
|
||||
<provider providerId="com.vladsch.idea.multimarkdown.editor.swing.html.css" providerName="Default Swing Stylesheet" />
|
||||
</StylesheetProvider>
|
||||
<ScriptProviders />
|
||||
<cssText />
|
||||
</CssSettings>
|
||||
<HtmlExportSettings updateOnSave="false" parentDir="$ProjectFileDir$" targetDir="$ProjectFileDir$" cssDir="" scriptDir="" plainHtml="false" imageDir="" copyLinkedImages="false" imageUniquifyType="0" targetExt="" useTargetExt="false" noCssNoScripts="false" linkToExportedHtml="true" exportOnSettingsChange="true" regenerateOnProjectOpen="false" />
|
||||
<LinkMapSettings>
|
||||
<textMaps />
|
||||
</LinkMapSettings>
|
||||
</component>
|
||||
</project>
|
||||
-3
@@ -1,3 +0,0 @@
|
||||
<component name="MarkdownNavigator.ProfileManager">
|
||||
<settings default="" pdf-export="" />
|
||||
</component>
|
||||
Generated
-8
@@ -1,8 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/simple-php-router.iml" filepath="$PROJECT_DIR$/.idea/simple-php-router.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
Generated
-14
@@ -1,14 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PhpTestFrameworkVersionCache">
|
||||
<tools_cache>
|
||||
<tool tool_name="PHPUnit">
|
||||
<cache>
|
||||
<versions>
|
||||
<info id="Local" version="6.5.7" />
|
||||
</versions>
|
||||
</cache>
|
||||
</tool>
|
||||
</tools_cache>
|
||||
</component>
|
||||
</project>
|
||||
Generated
-52
@@ -1,52 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="PhpIncludePathManager">
|
||||
<include_path>
|
||||
<path value="$PROJECT_DIR$/vendor/composer" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpdocumentor/reflection-common" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/phpunit" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpdocumentor/type-resolver" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpdocumentor/reflection-docblock" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-code-coverage" />
|
||||
<path value="$PROJECT_DIR$/vendor/webmozart/assert" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/phpunit-mock-objects" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/version" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-token-stream" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/diff" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-text-template" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/recursion-context" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-timer" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/exporter" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-file-iterator" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/environment" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/comparator" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/global-state" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/instantiator" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpspec/prophecy" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/resource-operations" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/code-unit-reverse-lookup" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/object-reflector" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/object-enumerator" />
|
||||
<path value="$PROJECT_DIR$/vendor/hamcrest/hamcrest-php" />
|
||||
<path value="$PROJECT_DIR$/vendor/theseer/tokenizer" />
|
||||
<path value="$PROJECT_DIR$/vendor/phar-io/version" />
|
||||
<path value="$PROJECT_DIR$/vendor/phar-io/manifest" />
|
||||
<path value="$PROJECT_DIR$/vendor/myclabs/deep-copy" />
|
||||
<path value="$PROJECT_DIR$/vendor/mockery/mockery" />
|
||||
<path value="$PROJECT_DIR$/vendor/jeremeamia/SuperClosure" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-util" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php56" />
|
||||
<path value="$PROJECT_DIR$/vendor/php-di/invoker" />
|
||||
<path value="$PROJECT_DIR$/vendor/php-di/phpdoc-reader" />
|
||||
<path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/container" />
|
||||
<path value="$PROJECT_DIR$/vendor/php-di/php-di" />
|
||||
</include_path>
|
||||
</component>
|
||||
<component name="PhpProjectSharedConfiguration" php_language_level="7.1" />
|
||||
<component name="PhpUnit">
|
||||
<phpunit_settings>
|
||||
<PhpUnitSettings load_method="CUSTOM_LOADER" configuration_file_path="$PROJECT_DIR$/phpunit.xml" custom_loader_path="$PROJECT_DIR$/vendor/autoload.php" phpunit_phar_path="" use_configuration_file="true" />
|
||||
</phpunit_settings>
|
||||
</component>
|
||||
</project>
|
||||
Generated
-49
@@ -1,49 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="WEB_MODULE" version="4">
|
||||
<component name="NewModuleRootManager">
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/src/Pecee" isTestSource="false" packagePrefix="Pecee\" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/composer" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/doctrine/instantiator" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/hamcrest/hamcrest-php" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/jeremeamia/SuperClosure" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/mockery/mockery" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/myclabs/deep-copy" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/nikic/php-parser" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phar-io/manifest" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phar-io/version" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/php-di/invoker" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/php-di/php-di" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/php-di/phpdoc-reader" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpdocumentor/reflection-common" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpdocumentor/reflection-docblock" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpdocumentor/type-resolver" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpspec/prophecy" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-code-coverage" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-file-iterator" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-text-template" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-timer" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/php-token-stream" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/phpunit" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/phpunit/phpunit-mock-objects" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/psr/container" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/code-unit-reverse-lookup" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/comparator" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/diff" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/environment" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/exporter" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/global-state" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/object-enumerator" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/object-reflector" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/recursion-context" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/resource-operations" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/sebastian/version" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-php56" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/symfony/polyfill-util" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/theseer/tokenizer" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/vendor/webmozart/assert" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
||||
Generated
-6
@@ -1,6 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="$PROJECT_DIR$" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
Generated
-992
@@ -1,992 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="BookmarkManager">
|
||||
<bookmark url="file://$PROJECT_DIR$/src/Pecee/Http/Input/InputHandler.php" line="221" />
|
||||
</component>
|
||||
<component name="ChangeListManager">
|
||||
<list default="true" id="a7058529-bdc4-40b4-a50d-c50564dc83f0" name="Default" comment="">
|
||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/README.md" beforeDir="false" afterPath="$PROJECT_DIR$/README.md" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/helpers.php" beforeDir="false" afterPath="$PROJECT_DIR$/helpers.php" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/Pecee/Http/Input/InputHandler.php" beforeDir="false" afterPath="$PROJECT_DIR$/src/Pecee/Http/Input/InputHandler.php" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/Pecee/Http/Middleware/BaseCsrfVerifier.php" beforeDir="false" afterPath="$PROJECT_DIR$/src/Pecee/Http/Middleware/BaseCsrfVerifier.php" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/Pecee/Http/Request.php" beforeDir="false" afterPath="$PROJECT_DIR$/src/Pecee/Http/Request.php" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/Pecee/Http/Url.php" beforeDir="false" afterPath="$PROJECT_DIR$/src/Pecee/Http/Url.php" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/LoadableRoute.php" beforeDir="false" afterPath="$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/LoadableRoute.php" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/Route.php" beforeDir="false" afterPath="$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/Route.php" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/RouteController.php" beforeDir="false" afterPath="$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/RouteController.php" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/RouteGroup.php" beforeDir="false" afterPath="$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/RouteGroup.php" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/RouteResource.php" beforeDir="false" afterPath="$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/RouteResource.php" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/Pecee/SimpleRouter/Router.php" beforeDir="false" afterPath="$PROJECT_DIR$/src/Pecee/SimpleRouter/Router.php" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/src/Pecee/SimpleRouter/SimpleRouter.php" beforeDir="false" afterPath="$PROJECT_DIR$/src/Pecee/SimpleRouter/SimpleRouter.php" afterDir="false" />
|
||||
<change beforePath="$PROJECT_DIR$/tests/Pecee/SimpleRouter/InputHandlerTest.php" beforeDir="false" afterPath="$PROJECT_DIR$/tests/Pecee/SimpleRouter/InputHandlerTest.php" afterDir="false" />
|
||||
</list>
|
||||
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
|
||||
<option name="TRACKING_ENABLED" value="true" />
|
||||
<option name="SHOW_DIALOG" value="false" />
|
||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
||||
<option name="LAST_RESOLUTION" value="IGNORE" />
|
||||
</component>
|
||||
<component name="ComposerSettings" doNotAsk="true" synchronizationState="SYNCHRONIZE">
|
||||
<pharConfigPath>$PROJECT_DIR$/composer.json</pharConfigPath>
|
||||
</component>
|
||||
<component name="FavoritesManager">
|
||||
<favorites_list name="simple-php-router" />
|
||||
</component>
|
||||
<component name="FileEditorManager">
|
||||
<leaf SIDE_TABS_SIZE_LIMIT_KEY="375">
|
||||
<file leaf-file-name="LoadableRoute.php" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/LoadableRoute.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="20">
|
||||
<caret line="71" column="33" selection-start-line="71" selection-start-column="27" selection-end-line="71" selection-end-column="33" />
|
||||
<folding>
|
||||
<element signature="e#44#82#0#PHP" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="RouteController.php" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/RouteController.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="20">
|
||||
<caret line="15" column="22" lean-forward="true" selection-start-line="15" selection-start-column="22" selection-end-line="15" selection-end-column="22" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="IRoute.php" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/IRoute.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="224">
|
||||
<caret line="39" column="10" selection-start-line="39" selection-start-column="10" selection-end-line="39" selection-end-column="10" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="ILoadableRoute.php" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/ILoadableRoute.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="204">
|
||||
<caret line="32" column="36" selection-start-line="32" selection-start-column="30" selection-end-line="32" selection-end-column="36" />
|
||||
<folding>
|
||||
<element signature="e#44#67#0#PHP" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="RouteUrl.php" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/RouteUrl.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="200">
|
||||
<caret line="10" column="22" lean-forward="true" selection-start-line="10" selection-start-column="22" selection-end-line="10" selection-end-column="22" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="InputHandler.php" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/Http/Input/InputHandler.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="425">
|
||||
<caret line="280" column="38" selection-start-line="280" selection-start-column="38" selection-end-line="280" selection-end-column="38" />
|
||||
<folding>
|
||||
<element signature="e#36#82#0#PHP" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="Route.php" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/Route.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="162">
|
||||
<caret line="498" column="61" selection-start-line="498" selection-start-column="61" selection-end-line="498" selection-end-column="61" />
|
||||
<folding>
|
||||
<element signature="e#44#82#0#PHP" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="Router.php" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/Router.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="220">
|
||||
<caret line="517" lean-forward="true" selection-start-line="517" selection-end-line="517" />
|
||||
<folding>
|
||||
<element signature="e#38#84#0#PHP" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="SimpleRouter.php" pinned="false" current-in-tab="false">
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/SimpleRouter.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="505">
|
||||
<caret line="63" selection-start-line="63" selection-end-line="63" />
|
||||
<folding>
|
||||
<element signature="e#302#319#0#PHP" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
<file leaf-file-name="helpers.php" pinned="false" current-in-tab="true">
|
||||
<entry file="file://$PROJECT_DIR$/helpers.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="180">
|
||||
<caret line="51" column="59" selection-start-line="51" selection-start-column="59" selection-end-line="51" selection-end-column="59" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</file>
|
||||
</leaf>
|
||||
</component>
|
||||
<component name="FindInProjectRecents">
|
||||
<findStrings>
|
||||
<find>void</find>
|
||||
<find>set</find>
|
||||
<find>hasParam</find>
|
||||
<find>csrf_token</find>
|
||||
<find>static function start</find>
|
||||
<find>fireEvents(</find>
|
||||
<find>->setUrl</find>
|
||||
<find>EVENT_LOAD</find>
|
||||
<find>addRoute</find>
|
||||
<find>$this->isPro</find>
|
||||
<find>7.2</find>
|
||||
<find>options</find>
|
||||
<find>parent::set</find>
|
||||
<find>parseParameters</find>
|
||||
<find>stripos</find>
|
||||
<find>setPrefix</find>
|
||||
<find>var_dum</find>
|
||||
<find>parse</find>
|
||||
<find>getParams</find>
|
||||
<find>setQuery</find>
|
||||
<find>contains</find>
|
||||
<find>matchRoute</find>
|
||||
<find>->getValue</find>
|
||||
<find>->find</find>
|
||||
<find>function find</find>
|
||||
<find>Req</find>
|
||||
<find>value(</find>
|
||||
<find>file(</find>
|
||||
<find>setUrl</find>
|
||||
<find>TODO</find>
|
||||
</findStrings>
|
||||
<dirStrings>
|
||||
<dir>D:\Workspace\simple-php-router\src\Pecee\SimpleRouter\Route</dir>
|
||||
<dir>D:\Workspace\simple-php-router\src</dir>
|
||||
<dir>D:\Workspace\simple-php-router\tests\Pecee\SimpleRouter\Dummy</dir>
|
||||
<dir>D:\Workspace\simple-php-router</dir>
|
||||
<dir>E:\Workspace\simple-php-router\tests</dir>
|
||||
<dir>E:\Workspace\simple-php-router\src\Pecee</dir>
|
||||
<dir>E:\Workspace\simple-php-router\tests\Pecee\SimpleRouter</dir>
|
||||
<dir>E:\Workspace\simple-php-router\src\Pecee\SimpleRouter\Route</dir>
|
||||
<dir>E:\Workspace\simple-php-router\src\Pecee\SimpleRouter</dir>
|
||||
<dir>E:\Workspace\simple-php-router\src</dir>
|
||||
<dir>E:\Workspace\simple-php-router</dir>
|
||||
</dirStrings>
|
||||
</component>
|
||||
<component name="Git.Settings">
|
||||
<option name="RECENT_GIT_ROOT_PATH" value="$PROJECT_DIR$" />
|
||||
</component>
|
||||
<component name="IdeDocumentHistory">
|
||||
<option name="CHANGED_PATHS">
|
||||
<list>
|
||||
<option value="$PROJECT_DIR$/tests/Pecee/SimpleRouter/Dummy/Handler/ExceptionHandlerFirst.php" />
|
||||
<option value="$PROJECT_DIR$/tests/Pecee/SimpleRouter/Dummy/Handler/ExceptionHandlerSecond.php" />
|
||||
<option value="$PROJECT_DIR$/tests/TestRouter.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/Event/IEventArgument.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/IRouterBootManager.php" />
|
||||
<option value="$PROJECT_DIR$/tests/Pecee/SimpleRouter/Dummy/Security/SilentTokenProvider.php" />
|
||||
<option value="$PROJECT_DIR$/tests/Pecee/SimpleRouter/Dummy/Managers/TestBootManager.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/Http/Security/CookieTokenProvider.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/Http/Security/ITokenProvider.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/Http/Response.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/IRoute.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/RoutePartialGroup.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/Handlers/IEventHandler.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/Handlers/DebugEventHandler.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/Event/EventArgument.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/Handlers/ClassHandler.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/Handlers/ClassLoader.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/ClassLoader.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/ClassLoader/DIContainerBuilder.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/ClassLoader/Containers/DIContainerBuilder.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/ClassLoader/ContainerInterface.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/ClassLoader/IContainer.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/ClassLoader/IClassLoader.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/ClassLoader/ClassLoader.php" />
|
||||
<option value="$PROJECT_DIR$/composer.json" />
|
||||
<option value="$PROJECT_DIR$/tests/Pecee/SimpleRouter/GroupTest.php" />
|
||||
<option value="$PROJECT_DIR$/tests/Pecee/SimpleRouter/RouterRouteTest.php" />
|
||||
<option value="$PROJECT_DIR$/tests/Pecee/SimpleRouter/DependencyInjectionTest.php" />
|
||||
<option value="$PROJECT_DIR$/.gitignore" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/Http/Input/IInputItem.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/Http/Input/InputItem.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/Http/Input/InputFile.php" />
|
||||
<option value="$PROJECT_DIR$/tests/Pecee/SimpleRouter/EventHandlerTest.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/Handlers/EventHandler.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/RouteGroup.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/RouteResource.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/Http/Url.php" />
|
||||
<option value="$PROJECT_DIR$/tests/Pecee/SimpleRouter/RouterUrlTest.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/Http/Middleware/BaseCsrfVerifier.php" />
|
||||
<option value="$PROJECT_DIR$/README.md" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/Http/Request.php" />
|
||||
<option value="$PROJECT_DIR$/tests/Pecee/SimpleRouter/InputHandlerTest.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/LoadableRoute.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/RouteController.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/ILoadableRoute.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/RouteUrl.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/Http/Input/InputHandler.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/Route.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/Router.php" />
|
||||
<option value="$PROJECT_DIR$/src/Pecee/SimpleRouter/SimpleRouter.php" />
|
||||
<option value="$PROJECT_DIR$/helpers.php" />
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" />
|
||||
<component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER" />
|
||||
<component name="JsFlowSettings">
|
||||
<service-enabled>false</service-enabled>
|
||||
<exe-path />
|
||||
<annotation-enable>false</annotation-enable>
|
||||
<other-services-enabled>false</other-services-enabled>
|
||||
<auto-save>true</auto-save>
|
||||
</component>
|
||||
<component name="JsGulpfileManager">
|
||||
<detection-done>true</detection-done>
|
||||
<sorting>DEFINITION_ORDER</sorting>
|
||||
</component>
|
||||
<component name="PhpWorkspaceProjectConfiguration" interpreter_name="PHP 7.2">
|
||||
<include_path>
|
||||
<path value="$PROJECT_DIR$/vendor/composer" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpdocumentor/reflection-common" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/phpunit" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpdocumentor/type-resolver" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpdocumentor/reflection-docblock" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-code-coverage" />
|
||||
<path value="$PROJECT_DIR$/vendor/webmozart/assert" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/phpunit-mock-objects" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/version" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-token-stream" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/diff" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-text-template" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/recursion-context" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-timer" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/exporter" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpunit/php-file-iterator" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/environment" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/comparator" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/global-state" />
|
||||
<path value="$PROJECT_DIR$/vendor/doctrine/instantiator" />
|
||||
<path value="$PROJECT_DIR$/vendor/phpspec/prophecy" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/resource-operations" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/code-unit-reverse-lookup" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/object-reflector" />
|
||||
<path value="$PROJECT_DIR$/vendor/sebastian/object-enumerator" />
|
||||
<path value="$PROJECT_DIR$/vendor/hamcrest/hamcrest-php" />
|
||||
<path value="$PROJECT_DIR$/vendor/theseer/tokenizer" />
|
||||
<path value="$PROJECT_DIR$/vendor/phar-io/version" />
|
||||
<path value="$PROJECT_DIR$/vendor/phar-io/manifest" />
|
||||
<path value="$PROJECT_DIR$/vendor/myclabs/deep-copy" />
|
||||
<path value="$PROJECT_DIR$/vendor/mockery/mockery" />
|
||||
<path value="$PROJECT_DIR$/vendor/jeremeamia/SuperClosure" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-util" />
|
||||
<path value="$PROJECT_DIR$/vendor/symfony/polyfill-php56" />
|
||||
<path value="$PROJECT_DIR$/vendor/php-di/invoker" />
|
||||
<path value="$PROJECT_DIR$/vendor/php-di/phpdoc-reader" />
|
||||
<path value="$PROJECT_DIR$/vendor/nikic/php-parser" />
|
||||
<path value="$PROJECT_DIR$/vendor/psr/container" />
|
||||
<path value="$PROJECT_DIR$/vendor/php-di/php-di" />
|
||||
</include_path>
|
||||
</component>
|
||||
<component name="ProjectFrameBounds" extendedState="6">
|
||||
<option name="x" value="-10" />
|
||||
<option name="width" value="2295" />
|
||||
<option name="height" value="1235" />
|
||||
</component>
|
||||
<component name="ProjectLevelVcsManager">
|
||||
<ConfirmationsSetting value="2" id="Add" />
|
||||
</component>
|
||||
<component name="ProjectView">
|
||||
<navigator proportions="" version="1">
|
||||
<foldersAlwaysOnTop value="true" />
|
||||
</navigator>
|
||||
<panes>
|
||||
<pane id="Scope" />
|
||||
<pane id="ProjectPane">
|
||||
<subPane>
|
||||
<expand>
|
||||
<path>
|
||||
<item name="simple-php-router" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="simple-php-router" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="simple-php-router" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="simple-php-router" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="src" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="simple-php-router" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="simple-php-router" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="src" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="Pecee" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="simple-php-router" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="simple-php-router" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="src" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="Pecee" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="Http" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="simple-php-router" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="simple-php-router" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="src" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="Pecee" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="Http" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="Input" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="simple-php-router" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="simple-php-router" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="src" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="Pecee" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="SimpleRouter" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="simple-php-router" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="simple-php-router" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="src" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="Pecee" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="SimpleRouter" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="ClassLoader" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="simple-php-router" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="simple-php-router" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="src" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="Pecee" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="SimpleRouter" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="Handlers" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="simple-php-router" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="simple-php-router" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="src" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="Pecee" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="SimpleRouter" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="Route" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
</path>
|
||||
<path>
|
||||
<item name="simple-php-router" type="b2602c69:ProjectViewProjectNode" />
|
||||
<item name="simple-php-router" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
<item name="tests" type="2a2b976b:PhpTreeStructureProvider$1" />
|
||||
</path>
|
||||
</expand>
|
||||
<select />
|
||||
</subPane>
|
||||
</pane>
|
||||
</panes>
|
||||
</component>
|
||||
<component name="PropertiesComponent">
|
||||
<property name="WebServerToolWindowFactoryState" value="false" />
|
||||
<property name="last_opened_file_path" value="$PROJECT_DIR$/../pecee-pixie" />
|
||||
<property name="node.js.detected.package.eslint" value="true" />
|
||||
<property name="node.js.detected.package.standard" value="true" />
|
||||
<property name="node.js.path.for.package.eslint" value="project" />
|
||||
<property name="node.js.path.for.package.standard" value="project" />
|
||||
<property name="node.js.selected.package.eslint" value="" />
|
||||
<property name="node.js.selected.package.standard" value="" />
|
||||
<property name="run.code.analysis.last.selected.profile" value="pProject Default" />
|
||||
<property name="settings.editor.selected.configurable" value="preferences.pluginManager" />
|
||||
</component>
|
||||
<component name="RecentsManager">
|
||||
<key name="CopyFile.RECENT_KEYS">
|
||||
<recent name="E:\Workspace\simple-php-router\tests\Pecee\SimpleRouter" />
|
||||
<recent name="D:\Workspace\simple-php-router\tests" />
|
||||
<recent name="D:\Workspace\simple-php-router" />
|
||||
<recent name="D:\Workspace\simple-php-router\test" />
|
||||
<recent name="D:\Workspace\simple-php-router\src\Pecee\SimpleRouter\Route" />
|
||||
</key>
|
||||
<key name="MoveFile.RECENT_KEYS">
|
||||
<recent name="E:\Workspace\simple-php-router\src\Pecee\SimpleRouter\ClassLoader\Containers" />
|
||||
<recent name="E:\Workspace\simple-php-router\src\Pecee\SimpleRouter\ClassLoader" />
|
||||
<recent name="E:\Workspace\simple-php-router\src\Pecee\SimpleRouter" />
|
||||
<recent name="E:\Workspace\simple-php-router\src\Pecee\SimpleRouter\Handler" />
|
||||
<recent name="D:\Workspace\simple-php-router\tests" />
|
||||
</key>
|
||||
</component>
|
||||
<component name="RunDashboard">
|
||||
<option name="ruleStates">
|
||||
<list>
|
||||
<RuleState>
|
||||
<option name="name" value="ConfigurationTypeDashboardGroupingRule" />
|
||||
</RuleState>
|
||||
<RuleState>
|
||||
<option name="name" value="StatusDashboardGroupingRule" />
|
||||
</RuleState>
|
||||
</list>
|
||||
</option>
|
||||
</component>
|
||||
<component name="RunManager" selected="PHPUnit.phpunit.xml">
|
||||
<configuration name="EventHandlerTest" type="PHPUnitRunConfigurationType" factoryName="PHPUnit" temporary="true">
|
||||
<TestRunner class="EventHandlerTest" file="$PROJECT_DIR$/tests/Pecee/SimpleRouter/EventHandlerTest.php" scope="Class" />
|
||||
</configuration>
|
||||
<configuration name="RouterUrlTest" type="PHPUnitRunConfigurationType" factoryName="PHPUnit" temporary="true">
|
||||
<TestRunner class="RouterUrlTest" file="$PROJECT_DIR$/tests/Pecee/SimpleRouter/RouterUrlTest.php" scope="Class" />
|
||||
</configuration>
|
||||
<configuration name="phpunit.xml" type="PHPUnitRunConfigurationType" factoryName="PHPUnit" temporary="true">
|
||||
<TestRunner configuration_file="$PROJECT_DIR$/phpunit.xml" scope="XML" use_alternative_configuration_file="true" />
|
||||
</configuration>
|
||||
<configuration name="tests" type="PHPUnitRunConfigurationType" factoryName="PHPUnit" temporary="true">
|
||||
<TestRunner directory="$PROJECT_DIR$/tests" />
|
||||
</configuration>
|
||||
<configuration name="debug.php" type="PhpLocalRunConfigurationType" factoryName="PHP Console" temporary="true" path="$PROJECT_DIR$/tests/debug.php" />
|
||||
<list>
|
||||
<item itemvalue="PHPUnit.tests" />
|
||||
<item itemvalue="PHPUnit.RouterUrlTest" />
|
||||
<item itemvalue="PHPUnit.phpunit.xml" />
|
||||
<item itemvalue="PHP Script.debug.php" />
|
||||
<item itemvalue="PHPUnit.EventHandlerTest" />
|
||||
</list>
|
||||
<recent_temporary>
|
||||
<list>
|
||||
<item itemvalue="PHPUnit.phpunit.xml" />
|
||||
<item itemvalue="PHPUnit.EventHandlerTest" />
|
||||
<item itemvalue="PHPUnit.tests" />
|
||||
<item itemvalue="PHP Script.debug.php" />
|
||||
<item itemvalue="PHPUnit.RouterUrlTest" />
|
||||
</list>
|
||||
</recent_temporary>
|
||||
</component>
|
||||
<component name="SvnConfiguration">
|
||||
<configuration />
|
||||
</component>
|
||||
<component name="TaskManager">
|
||||
<task active="true" id="Default" summary="Default task">
|
||||
<changelist id="a7058529-bdc4-40b4-a50d-c50564dc83f0" name="Default" comment="" />
|
||||
<created>1502498236860</created>
|
||||
<option name="number" value="Default" />
|
||||
<option name="presentableId" value="Default" />
|
||||
<updated>1502498236860</updated>
|
||||
<workItem from="1502498238130" duration="495000" />
|
||||
<workItem from="1502589327470" duration="1325000" />
|
||||
<workItem from="1502643621164" duration="1124000" />
|
||||
<workItem from="1502665379176" duration="1624000" />
|
||||
<workItem from="1502669212357" duration="163000" />
|
||||
<workItem from="1503009054866" duration="109000" />
|
||||
<workItem from="1503143546207" duration="965000" />
|
||||
<workItem from="1503146420259" duration="656000" />
|
||||
<workItem from="1503148077591" duration="1223000" />
|
||||
<workItem from="1503157038418" duration="7000" />
|
||||
<workItem from="1503418539960" duration="475000" />
|
||||
<workItem from="1503499434906" duration="6410000" />
|
||||
<workItem from="1503519096046" duration="649000" />
|
||||
<workItem from="1503520310378" duration="280000" />
|
||||
<workItem from="1503521737747" duration="856000" />
|
||||
<workItem from="1503524427576" duration="2573000" />
|
||||
<workItem from="1503536487719" duration="1589000" />
|
||||
<workItem from="1503542802083" duration="820000" />
|
||||
<workItem from="1503585789014" duration="820000" />
|
||||
<workItem from="1504176764746" duration="658000" />
|
||||
<workItem from="1504283976613" duration="694000" />
|
||||
<workItem from="1504448385820" duration="7834000" />
|
||||
<workItem from="1504459201935" duration="83000" />
|
||||
<workItem from="1504459311471" duration="1376000" />
|
||||
<workItem from="1504486369526" duration="451000" />
|
||||
<workItem from="1504917061077" duration="1291000" />
|
||||
<workItem from="1507375921398" duration="131000" />
|
||||
<workItem from="1508785846050" duration="916000" />
|
||||
<workItem from="1508786969551" duration="615000" />
|
||||
<workItem from="1508787603350" duration="1889000" />
|
||||
<workItem from="1509491007644" duration="14000" />
|
||||
<workItem from="1509491033605" duration="6000" />
|
||||
<workItem from="1510192196700" duration="11000" />
|
||||
<workItem from="1510192217149" duration="152000" />
|
||||
<workItem from="1510193026656" duration="140000" />
|
||||
<workItem from="1511567082879" duration="3024000" />
|
||||
<workItem from="1511629790083" duration="1115000" />
|
||||
<workItem from="1511632906778" duration="6000" />
|
||||
<workItem from="1511709768816" duration="954000" />
|
||||
<workItem from="1511710733832" duration="10000" />
|
||||
<workItem from="1511710754848" duration="6388000" />
|
||||
<workItem from="1511717327384" duration="1762000" />
|
||||
<workItem from="1511736112440" duration="855000" />
|
||||
<workItem from="1511741616771" duration="3149000" />
|
||||
<workItem from="1512583258866" duration="985000" />
|
||||
<workItem from="1512706044104" duration="1603000" />
|
||||
<workItem from="1521506970558" duration="7811000" />
|
||||
<workItem from="1522072655826" duration="1072000" />
|
||||
<workItem from="1522073747209" duration="63000" />
|
||||
<workItem from="1522073847648" duration="23574000" />
|
||||
<workItem from="1522309434425" duration="745000" />
|
||||
<workItem from="1522310203119" duration="120000" />
|
||||
<workItem from="1522310337826" duration="117000" />
|
||||
<workItem from="1522310475899" duration="12840000" />
|
||||
<workItem from="1522325810130" duration="30260000" />
|
||||
<workItem from="1522360506281" duration="168000" />
|
||||
<workItem from="1522378435862" duration="2772000" />
|
||||
<workItem from="1522385007533" duration="313000" />
|
||||
<workItem from="1522507670882" duration="309000" />
|
||||
<workItem from="1522508007514" duration="2427000" />
|
||||
<workItem from="1522530661439" duration="3502000" />
|
||||
<workItem from="1522668357317" duration="4847000" />
|
||||
<workItem from="1523014652739" duration="11926000" />
|
||||
</task>
|
||||
<servers />
|
||||
</component>
|
||||
<component name="TestHistory">
|
||||
<history-entry file="phpunit_xml - 2018.04.06 at 16h 11m 34s.xml">
|
||||
<configuration name="phpunit.xml" configurationId="PHPUnitRunConfigurationType" />
|
||||
</history-entry>
|
||||
<history-entry file="phpunit_xml - 2018.04.06 at 16h 11m 56s.xml">
|
||||
<configuration name="phpunit.xml" configurationId="PHPUnitRunConfigurationType" />
|
||||
</history-entry>
|
||||
<history-entry file="phpunit_xml - 2018.04.06 at 16h 12m 06s.xml">
|
||||
<configuration name="phpunit.xml" configurationId="PHPUnitRunConfigurationType" />
|
||||
</history-entry>
|
||||
<history-entry file="phpunit_xml - 2018.04.06 at 16h 12m 15s.xml">
|
||||
<configuration name="phpunit.xml" configurationId="PHPUnitRunConfigurationType" />
|
||||
</history-entry>
|
||||
<history-entry file="phpunit_xml - 2018.04.06 at 16h 53m 38s.xml">
|
||||
<configuration name="phpunit.xml" configurationId="PHPUnitRunConfigurationType" />
|
||||
</history-entry>
|
||||
<history-entry file="phpunit_xml - 2018.04.06 at 16h 54m 36s.xml">
|
||||
<configuration name="phpunit.xml" configurationId="PHPUnitRunConfigurationType" />
|
||||
</history-entry>
|
||||
<history-entry file="phpunit_xml - 2018.04.06 at 16h 55m 10s.xml">
|
||||
<configuration name="phpunit.xml" configurationId="PHPUnitRunConfigurationType" />
|
||||
</history-entry>
|
||||
<history-entry file="phpunit_xml - 2018.04.06 at 16h 55m 25s.xml">
|
||||
<configuration name="phpunit.xml" configurationId="PHPUnitRunConfigurationType" />
|
||||
</history-entry>
|
||||
<history-entry file="phpunit_xml - 2018.04.06 at 16h 57m 00s.xml">
|
||||
<configuration name="phpunit.xml" configurationId="PHPUnitRunConfigurationType" />
|
||||
</history-entry>
|
||||
<history-entry file="phpunit_xml - 2018.04.06 at 16h 57m 10s.xml">
|
||||
<configuration name="phpunit.xml" configurationId="PHPUnitRunConfigurationType" />
|
||||
</history-entry>
|
||||
</component>
|
||||
<component name="TimeTrackingManager">
|
||||
<option name="totallyTimeSpent" value="161141000" />
|
||||
</component>
|
||||
<component name="TodoView">
|
||||
<todo-panel id="selected-file">
|
||||
<is-autoscroll-to-source value="true" />
|
||||
</todo-panel>
|
||||
<todo-panel id="all">
|
||||
<are-packages-shown value="true" />
|
||||
<is-autoscroll-to-source value="true" />
|
||||
</todo-panel>
|
||||
</component>
|
||||
<component name="ToolWindowManager">
|
||||
<frame x="-7" y="-7" width="2062" height="1126" extended-state="6" />
|
||||
<editor active="true" />
|
||||
<layout>
|
||||
<window_info anchor="bottom" id="TODO" order="11" weight="0.32983023" />
|
||||
<window_info anchor="bottom" id="Event Log" order="7" sideWeight="0.50919265" side_tool="true" weight="0.32902184" />
|
||||
<window_info anchor="bottom" id="Database Changes" order="13" show_stripe_button="false" />
|
||||
<window_info anchor="bottom" id="Run" order="2" sideWeight="0.49080735" weight="0.3272727" />
|
||||
<window_info anchor="bottom" id="Version Control" order="14" weight="0.32828283" />
|
||||
<window_info anchor="bottom" id="Terminal" order="12" sideWeight="0.49680257" visible="true" weight="0.28282827" />
|
||||
<window_info active="true" content_ui="combo" id="Project" order="0" visible="true" weight="0.20479521" />
|
||||
<window_info anchor="bottom" id="Docker" order="8" show_stripe_button="false" />
|
||||
<window_info anchor="bottom" id="Inspection Results" order="15" weight="0.32828283" />
|
||||
<window_info anchor="right" id="Database" order="3" />
|
||||
<window_info anchor="bottom" id="Find" order="1" sideWeight="0.48880896" weight="0.3272727" />
|
||||
<window_info id="Structure" order="1" weight="0.24975026" />
|
||||
<window_info anchor="bottom" id="Debug" order="3" weight="0.4" />
|
||||
<window_info id="Favorites" order="2" weight="0.32967034" />
|
||||
<window_info anchor="bottom" id="Message" order="0" />
|
||||
<window_info anchor="right" content_ui="combo" id="Hierarchy" order="2" weight="0.25" />
|
||||
<window_info anchor="bottom" id="Inspection" order="6" weight="0.4" />
|
||||
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
|
||||
<window_info anchor="right" id="Commander" order="0" weight="0.4" />
|
||||
<window_info anchor="right" id="Ant Build" order="1" weight="0.25" />
|
||||
<window_info anchor="bottom" id="PHP-CGI Server" order="10" />
|
||||
<window_info anchor="bottom" id="REST Client" order="5" weight="0.32929292" />
|
||||
<window_info anchor="bottom" id="Command Line Tools Console" order="9" weight="0.32928804" />
|
||||
</layout>
|
||||
</component>
|
||||
<component name="TypeScriptGeneratedFilesManager">
|
||||
<option name="version" value="1" />
|
||||
</component>
|
||||
<component name="VcsContentAnnotationSettings">
|
||||
<option name="myLimit" value="2678400000" />
|
||||
</component>
|
||||
<component name="XDebuggerManager">
|
||||
<breakpoint-manager>
|
||||
<option name="time" value="3" />
|
||||
</breakpoint-manager>
|
||||
</component>
|
||||
<component name="editorHistoryManager">
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/Handlers/IExceptionHandler.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="48">
|
||||
<caret line="2" column="10" lean-forward="true" selection-start-line="2" selection-start-column="10" selection-end-line="2" selection-end-column="28" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/Handlers/DebugEventHandler.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="168">
|
||||
<caret line="7" column="38" lean-forward="true" selection-start-line="7" selection-start-column="38" selection-end-line="7" selection-end-column="38" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/Handlers/IEventHandler.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="552">
|
||||
<caret line="23" column="20" selection-start-line="23" selection-start-column="20" selection-end-line="23" selection-end-column="20" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/Event/EventArgument.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="54">
|
||||
<caret line="45" column="26" lean-forward="true" selection-start-line="45" selection-start-column="26" selection-end-line="45" selection-end-column="26" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/Handlers/CallbackExceptionHandler.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="48">
|
||||
<caret line="2" selection-start-line="2" selection-end-line="2" selection-end-column="38" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/vendor/php-di/php-di/src/ContainerBuilder.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="210">
|
||||
<caret line="121" column="21" selection-start-line="121" selection-start-column="21" selection-end-line="121" selection-end-column="21" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/ClassLoader/Containers/IContainer.php" />
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/ClassLoader/Containers/DIContainerBuilder.php" />
|
||||
<entry file="file://$PROJECT_DIR$/vendor/php-di/php-di/src/FactoryInterface.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="267">
|
||||
<caret line="14" column="10" selection-start-line="14" selection-start-column="10" selection-end-line="14" selection-end-column="10" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/vendor/php-di/invoker/src/InvokerInterface.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="264">
|
||||
<caret line="13" column="10" selection-start-line="13" selection-start-column="10" selection-end-line="13" selection-end-column="10" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/vendor/psr/container/src/ContainerInterface.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="192">
|
||||
<caret line="10" column="10" selection-start-line="10" selection-start-column="10" selection-end-line="10" selection-end-column="10" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/ClassLoader/IContainer.php" />
|
||||
<entry file="file://$PROJECT_DIR$/vendor/mockery/mockery/library/Mockery/Container.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="-3360">
|
||||
<caret line="26" column="6" selection-start-line="26" selection-start-column="6" selection-end-line="26" selection-end-column="6" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/vendor/php-di/php-di/src/Container.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="-21">
|
||||
<caret line="266" column="20" selection-start-line="266" selection-start-column="20" selection-end-line="266" selection-end-column="20" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/ClassLoader/IClassLoader.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="144">
|
||||
<caret line="6" selection-start-line="6" selection-end-line="6" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/tmp/CompiledContainer.php" />
|
||||
<entry file="file://$PROJECT_DIR$/composer.json">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="370">
|
||||
<caret line="30" column="27" selection-start-line="30" selection-start-column="27" selection-end-line="30" selection-end-column="27" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/ClassLoader/ClassLoader.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="384">
|
||||
<caret line="34" column="47" selection-start-line="34" selection-start-column="47" selection-end-line="34" selection-end-column="47" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/tests/Pecee/SimpleRouter/GroupTest.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="258">
|
||||
<caret line="21" column="8" selection-start-line="21" selection-start-column="8" selection-end-line="21" selection-end-column="8" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/tests/Pecee/SimpleRouter/RouterRouteTest.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="572">
|
||||
<caret line="105" column="33" selection-start-line="105" selection-start-column="33" selection-end-line="105" selection-end-column="33" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/tests/Pecee/SimpleRouter/Dummy/Exception/ResponseException.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="192">
|
||||
<caret line="8" column="8" selection-start-line="8" selection-start-column="8" selection-end-line="8" selection-end-column="8" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/tests/Pecee/SimpleRouter/DependencyInjectionTest.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="696">
|
||||
<caret line="29" column="38" selection-start-line="29" selection-start-column="38" selection-end-line="29" selection-end-column="38" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/Http/Input/IInputItem.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="380">
|
||||
<caret line="19" column="40" selection-start-line="19" selection-start-column="40" selection-end-line="19" selection-end-column="40" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/Http/Input/InputItem.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="80">
|
||||
<caret line="4" column="37" selection-start-line="4" selection-start-column="37" selection-end-line="4" selection-end-column="37" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/Http/Input/InputFile.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="180">
|
||||
<caret line="9" column="17" selection-start-line="9" selection-start-column="17" selection-end-line="9" selection-end-column="17" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/Handlers/EventHandler.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="540">
|
||||
<caret line="28" selection-start-line="28" selection-end-line="28" />
|
||||
<folding>
|
||||
<element signature="e#47#90#0#PHP" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/tests/Pecee/SimpleRouter/EventHandlerTest.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="1860">
|
||||
<caret line="94" column="24" selection-start-line="94" selection-start-column="24" selection-end-line="94" selection-end-column="24" />
|
||||
<folding>
|
||||
<element signature="e#249#292#0#PHP" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/IPartialGroupRoute.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="80">
|
||||
<caret line="4" column="10" selection-start-line="4" selection-start-column="10" selection-end-line="4" selection-end-column="10" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/RouteResource.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="403">
|
||||
<caret line="94" column="116" selection-start-line="94" selection-start-column="116" selection-end-line="94" selection-end-column="116" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/Http/Response.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="-2096" />
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/README.md">
|
||||
<provider selected="true" editor-type-id="split-provider[text-editor;markdown-preview-editor]">
|
||||
<state split_layout="SPLIT">
|
||||
<first_editor relative-caret-position="165">
|
||||
<caret line="1202" lean-forward="true" selection-start-line="1202" selection-end-line="1202" />
|
||||
</first_editor>
|
||||
<second_editor />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/vendor/phpunit/phpunit/src/Framework/TestCase.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="-687">
|
||||
<caret line="100" column="15" selection-start-line="100" selection-start-column="15" selection-end-line="100" selection-end-column="15" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/Http/Middleware/BaseCsrfVerifier.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="213">
|
||||
<caret line="69" column="56" selection-start-line="69" selection-start-column="56" selection-end-line="69" selection-end-column="56" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/Http/Request.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="286">
|
||||
<caret line="88" column="24" lean-forward="true" selection-start-line="88" selection-start-column="24" selection-end-line="88" selection-end-column="35" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/tests/Pecee/SimpleRouter/MiddlewareTest.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="120">
|
||||
<caret line="6" column="53" lean-forward="true" selection-start-line="6" selection-start-column="53" selection-end-line="6" selection-end-column="53" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/tests/Pecee/SimpleRouter/RouterUrlTest.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="-34">
|
||||
<caret line="85" selection-start-line="85" selection-end-line="85" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/vendor/phpunit/phpunit/src/Framework/Assert.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="333">
|
||||
<caret line="1197" column="27" selection-start-line="1197" selection-start-column="27" selection-end-line="1197" selection-end-column="27" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/tests/Pecee/SimpleRouter/InputHandlerTest.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="1806">
|
||||
<caret line="93" column="63" selection-start-line="93" selection-start-column="63" selection-end-line="93" selection-end-column="63" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/Http/Url.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="86">
|
||||
<caret line="25" column="20" selection-start-line="25" selection-start-column="20" selection-end-line="25" selection-end-column="20" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/RouteGroup.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="716">
|
||||
<caret line="55" column="45" selection-start-line="55" selection-start-column="45" selection-end-line="55" selection-end-column="45" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/tests/TestRouter.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="240">
|
||||
<caret line="12" selection-start-line="12" selection-end-line="12" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/LoadableRoute.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="20">
|
||||
<caret line="71" column="33" selection-start-line="71" selection-start-column="27" selection-end-line="71" selection-end-column="33" />
|
||||
<folding>
|
||||
<element signature="e#44#82#0#PHP" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/RouteController.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="20">
|
||||
<caret line="15" column="22" lean-forward="true" selection-start-line="15" selection-start-column="22" selection-end-line="15" selection-end-column="22" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/IRoute.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="224">
|
||||
<caret line="39" column="10" selection-start-line="39" selection-start-column="10" selection-end-line="39" selection-end-column="10" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/ILoadableRoute.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="204">
|
||||
<caret line="32" column="36" selection-start-line="32" selection-start-column="30" selection-end-line="32" selection-end-column="36" />
|
||||
<folding>
|
||||
<element signature="e#44#67#0#PHP" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/RouteUrl.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="200">
|
||||
<caret line="10" column="22" lean-forward="true" selection-start-line="10" selection-start-column="22" selection-end-line="10" selection-end-column="22" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/Http/Input/InputHandler.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="425">
|
||||
<caret line="280" column="38" selection-start-line="280" selection-start-column="38" selection-end-line="280" selection-end-column="38" />
|
||||
<folding>
|
||||
<element signature="e#36#82#0#PHP" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/Route/Route.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="162">
|
||||
<caret line="498" column="61" selection-start-line="498" selection-start-column="61" selection-end-line="498" selection-end-column="61" />
|
||||
<folding>
|
||||
<element signature="e#44#82#0#PHP" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/Router.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="220">
|
||||
<caret line="517" lean-forward="true" selection-start-line="517" selection-end-line="517" />
|
||||
<folding>
|
||||
<element signature="e#38#84#0#PHP" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/src/Pecee/SimpleRouter/SimpleRouter.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="505">
|
||||
<caret line="63" selection-start-line="63" selection-end-line="63" />
|
||||
<folding>
|
||||
<element signature="e#302#319#0#PHP" expanded="true" />
|
||||
</folding>
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
<entry file="file://$PROJECT_DIR$/helpers.php">
|
||||
<provider selected="true" editor-type-id="text-editor">
|
||||
<state relative-caret-position="180">
|
||||
<caret line="51" column="59" selection-start-line="51" selection-start-column="59" selection-end-line="51" selection-end-column="59" />
|
||||
</state>
|
||||
</provider>
|
||||
</entry>
|
||||
</component>
|
||||
</project>
|
||||
@@ -1,13 +0,0 @@
|
||||
build:
|
||||
tests:
|
||||
override:
|
||||
-
|
||||
command: './vendor/bin/phpunit --coverage-clover=coverage.clover'
|
||||
coverage:
|
||||
file: 'coverage.clover'
|
||||
format: 'clover'
|
||||
checks:
|
||||
php:
|
||||
code_rating: true
|
||||
duplication: true
|
||||
|
||||
-13
@@ -1,13 +0,0 @@
|
||||
sudo: false
|
||||
|
||||
language: php
|
||||
|
||||
php:
|
||||
- 7.1
|
||||
|
||||
before_script:
|
||||
- curl -sS http://getcomposer.org/installer | php
|
||||
- php composer.phar install --prefer-source --no-interaction
|
||||
|
||||
script:
|
||||
- ./vendor/bin/phpunit
|
||||
@@ -14,8 +14,7 @@ SimpleRouter::get('/', function() {
|
||||
|
||||
### Support the project
|
||||
|
||||
If you like simple-router and wish to see the continued development and maintenance of the project,
|
||||
please consider showing your support by buying me a coffee. Supporters will be listed under the credits section of this documentation.
|
||||
If you like simple-router and wish to see the continued development and maintenance of the project, please consider showing your support by buying me a coffee. Supporters will be listed under the credits section of this documentation.
|
||||
|
||||
You can donate any amount of your choice by [clicking here](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=NNX4D2RUSALCN).
|
||||
|
||||
@@ -33,6 +32,7 @@ You can donate any amount of your choice by [clicking here](https://www.paypal.c
|
||||
- [Helper functions](#helper-functions)
|
||||
- [Routes](#routes)
|
||||
- [Basic routing](#basic-routing)
|
||||
- [Class hinting](#class-hinting)
|
||||
- [Available methods](#available-methods)
|
||||
- [Multiple HTTP-verbs](#multiple-http-verbs)
|
||||
- [Route parameters](#route-parameters)
|
||||
@@ -51,9 +51,6 @@ You can donate any amount of your choice by [clicking here](https://www.paypal.c
|
||||
- [Partial groups](#partial-groups)
|
||||
- [Form Method Spoofing](#form-method-spoofing)
|
||||
- [Accessing The Current Route](#accessing-the-current-route)
|
||||
- [Dependency injection](#dependency-injection)
|
||||
- [Enabling dependency injection](#enabling-dependency-injection)
|
||||
- [More reading](#more-reading)
|
||||
- [Other examples](#other-examples)
|
||||
- [CSRF-protection](#csrf-protection)
|
||||
- [Adding CSRF-verifier](#adding-csrf-verifier)
|
||||
@@ -65,6 +62,7 @@ You can donate any amount of your choice by [clicking here](https://www.paypal.c
|
||||
- [ExceptionHandlers](#exceptionhandlers)
|
||||
- [Handling 404, 403 and other errors](#handling-404-403-and-other-errors)
|
||||
- [Using custom exception handlers](#using-custom-exception-handlers)
|
||||
- [Prevent merge of parent exception-handlers](#prevent-merge-of-parent-exception-handlers)
|
||||
- [Urls](#urls)
|
||||
- [Get the current url](#get-the-current-url)
|
||||
- [Get by name (single route)](#get-by-name-single-route)
|
||||
@@ -80,15 +78,21 @@ You can donate any amount of your choice by [clicking here](https://www.paypal.c
|
||||
- [Get parameter object](#get-parameter-object)
|
||||
- [Managing files](#managing-files)
|
||||
- [Get all parameters](#get-all-parameters)
|
||||
- [Check if parameters exists](#check-if-parameters-exists)
|
||||
- [Events](#events)
|
||||
- [Available events](#available-events)
|
||||
- [Registering new event](#registering-new-event)
|
||||
- [Custom EventHandlers](#custom-eventhandlers)
|
||||
- [Advanced](#advanced)
|
||||
- [Disable multiple route rendering](#disable-multiple-route-rendering)
|
||||
- [Restrict access to IP](#restrict-access-to-ip)
|
||||
- [Setting custom base path](#setting-custom-base-path)
|
||||
- [Url rewriting](#url-rewriting)
|
||||
- [Changing current route](#changing-current-route)
|
||||
- [Bootmanager: loading routes dynamically](#bootmanager-loading-routes-dynamically)
|
||||
- [Adding routes manually](#adding-routes-manually)
|
||||
- [Custom class-loader](#custom-class-loader)
|
||||
- [Integrating with php-di](#Integrating-with-php-di)
|
||||
- [Parameters](#parameters)
|
||||
- [Extending](#extending)
|
||||
- [Help and support](#help-and-support)
|
||||
@@ -123,7 +127,7 @@ composer require pecee/simple-router
|
||||
|
||||
The goal of this project is to create a router that is more or less 100% compatible with the Laravel documentation, while remaining as simple as possible, and as easy to integrate and change without compromising either speed or complexity. Being lightweight is the #1 priority.
|
||||
|
||||
We've included a simple demo project for the router which can be found in the `demo-project` folder. This project should give you a basic understanding of how to setup and use simple-php-router project.
|
||||
We've included a simple demo project for the router which can be found [here](https://github.com/skipperbent/simple-router-demo). This project should give you a basic understanding of how to setup and use simple-php-router project.
|
||||
|
||||
Please note that the demo-project only covers how to integrate the `simple-php-router` in a project without an existing framework. If you are using a framework in your project, the implementation might vary.
|
||||
|
||||
@@ -144,6 +148,7 @@ You can find the demo-project here: [https://github.com/skipperbent/simple-route
|
||||
## Requirements
|
||||
|
||||
- PHP 7.1 or greater (version 3.x and below supports PHP 5.5+)
|
||||
- PHP JSON extension enabled.
|
||||
|
||||
## Features
|
||||
|
||||
@@ -160,6 +165,8 @@ You can find the demo-project here: [https://github.com/skipperbent/simple-route
|
||||
- Sub-domain routing
|
||||
- Custom boot managers to rewrite urls to "nicer" ones.
|
||||
- Input manager; easily manage `GET`, `POST` and `FILE` values.
|
||||
- IP based restrictions.
|
||||
- Easily extendable.
|
||||
|
||||
## Installation
|
||||
|
||||
@@ -249,6 +256,7 @@ To add `favicon.ico` to the IIS ignore-list, add the following line to the `<con
|
||||
```
|
||||
|
||||
You can also make one exception for files with some extensions:
|
||||
|
||||
```
|
||||
<add input="{REQUEST_FILENAME}" pattern="\.ico|\.png|\.css|\.jpg" negate="true" ignoreCase="true" />
|
||||
```
|
||||
@@ -256,6 +264,7 @@ You can also make one exception for files with some extensions:
|
||||
If you are using `$_SERVER['ORIG_PATH_INFO']`, you will get `\index.php\` as part of the returned value.
|
||||
|
||||
**Example:**
|
||||
|
||||
```
|
||||
/index.php/test/mypage.php
|
||||
```
|
||||
@@ -297,8 +306,6 @@ We recommend that you add these helper functions to your project. These will all
|
||||
To implement the functions below, simply copy the code to a new file and require the file before initializing the router or copy the `helpers.php` we've included in this library.
|
||||
|
||||
```php
|
||||
<?php
|
||||
|
||||
use Pecee\SimpleRouter\SimpleRouter as Router;
|
||||
use Pecee\Http\Url;
|
||||
use Pecee\Http\Response;
|
||||
@@ -346,7 +353,7 @@ function request(): Request
|
||||
/**
|
||||
* Get input class
|
||||
* @param string|null $index Parameter index name
|
||||
* @param string|null $defaultValue Default return value
|
||||
* @param string|mixed|null $defaultValue Default return value
|
||||
* @param array ...$methods Default methods
|
||||
* @return \Pecee\Http\Input\InputHandler|array|string|null
|
||||
*/
|
||||
@@ -403,6 +410,14 @@ SimpleRouter::get('/', function() {
|
||||
});
|
||||
```
|
||||
|
||||
### Class hinting
|
||||
|
||||
You can use class hinting to load a class & method like this:
|
||||
|
||||
```php
|
||||
SimpleRouter::get('/', [MyClass::class, 'myMethod']);
|
||||
```
|
||||
|
||||
### Available methods
|
||||
|
||||
Here you can see a list over all available routes:
|
||||
@@ -458,7 +473,8 @@ SimpleRouter::get('/posts/{post}/comments/{comment}', function ($postId, $commen
|
||||
});
|
||||
```
|
||||
|
||||
**Note:** Route parameters are always encased within {} braces and should consist of alphabetic characters. Route parameters may not contain a - character. Use an underscore (_) instead.
|
||||
**Note:** Route parameters are always encased within `{` `}` braces and should consist of alphabetic characters. Route parameters can only contain certain characters like `A-Z`, `a-z`, `0-9`, `-` and `_`.
|
||||
If your route contain other characters, please see [Custom regex for matching parameters](#custom-regex-for-matching-parameters).
|
||||
|
||||
### Optional parameters
|
||||
|
||||
@@ -483,13 +499,13 @@ SimpleRouter::get('/user/{name}', function ($name) {
|
||||
|
||||
// ... do stuff
|
||||
|
||||
})->where('name', '[A-Za-z]+');
|
||||
})->where([ 'name' => '[A-Za-z]+' ]);
|
||||
|
||||
SimpleRouter::get('/user/{id}', function ($id) {
|
||||
|
||||
// ... do stuff
|
||||
|
||||
})->where('id', '[0-9]+');
|
||||
})->where([ 'id' => '[0-9]+' ]);
|
||||
|
||||
SimpleRouter::get('/user/{id}/{name}', function ($id, $name) {
|
||||
|
||||
@@ -521,10 +537,12 @@ SimpleRouter::all('/ajax/abc/123', function($param1, $param2) {
|
||||
|
||||
### Custom regex for matching parameters
|
||||
|
||||
By default simple-php-router uses the `\w` regular expression when matching parameters.
|
||||
By default simple-php-router uses the `[\w\-]+` regular expression. It will match `A-Z`, `a-z`, `0-9`, `-` and `_` characters in parameters.
|
||||
This decision was made with speed and reliability in mind, as this match will match both letters, number and most of the used symbols on the internet.
|
||||
|
||||
However, sometimes it can be necessary to add a custom regular expression to match more advanced characters like `-` etc.
|
||||
However, sometimes it can be necessary to add a custom regular expression to match more advanced characters like foreign letters `æ ø å` etc.
|
||||
|
||||
You can test your custom regular expression by using on the site [Regex101.com](https://www.regex101.com).
|
||||
|
||||
Instead of adding a custom regular expression to all your parameters, you can simply add a global regular expression which will be used on all the parameters on the route.
|
||||
|
||||
@@ -532,16 +550,16 @@ Instead of adding a custom regular expression to all your parameters, you can si
|
||||
|
||||
#### Example
|
||||
|
||||
This example will ensure that all parameters use the `[\w\-]+` regular expression when parsing.
|
||||
This example will ensure that all parameters use the `[\w\-\æ\ø\å]+` (`a-z`, `A-Z`, `-`, `_`, `0-9`, `æ`, `ø`, `å`) regular expression when parsing.
|
||||
|
||||
```php
|
||||
SimpleRouter::get('/path/{parameter}', 'VideoController@home', ['defaultParameterRegex' => '[\w\-]+']);
|
||||
SimpleRouter::get('/path/{parameter}', 'VideoController@home', ['defaultParameterRegex' => '[\w\-\æ\ø\å]+']);
|
||||
```
|
||||
|
||||
You can also apply this setting to a group if you need multiple routes to use your custom regular expression when parsing parameters.
|
||||
|
||||
```php
|
||||
SimpleRouter::group(['defaultParameterRegex' => '[\w\-]+'], function() {
|
||||
SimpleRouter::group(['defaultParameterRegex' => '[\w\-\æ\ø\å]+'], function() {
|
||||
|
||||
SimpleRouter::get('/path/{parameter}', 'VideoController@home');
|
||||
|
||||
@@ -620,6 +638,23 @@ SimpleRouter::group(['namespace' => 'Admin'], function () {
|
||||
});
|
||||
```
|
||||
|
||||
You can add parameters to the prefixes of your routes.
|
||||
|
||||
Parameters from your previous routes will be injected
|
||||
into your routes after any route-required parameters, starting from oldest to newest.
|
||||
|
||||
```php
|
||||
SimpleRouter::group(['prefix' => '/lang/{lang}'], function ($language) {
|
||||
|
||||
SimpleRouter::get('/about', function($language) {
|
||||
|
||||
// Will match /lang/da/about
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
### Subdomain-routing
|
||||
|
||||
Route groups may also be used to handle sub-domain routing. Sub-domains may be assigned route parameters just like route urls, allowing you to capture a portion of the sub-domain for usage in your route or controller. The sub-domain may be specified using the `domain` key on the group attribute array:
|
||||
@@ -644,29 +679,37 @@ SimpleRouter::group(['prefix' => '/admin'], function () {
|
||||
});
|
||||
```
|
||||
|
||||
You can also use parameters in your groups:
|
||||
|
||||
```php
|
||||
SimpleRouter::group(['prefix' => '/lang/{language}'], function ($language) {
|
||||
SimpleRouter::get('/users', function ($language) {
|
||||
// Matches The "/lang/da/users" URL
|
||||
});
|
||||
});
|
||||
```
|
||||
|
||||
## Partial groups
|
||||
|
||||
Partial router groups has the same benefits as a normal group, but supports parameters and are only rendered once the url has matched.
|
||||
Partial router groups has the same benefits as a normal group, but **are only rendered once the url has matched**
|
||||
in contrast to a normal group which are always rendered in order to retrieve it's child routes.
|
||||
Partial groups are therefore more like a hybrid of a traditional route with the benefits of a group.
|
||||
|
||||
This can be extremely useful in situations, where you only want special routes to be added, when a certain criteria or logic has been met.
|
||||
This can be extremely useful in situations where you only want special routes to be added, but only when a certain criteria or logic has been met.
|
||||
|
||||
**NOTE:** Use partial groups with caution as routes added within are only rendered and available once the url of the partial-group has matched. This can cause `url()` not to find urls for the routes added within.
|
||||
**NOTE:** Use partial groups with caution as routes added within are only rendered and available once the url of the partial-group has matched.
|
||||
This can cause `url()` not to find urls for the routes added within before the partial-group has been matched and is rendered.
|
||||
|
||||
**Example:**
|
||||
|
||||
```php
|
||||
SimpleRouter::partialGroup('/admin/{applicationId}', function ($applicationId) {
|
||||
SimpleRouter::partialGroup('/plugin/{name}', function ($plugin) {
|
||||
|
||||
SimpleRouter::get('/', function($applicationId) {
|
||||
|
||||
// Matches The "/admin/applicationId" URL
|
||||
|
||||
});
|
||||
// Add routes from plugin
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## Form Method Spoofing
|
||||
|
||||
HTML forms do not support `PUT`, `PATCH` or `DELETE` actions. So, when defining `PUT`, `PATCH` or `DELETE` routes that are called from an HTML form, you will need to add a hidden `_method` field to the form. The value sent with the `_method` field will be used as the HTTP request method:
|
||||
@@ -684,88 +727,6 @@ SimpleRouter::request()->getLoadedRoute();
|
||||
request()->getLoadedRoute();
|
||||
```
|
||||
|
||||
## Dependency injection
|
||||
|
||||
simple-router supports dependency injection using the [`php-di`](http://php-di.org/) library.
|
||||
|
||||
Dependency injection allows the framework to automatically "inject" (load) classes added as parameters. This can simplify your code, as you can avoid creating new instances of objects you are using often in your `Controllers` etc.
|
||||
|
||||
Here's a basic example of a controller class using dependency injection:
|
||||
|
||||
```php
|
||||
namespace Demo\Controllers;
|
||||
|
||||
class DefaultController {
|
||||
|
||||
public function login(User $user): string
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
The example above will automatically create a new instance of the `User` from the `$user` parameter. This means that the `$user` class contains a new instance of the `User` class and we won't need to create a new instance our self.
|
||||
|
||||
**WARNING:** dependency injection can have some negative impact in performance. If you experience any performance issues, we recommend disabling this functionality.
|
||||
|
||||
### Enabling dependency injection
|
||||
|
||||
Dependency injection is disabled per default to avoid any performance issues.
|
||||
|
||||
Before enabling dependency injection, we recommend that you read the [Container configuration](http://php-di.org/doc/container-configuration.html) section of the php-di documentation. This section covers how to configure php-di to different environments and speed-up the performance.
|
||||
|
||||
#### Enabling for development environment
|
||||
|
||||
The example below should ONLY be used on a development environment.
|
||||
|
||||
```php
|
||||
// Create our new php-di container
|
||||
$container = (new \DI\ContainerBuilder())
|
||||
->useAutowiring(true)
|
||||
->build();
|
||||
|
||||
// Add our container to simple-router and enable dependency injection
|
||||
SimpleRouter::enableDependencyInjection($container);
|
||||
```
|
||||
|
||||
Please check the [More reading](#more-reading) section of the documentation for useful php-di links and tutorials.
|
||||
|
||||
#### Enabling for production environment
|
||||
|
||||
The example below compiles the injections, which can help speed up performance.
|
||||
|
||||
**Note:** You should change the `$cacheDir` to a cache-storage within your project.
|
||||
|
||||
```php
|
||||
// Cache directory
|
||||
$cacheDir = sys_get_temp_dir('simple-router');
|
||||
|
||||
// Create our new php-di container
|
||||
$container = (new \DI\ContainerBuilder())
|
||||
->enableCompilation($cacheDir)
|
||||
->writeProxiesToFile(true, $cacheDir . '/proxies')
|
||||
->useAutowiring(true)
|
||||
->build();
|
||||
|
||||
// Add our container to simple-router and enable dependency injection
|
||||
SimpleRouter::enableDependencyInjection($container);
|
||||
```
|
||||
|
||||
Please check the [More reading](#more-reading) section of the documentation for useful php-di links and tutorials.
|
||||
|
||||
### More reading
|
||||
|
||||
For more information about dependency injection, configuration and settings - we recommend that you check the php-di documentation or some of the useful links we've gathered below.
|
||||
|
||||
#### Useful links
|
||||
|
||||
- [php-di documentation](http://php-di.org/doc/)
|
||||
- [Understanding dependency injection](http://php-di.org/doc/understanding-di.html)
|
||||
- [Best practices guide](http://php-di.org/doc/best-practices.html)
|
||||
- [Configuring the container](http://php-di.org/doc/container-configuration.html)
|
||||
- [Definitions](http://php-di.org/doc/definition.html)
|
||||
|
||||
## Other examples
|
||||
|
||||
You can find many more examples in the `routes.php` example-file below:
|
||||
@@ -782,12 +743,17 @@ SimpleRouter::group(['middleware' => \Demo\Middlewares\Site::class, 'exceptionHa
|
||||
|
||||
SimpleRouter::get('/answers/{id}', 'ControllerAnswers@show', ['where' => ['id' => '[0-9]+']]);
|
||||
|
||||
/**
|
||||
* Class hinting is supported too
|
||||
*/
|
||||
|
||||
SimpleRouter::get('/answers/{id}', [ControllerAnswers::class, 'show'], ['where' => ['id' => '[0-9]+']]);
|
||||
|
||||
/**
|
||||
* Restful resource (see IRestController interface for available methods)
|
||||
*/
|
||||
|
||||
SimpleRouter::resource('/rest', ControllerRessource::class);
|
||||
SimpleRouter::resource('/rest', ControllerResource::class);
|
||||
|
||||
|
||||
/**
|
||||
@@ -808,7 +774,6 @@ SimpleRouter::group(['middleware' => \Demo\Middlewares\Site::class, 'exceptionHa
|
||||
});
|
||||
|
||||
SimpleRouter::get('/page/404', 'ControllerPage@notFound', ['as' => 'page.notfound']);
|
||||
|
||||
```
|
||||
|
||||
---
|
||||
@@ -827,7 +792,7 @@ If you want to store the token elsewhere, please refer to the "Creating custom T
|
||||
When you've created your CSRF-verifier you need to tell simple-php-router that it should use it. You can do this by adding the following line in your `routes.php` file:
|
||||
|
||||
```php
|
||||
Router::csrfVerifier(new \Demo\Middlewares\CsrfVerifier());
|
||||
SimpleRouter::csrfVerifier(new \Demo\Middlewares\CsrfVerifier());
|
||||
```
|
||||
|
||||
## Getting CSRF-token
|
||||
@@ -843,7 +808,7 @@ csrf_token();
|
||||
You can also get the token directly:
|
||||
|
||||
```php
|
||||
return Router::router()->getCsrfVerifier()->getTokenProvider()->getToken();
|
||||
return SimpleRouter::router()->getCsrfVerifier()->getTokenProvider()->getToken();
|
||||
```
|
||||
|
||||
The default name/key for the input-field is `csrf_token` and is defined in the `POST_KEY` constant in the `BaseCsrfVerifier` class.
|
||||
@@ -929,10 +894,10 @@ class SessionTokenProvider implements ITokenProvider
|
||||
Next you need to set your custom `ITokenProvider` implementation on your `BaseCsrfVerifier` class in your routes file:
|
||||
|
||||
```php
|
||||
$verifier = new \dscuz\Middleware\CsrfVerifier();
|
||||
$verifier = new \Demo\Middlewares\CsrfVerifier();
|
||||
$verifier->setTokenProvider(new SessionTokenProvider());
|
||||
|
||||
Router::csrfVerifier($verifier);
|
||||
SimpleRouter::csrfVerifier($verifier);
|
||||
```
|
||||
|
||||
---
|
||||
@@ -974,7 +939,7 @@ ExceptionHandler are classes that handles all exceptions. ExceptionsHandlers mus
|
||||
|
||||
## Handling 404, 403 and other errors
|
||||
|
||||
If you simply want to catch a 404 (page not found) etc. you can use the `Router::error($callback)` static helper method.
|
||||
If you simply want to catch a 404 (page not found) etc. you can use the `SimpleRouter::error($callback)` static helper method.
|
||||
|
||||
This will add a callback method which is fired whenever an error occurs on all routes.
|
||||
|
||||
@@ -982,17 +947,31 @@ The basic example below simply redirect the page to `/not-found` if an `NotFound
|
||||
The code should be placed in the file that contains your routes.
|
||||
|
||||
```php
|
||||
Router::get('/not-found', 'PageController@notFound');
|
||||
SimpleRouter::get('/not-found', 'PageController@notFound');
|
||||
SimpleRouter::get('/forbidden', 'PageController@notFound');
|
||||
|
||||
Router::error(function(Request $request, \Exception $exception) {
|
||||
SimpleRouter::error(function(Request $request, \Exception $exception) {
|
||||
|
||||
if($exception instanceof NotFoundHttpException && $exception->getCode() === 404) {
|
||||
response()->redirect('/not-found');
|
||||
switch($exception->getCode()) {
|
||||
// Page not found
|
||||
case 404:
|
||||
response()->redirect('/not-found');
|
||||
// Forbidden
|
||||
case 403:
|
||||
response()->redirect('/forbidden');
|
||||
}
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
The example above will redirect all errors with http-code `404` (page not found) to `/not-found` and `403` (forbidden) to `/forbidden`.
|
||||
|
||||
If you do not want a redirect, but want the error-page rendered on the current-url, you can tell the router to execute a rewrite callback like so:
|
||||
|
||||
```php
|
||||
$request->setRewriteCallback('ErrorController@notFound');
|
||||
```
|
||||
|
||||
## Using custom exception handlers
|
||||
|
||||
This is a basic example of an ExceptionHandler implementation (please see "[Easily overwrite route about to be loaded](#easily-overwrite-route-about-to-be-loaded)" for examples on how to change callback).
|
||||
@@ -1036,6 +1015,41 @@ class CustomExceptionHandler implements IExceptionHandler
|
||||
}
|
||||
```
|
||||
|
||||
You can add your custom exception-handler class to your group by using the `exceptionHandler` settings-attribute.
|
||||
`exceptionHandler` can be either class-name or array of class-names.
|
||||
|
||||
```php
|
||||
SimpleRouter::group(['exceptionHandler' => \Demo\Handlers\CustomExceptionHandler::class], function() {
|
||||
|
||||
// Your routes here
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
### Prevent merge of parent exception-handlers
|
||||
|
||||
By default the router will merge exception-handlers to any handlers provided by parent groups, and will be executed in the order of newest to oldest.
|
||||
|
||||
If you want your groups exception handler to be executed independently, you can add the `mergeExceptionHandlers` attribute and set it to `false`.
|
||||
|
||||
```php
|
||||
SimpleRouter::group(['prefix' => '/', 'exceptionHandler' => \Demo\Handlers\FirstExceptionHandler::class, 'mergeExceptionHandlers' => false], function() {
|
||||
|
||||
SimpleRouter::group(['prefix' => '/admin', 'exceptionHandler' => \Demo\Handlers\SecondExceptionHandler::class], function() {
|
||||
|
||||
// Both SecondExceptionHandler and FirstExceptionHandler will trigger (in that order).
|
||||
|
||||
});
|
||||
|
||||
SimpleRouter::group(['prefix' => '/user', 'exceptionHandler' => \Demo\Handlers\SecondExceptionHandler::class, 'mergeExceptionHandlers' => false], function() {
|
||||
|
||||
// Only SecondExceptionHandler will trigger.
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
# Urls
|
||||
@@ -1273,8 +1287,11 @@ $values = input()->all([
|
||||
All object implements the `IInputItem` interface and will always contain these methods:
|
||||
|
||||
- `getIndex()` - returns the index/key of the input.
|
||||
- `setIndex()` - set the index/key of the input.
|
||||
- `getName()` - returns a human friendly name for the input (company_name will be Company Name etc).
|
||||
- `setName()` - sets a human friendly name for the input (company_name will be Company Name etc).
|
||||
- `getValue()` - returns the value of the input.
|
||||
- `setValue()` - sets the value of the input.
|
||||
|
||||
`InputFile` has the same methods as above along with some other file-specific methods like:
|
||||
|
||||
@@ -1290,6 +1307,24 @@ All object implements the `IInputItem` interface and will always contain these m
|
||||
|
||||
---
|
||||
|
||||
### Check if parameters exists
|
||||
|
||||
You can easily if multiple items exists by using the `exists` method. It's simular to `value` as it can be used
|
||||
to filter on request-methods and supports both `string` and `array` as parameter value.
|
||||
|
||||
**Example:**
|
||||
|
||||
```php
|
||||
if(input()->exists(['name', 'lastname'])) {
|
||||
// Do stuff
|
||||
}
|
||||
|
||||
/* Similar to code above */
|
||||
if(input()->exists('name') && input()->exists('lastname')) {
|
||||
// Do stuff
|
||||
}
|
||||
```
|
||||
|
||||
# Events
|
||||
|
||||
This section will help you understand how to register your own callbacks to events in the router.
|
||||
@@ -1306,13 +1341,13 @@ All event callbacks will retrieve a `EventArgument` object as parameter. This ob
|
||||
| `EVENT_ALL` | - | Fires when a event is triggered. |
|
||||
| `EVENT_INIT` | - | Fires when router is initializing and before routes are loaded. |
|
||||
| `EVENT_LOAD` | `loadedRoutes` | Fires when all routes has been loaded and rendered, just before the output is returned. |
|
||||
| `EVENT_ADD_ROUTE` | `route` | Fires when route is added to the router. |
|
||||
| `EVENT_ADD_ROUTE` | `route`<br>`isSubRoute` | Fires when route is added to the router. `isSubRoute` is true when sub-route is rendered. |
|
||||
| `EVENT_REWRITE` | `rewriteUrl`<br>`rewriteRoute` | Fires when a url-rewrite is and just before the routes are re-initialized. |
|
||||
| `EVENT_BOOT` | `bootmanagers` | Fires when the router is booting. This happens just before boot-managers are rendered and before any routes has been loaded. |
|
||||
| `EVENT_RENDER_BOOTMANAGER` | `bootmanagers`<br>`bootmanager` | Fires before a boot-manager is rendered. |
|
||||
| `EVENT_LOAD_ROUTES` | `routes` | Fires when the router is about to load all routes. |
|
||||
| `EVENT_FIND_ROUTE` | `name` | Fires whenever the `findRoute` method is called within the `Router`. This usually happens when the router tries to find routes that contains a certain url, usually after the `EventHandler::EVENT_GET_URL` event. |
|
||||
| `EVENT_GET_URL` | `name`<br>`parameters`<br>`getParams` | Fires whenever the `Router::getUrl` method or `url`-helper function is called and the router tries to find the route. |
|
||||
| `EVENT_GET_URL` | `name`<br>`parameters`<br>`getParams` | Fires whenever the `SimpleRouter::getUrl` method or `url`-helper function is called and the router tries to find the route. |
|
||||
| `EVENT_MATCH_ROUTE` | `route` | Fires when a route is matched and valid (correct request-type etc). and before the route is rendered. |
|
||||
| `EVENT_RENDER_ROUTE` | `route` | Fires before a route is rendered. |
|
||||
| `EVENT_LOAD_EXCEPTIONS` | `exception`<br>`exceptionHandlers` | Fires when the router is loading exception-handlers. |
|
||||
@@ -1428,6 +1463,80 @@ class DatabaseDebugHandler implements IEventHandler
|
||||
|
||||
# Advanced
|
||||
|
||||
## Disable multiple route rendering
|
||||
|
||||
By default the router will try to execute all routes that matches a given url. To stop the router from executing any further routes any method can return a value.
|
||||
|
||||
This behavior can be easily disabled by setting `SimpleRouter::enableMultiRouteRendering(false)` in your `routes.php` file. This is the same behavior as version 3 and below.
|
||||
|
||||
## Restrict access to IP
|
||||
|
||||
You can white and/or blacklist access to IP's using the build in `IpRestrictAccess` middleware.
|
||||
|
||||
Create your own custom Middleware and extend the `IpRestrictAccess` class.
|
||||
|
||||
The `IpRestrictAccess` class contains two properties `ipBlacklist` and `ipWhitelist` that can be added to your middleware to change which IP's that have access to your routes.
|
||||
|
||||
You can use `*` to restrict access to a range of ips.
|
||||
|
||||
```php
|
||||
use \Pecee\Http\Middleware\IpRestrictAccess;
|
||||
|
||||
class IpBlockerMiddleware extends IpRestrictAccess
|
||||
{
|
||||
|
||||
protected $ipBlacklist = [
|
||||
'5.5.5.5',
|
||||
'8.8.*',
|
||||
];
|
||||
|
||||
protected $ipWhitelist = [
|
||||
'8.8.2.2',
|
||||
];
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
You can add the middleware to multiple routes by adding your [middleware to a group](#middleware).
|
||||
|
||||
## Setting custom base path
|
||||
|
||||
Sometimes it can be useful to add a custom base path to all of the routes added.
|
||||
|
||||
This can easily be done by taking advantage of the [Event Handlers](#events) support of the project.
|
||||
|
||||
```php
|
||||
$basePath = '/basepath';
|
||||
|
||||
$eventHandler = new EventHandler();
|
||||
$eventHandler->register(EventHandler::EVENT_ADD_ROUTE, function(EventArgument $event) use($basePath) {
|
||||
|
||||
$route = $event->route;
|
||||
|
||||
// Skip routes added by group as these will inherit the url
|
||||
if(!$event->isSubRoute) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch (true) {
|
||||
case $route instanceof ILoadableRoute:
|
||||
$route->prependUrl($basePath);
|
||||
break;
|
||||
case $route instanceof IGroupRoute:
|
||||
$route->prependPrefix($basePath);
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
SimpleRouter::addEventHandler($eventHandler);
|
||||
```
|
||||
|
||||
In the example shown above, we create a new `EVENT_ADD_ROUTE` event that triggers, when a new route is added.
|
||||
We skip all subroutes as these will inherit the url from their parent. Then, if the route is a group, we change the prefix
|
||||
otherwise we change the url.
|
||||
|
||||
## Url rewriting
|
||||
|
||||
### Changing current route
|
||||
@@ -1479,7 +1588,7 @@ class CustomRouterRules implement IRouterBootManager
|
||||
|
||||
// If the current url matches the rewrite url, we use our custom route
|
||||
|
||||
if($request->getUrl()->getPath() === $url) {
|
||||
if($request->getUrl()->contains($url)) {
|
||||
$request->setRewriteUrl($rule);
|
||||
}
|
||||
}
|
||||
@@ -1527,6 +1636,140 @@ $route->setPrefix('v1');
|
||||
$router->addRoute($route);
|
||||
```
|
||||
|
||||
## Custom class loader
|
||||
|
||||
You can easily extend simple-router to support custom injection frameworks like php-di by taking advantage of the ability to add your custom class-loader.
|
||||
|
||||
Class-loaders must inherit the `IClassLoader` interface.
|
||||
|
||||
**Example:**
|
||||
|
||||
```php
|
||||
class MyCustomClassLoader implements IClassLoader
|
||||
{
|
||||
/**
|
||||
* Load class
|
||||
*
|
||||
* @param string $class
|
||||
* @return object
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public function loadClass(string $class)
|
||||
{
|
||||
if (\class_exists($class) === false) {
|
||||
throw new NotFoundHttpException(sprintf('Class "%s" does not exist', $class), 404);
|
||||
}
|
||||
|
||||
return new $class();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when loading class method
|
||||
* @param object $class
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
* @return object
|
||||
*/
|
||||
public function loadClassMethod($class, string $method, array $parameters)
|
||||
{
|
||||
return call_user_func_array([$class, $method], array_values($parameters));
|
||||
}
|
||||
|
||||
/**
|
||||
* Load closure
|
||||
*
|
||||
* @param Callable $closure
|
||||
* @param array $parameters
|
||||
* @return mixed
|
||||
*/
|
||||
public function loadClosure(Callable $closure, array $parameters)
|
||||
{
|
||||
return \call_user_func_array($closure, array_values($parameters));
|
||||
}
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
Next, we need to configure our `routes.php` so the router uses our `MyCustomClassLoader` class for loading classes. This can be done by adding the following line to your `routes.php` file.
|
||||
|
||||
```php
|
||||
SimpleRouter::setCustomClassLoader(new MyCustomClassLoader());
|
||||
```
|
||||
|
||||
### Integrating with php-di
|
||||
|
||||
php-di support was discontinued by version 4.3, however you can easily add it again by creating your own class-loader like the example below:
|
||||
|
||||
```php
|
||||
use Pecee\SimpleRouter\Exceptions\ClassNotFoundHttpException;
|
||||
|
||||
class MyCustomClassLoader implements IClassLoader
|
||||
{
|
||||
|
||||
protected $container;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
// Create our new php-di container
|
||||
$this->container = (new \DI\ContainerBuilder())
|
||||
->useAutowiring(true)
|
||||
->build();
|
||||
}
|
||||
|
||||
/**
|
||||
* Load class
|
||||
*
|
||||
* @param string $class
|
||||
* @return object
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public function loadClass(string $class)
|
||||
{
|
||||
if (class_exists($class) === false) {
|
||||
throw new NotFoundHttpException(sprintf('Class "%s" does not exist', $class), 404);
|
||||
}
|
||||
|
||||
try {
|
||||
return $this->container->get($class);
|
||||
} catch (\Exception $e) {
|
||||
throw new NotFoundHttpException($e->getMessage(), (int)$e->getCode(), $e->getPrevious());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when loading class method
|
||||
* @param object $class
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
* @return object
|
||||
*/
|
||||
public function loadClassMethod($class, string $method, array $parameters)
|
||||
{
|
||||
try {
|
||||
return $this->container->call([$class, $method], $parameters);
|
||||
} catch (\Exception $e) {
|
||||
throw new NotFoundHttpException($e->getMessage(), (int)$e->getCode(), $e->getPrevious());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load closure
|
||||
*
|
||||
* @param Callable $closure
|
||||
* @param array $parameters
|
||||
* @return mixed
|
||||
*/
|
||||
public function loadClosure(callable $closure, array $parameters)
|
||||
{
|
||||
try {
|
||||
return $this->container->call($closure, $parameters);
|
||||
} catch (\Exception $e) {
|
||||
throw new NotFoundHttpException($e->getMessage(), (int)$e->getCode(), $e->getPrevious());
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## Parameters
|
||||
|
||||
This section contains advanced tips & tricks on extending the usage for parameters.
|
||||
@@ -1580,40 +1823,17 @@ You can read more about adding your own custom regular expression for matching p
|
||||
|
||||
### Multiple routes matches? Which one has the priority?
|
||||
|
||||
The router will match routes in the order they're added.
|
||||
The router will match routes in the order they're added and will render multiple routes, if they match.
|
||||
|
||||
It's possible to render multiple routes.
|
||||
|
||||
If you want the router to stop when a route is matched, you simply return a value in your callback or stop the execution manually (using `response()->json()` etc.).
|
||||
If you want the router to stop when a route is matched, you simply return a value in your callback or stop the execution manually (using `response()->json()` etc.) or simply by returning a result.
|
||||
|
||||
Any returned objects that implements the `__toString()` magic method will also prevent other routes from being rendered.
|
||||
|
||||
If you want the router only to execute one route per request, you can [disabling multiple route rendering](#disable-multiple-route-rendering).
|
||||
|
||||
### Using the router on sub-paths
|
||||
|
||||
Using the library on a sub-path like `localhost/project/` is not officially supported, however it is possible to get it working quite easily.
|
||||
|
||||
Add an event that appends your sub-path when a new loadable route is added.
|
||||
|
||||
**Example:**
|
||||
|
||||
```php
|
||||
// ... your routes.php file
|
||||
|
||||
if($isRunningLocally) {
|
||||
|
||||
$eventHandler = new EventHandler();
|
||||
$eventHandler->register(EventHandler::EVENT_ADD_ROUTE, function (EventArgument $arg) use (&$status) {
|
||||
|
||||
if ($arg->route instanceof \Pecee\SimpleRouter\Route\LoadableRoute) {
|
||||
$arg->route->prependUrl('/local-path');
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
TestRouter::addEventHandler($eventHandler);
|
||||
|
||||
}
|
||||
```
|
||||
Please refer to [Setting custom base path](#setting-custom-base-path) part of the documentation.
|
||||
|
||||
## Debugging
|
||||
|
||||
@@ -1853,4 +2073,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
SOFTWARE.
|
||||
+13
-4
@@ -28,15 +28,24 @@
|
||||
],
|
||||
"require": {
|
||||
"php": ">=7.1",
|
||||
"php-di/php-di": "^6.0"
|
||||
"ext-json": "*"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "^6.0",
|
||||
"mockery/mockery": "^1"
|
||||
"phpunit/phpunit": "^7",
|
||||
"mockery/mockery": "^1",
|
||||
"phpstan/phpstan": "^0",
|
||||
"phpstan/phpstan-phpunit": "^0",
|
||||
"phpstan/phpstan-deprecation-rules": "^0",
|
||||
"phpstan/phpstan-strict-rules": "^0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": [
|
||||
"phpunit tests"
|
||||
]
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"Pecee\\": "src/Pecee/"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -47,7 +47,7 @@ function request(): Request
|
||||
/**
|
||||
* Get input class
|
||||
* @param string|null $index Parameter index name
|
||||
* @param string|null $defaultValue Default return value
|
||||
* @param string|mixed|null $defaultValue Default return value
|
||||
* @param array ...$methods Default methods
|
||||
* @return \Pecee\Http\Input\InputHandler|array|string|null
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
parameters:
|
||||
level: 6
|
||||
paths:
|
||||
- src
|
||||
fileExtensions:
|
||||
- php
|
||||
bootstrapFiles:
|
||||
- ./vendor/autoload.php
|
||||
ignoreErrors:
|
||||
reportUnmatchedIgnoredErrors: true
|
||||
checkMissingIterableValueType: false
|
||||
checkGenericClassInNonGenericObjectType: false
|
||||
parallel:
|
||||
processTimeout: 300.0
|
||||
jobSize: 10
|
||||
maximumNumberOfProcesses: 4
|
||||
minimumNumberOfJobsPerProcess: 4
|
||||
includes:
|
||||
- vendor/phpstan/phpstan-strict-rules/rules.neon
|
||||
- vendor/phpstan/phpstan-phpunit/extension.neon
|
||||
- vendor/phpstan/phpstan-phpunit/rules.neon
|
||||
- vendor/phpstan/phpstan-deprecation-rules/rules.neon
|
||||
+3
-3
@@ -9,15 +9,15 @@
|
||||
convertNoticesToExceptions="true"
|
||||
convertWarningsToExceptions="true"
|
||||
processIsolation="false"
|
||||
stopOnFailure="false"
|
||||
syntaxCheck="false">
|
||||
stopOnFailure="false">
|
||||
<testsuites>
|
||||
<testsuite name="SimpleRouter Test Suite">
|
||||
<directory>tests/Pecee/SimpleRouter/</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<whitelist processUncoveredFilesFromWhitelist="true">
|
||||
<whitelist addUncoveredFilesFromWhitelist="true"
|
||||
processUncoveredFilesFromWhitelist="true">
|
||||
<directory suffix=".php">src</directory>
|
||||
</whitelist>
|
||||
</filter>
|
||||
|
||||
@@ -6,43 +6,43 @@ interface IResourceController
|
||||
{
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
* @return mixed
|
||||
*/
|
||||
public function index(): ?string;
|
||||
public function index();
|
||||
|
||||
/**
|
||||
* @param mixed $id
|
||||
* @return string|null
|
||||
* @return mixed
|
||||
*/
|
||||
public function show($id): ?string;
|
||||
public function show($id);
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
* @return mixed
|
||||
*/
|
||||
public function store(): ?string;
|
||||
public function store();
|
||||
|
||||
/**
|
||||
* @return string|null
|
||||
* @return mixed
|
||||
*/
|
||||
public function create(): ?string;
|
||||
public function create();
|
||||
|
||||
/**
|
||||
* View
|
||||
* @param mixed $id
|
||||
* @return string|null
|
||||
* @return mixed
|
||||
*/
|
||||
public function edit($id): ?string;
|
||||
public function edit($id);
|
||||
|
||||
/**
|
||||
* @param mixed $id
|
||||
* @return string|null
|
||||
* @return mixed
|
||||
*/
|
||||
public function update($id): ?string;
|
||||
public function update($id);
|
||||
|
||||
/**
|
||||
* @param mixed $id
|
||||
* @return string|null
|
||||
* @return mixed
|
||||
*/
|
||||
public function destroy($id): ?string;
|
||||
public function destroy($id);
|
||||
|
||||
}
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
namespace Pecee\Http\Exceptions;
|
||||
|
||||
class MalformedUrlException extends \Exception
|
||||
use Exception;
|
||||
|
||||
class MalformedUrlException extends Exception
|
||||
{
|
||||
|
||||
}
|
||||
@@ -13,9 +13,15 @@ interface IInputItem
|
||||
|
||||
public function setName(string $name): self;
|
||||
|
||||
public function getValue(): ?string;
|
||||
/**
|
||||
* @return mixed
|
||||
*/
|
||||
public function getValue();
|
||||
|
||||
public function setValue(string $value): self;
|
||||
/**
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function setValue($value): self;
|
||||
|
||||
public function __toString(): string;
|
||||
|
||||
|
||||
@@ -6,12 +6,39 @@ use Pecee\Exceptions\InvalidArgumentException;
|
||||
|
||||
class InputFile implements IInputItem
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $index;
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
public $name;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
public $filename;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
public $size;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
public $type;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
public $errors;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
public $tmpName;
|
||||
|
||||
public function __construct(string $index)
|
||||
@@ -165,7 +192,7 @@ class InputFile implements IInputItem
|
||||
* @param string $name
|
||||
* @return static
|
||||
*/
|
||||
public function setFilename($name): IInputItem
|
||||
public function setFilename(string $name): IInputItem
|
||||
{
|
||||
$this->filename = $name;
|
||||
|
||||
@@ -188,7 +215,7 @@ class InputFile implements IInputItem
|
||||
* @param string $destination
|
||||
* @return bool
|
||||
*/
|
||||
public function move($destination): bool
|
||||
public function move(string $destination): bool
|
||||
{
|
||||
return move_uploaded_file($this->tmpName, $destination);
|
||||
}
|
||||
@@ -216,20 +243,20 @@ class InputFile implements IInputItem
|
||||
/**
|
||||
* Get upload-error code.
|
||||
*
|
||||
* @return int
|
||||
* @return int|null
|
||||
*/
|
||||
public function getError(): int
|
||||
public function getError(): ?int
|
||||
{
|
||||
return (int)$this->errors;
|
||||
return $this->errors;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set error
|
||||
*
|
||||
* @param int $error
|
||||
* @param int|null $error
|
||||
* @return static
|
||||
*/
|
||||
public function setError($error): IInputItem
|
||||
public function setError(?int $error): IInputItem
|
||||
{
|
||||
$this->errors = (int)$error;
|
||||
|
||||
@@ -249,7 +276,7 @@ class InputFile implements IInputItem
|
||||
* @param string $name
|
||||
* @return static
|
||||
*/
|
||||
public function setTmpName($name): IInputItem
|
||||
public function setTmpName(string $name): IInputItem
|
||||
{
|
||||
$this->tmpName = $name;
|
||||
|
||||
@@ -261,16 +288,16 @@ class InputFile implements IInputItem
|
||||
return $this->getTmpName();
|
||||
}
|
||||
|
||||
public function getValue(): ?string
|
||||
public function getValue(): string
|
||||
{
|
||||
return $this->getFilename();
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $value
|
||||
* @param mixed $value
|
||||
* @return static
|
||||
*/
|
||||
public function setValue(string $value): IInputItem
|
||||
public function setValue($value): IInputItem
|
||||
{
|
||||
$this->filename = $value;
|
||||
|
||||
|
||||
@@ -27,6 +27,24 @@ class InputHandler
|
||||
*/
|
||||
protected $request;
|
||||
|
||||
/**
|
||||
* Original post variables
|
||||
* @var array
|
||||
*/
|
||||
protected $originalPost = [];
|
||||
|
||||
/**
|
||||
* Original get/params variables
|
||||
* @var array
|
||||
*/
|
||||
protected $originalParams = [];
|
||||
|
||||
/**
|
||||
* Get original file variables
|
||||
* @var array
|
||||
*/
|
||||
protected $originalFile = [];
|
||||
|
||||
/**
|
||||
* Input constructor.
|
||||
* @param Request $request
|
||||
@@ -45,39 +63,60 @@ class InputHandler
|
||||
public function parseInputs(): void
|
||||
{
|
||||
/* Parse get requests */
|
||||
if (\count($_GET) !== 0) {
|
||||
$this->get = $this->parseInputItem($_GET);
|
||||
if (count($_GET) !== 0) {
|
||||
$this->originalParams = $_GET;
|
||||
$this->get = $this->parseInputItem($this->originalParams);
|
||||
}
|
||||
|
||||
/* Parse post requests */
|
||||
$postVars = $_POST;
|
||||
$this->originalPost = $_POST;
|
||||
|
||||
if (\in_array($this->request->getMethod(), ['put', 'patch', 'delete'], false) === true) {
|
||||
parse_str(file_get_contents('php://input'), $postVars);
|
||||
if ($this->request->isPostBack() === true) {
|
||||
|
||||
$contents = file_get_contents('php://input');
|
||||
|
||||
// Append any PHP-input json
|
||||
if (strpos(trim($contents), '{') === 0) {
|
||||
$post = json_decode($contents, true);
|
||||
|
||||
if ($post !== false) {
|
||||
$this->originalPost += $post;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (\count($postVars) !== 0) {
|
||||
$this->post = $this->parseInputItem($postVars);
|
||||
if (count($this->originalPost) !== 0) {
|
||||
$this->post = $this->parseInputItem($this->originalPost);
|
||||
}
|
||||
|
||||
/* Parse get requests */
|
||||
if (\count($_FILES) !== 0) {
|
||||
$this->file = $this->parseFiles();
|
||||
if (count($_FILES) !== 0) {
|
||||
$this->originalFile = $_FILES;
|
||||
$this->file = $this->parseFiles($this->originalFile);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $files Array with files to parse
|
||||
* @param string|null $parentKey Key from parent (used when parsing nested array).
|
||||
* @return array
|
||||
*/
|
||||
public function parseFiles(): array
|
||||
public function parseFiles(array $files, ?string $parentKey = null): array
|
||||
{
|
||||
$list = [];
|
||||
|
||||
foreach ((array)$_FILES as $key => $value) {
|
||||
foreach ($files as $key => $value) {
|
||||
|
||||
// Parse multi dept file array
|
||||
if(isset($value['name']) === false && is_array($value) === true) {
|
||||
$list[$key] = $this->parseFiles($value, $key);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Handle array input
|
||||
if (\is_array($value['name']) === false) {
|
||||
$values['index'] = $key;
|
||||
if (is_array($value['name']) === false) {
|
||||
$values = ['index' => $parentKey ?? $key];
|
||||
|
||||
try {
|
||||
$list[$key] = InputFile::createFromArray($values + $value);
|
||||
} catch (InvalidArgumentException $e) {
|
||||
@@ -108,7 +147,7 @@ class InputHandler
|
||||
* @param array|null $original
|
||||
* @return array
|
||||
*/
|
||||
protected function rearrangeFile(array $values, &$index, $original): array
|
||||
protected function rearrangeFile(array $values, array &$index, ?array $original): array
|
||||
{
|
||||
$originalIndex = $index[0];
|
||||
array_shift($index);
|
||||
@@ -117,12 +156,12 @@ class InputHandler
|
||||
|
||||
foreach ($values as $key => $value) {
|
||||
|
||||
if (\is_array($original['name'][$key]) === false) {
|
||||
if (is_array($original['name'][$key]) === false) {
|
||||
|
||||
try {
|
||||
|
||||
$file = InputFile::createFromArray([
|
||||
'index' => (empty($key) === true && empty($originalIndex) === false) ? $originalIndex : $key,
|
||||
'index' => ($key === '' && $originalIndex !== '') ? $originalIndex : $key,
|
||||
'name' => $original['name'][$key],
|
||||
'error' => $original['error'][$key],
|
||||
'tmp_name' => $original['tmp_name'][$key],
|
||||
@@ -171,14 +210,11 @@ class InputHandler
|
||||
foreach ($array as $key => $value) {
|
||||
|
||||
// Handle array input
|
||||
if (\is_array($value) === false) {
|
||||
$list[$key] = new InputItem($key, $value);
|
||||
continue;
|
||||
if (is_array($value) === true) {
|
||||
$value = $this->parseInputItem($value);
|
||||
}
|
||||
|
||||
$output = $this->parseInputItem($value);
|
||||
|
||||
$list[$key] = $output;
|
||||
$list[$key] = new InputItem($key, $value);
|
||||
}
|
||||
|
||||
return $list;
|
||||
@@ -195,57 +231,88 @@ class InputHandler
|
||||
{
|
||||
$element = null;
|
||||
|
||||
if (\count($methods) === 0 || \in_array('get', $methods, true) === true) {
|
||||
if(count($methods) > 0) {
|
||||
$methods = is_array(...$methods) ? array_values(...$methods) : $methods;
|
||||
}
|
||||
|
||||
if (count($methods) === 0 || in_array(Request::REQUEST_TYPE_GET, $methods, true) === true) {
|
||||
$element = $this->get($index);
|
||||
}
|
||||
|
||||
if (($element === null && \count($methods) === 0) || (\count($methods) !== 0 && \in_array('post', $methods, true) === true)) {
|
||||
if (($element === null && count($methods) === 0) || (count($methods) !== 0 && in_array(Request::REQUEST_TYPE_POST, $methods, true) === true)) {
|
||||
$element = $this->post($index);
|
||||
}
|
||||
|
||||
if (($element === null && \count($methods) === 0) || (\count($methods) !== 0 && \in_array('file', $methods, true) === true)) {
|
||||
if (($element === null && count($methods) === 0) || (count($methods) !== 0 && in_array('file', $methods, true) === true)) {
|
||||
$element = $this->file($index);
|
||||
}
|
||||
|
||||
return $element;
|
||||
}
|
||||
|
||||
protected function getValueFromArray(array $array): array
|
||||
{
|
||||
$output = [];
|
||||
/* @var $item InputItem */
|
||||
foreach ($array as $key => $item) {
|
||||
|
||||
if ($item instanceof IInputItem) {
|
||||
$item = $item->getValue();
|
||||
}
|
||||
|
||||
$output[$key] = is_array($item) ? $this->getValueFromArray($item) : $item;
|
||||
}
|
||||
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get input element value matching index
|
||||
*
|
||||
* @param string $index
|
||||
* @param string|null $defaultValue
|
||||
* @param string|mixed|null $defaultValue
|
||||
* @param array ...$methods
|
||||
* @return string|array
|
||||
*/
|
||||
public function value(string $index, ?string $defaultValue = null, ...$methods)
|
||||
public function value(string $index, $defaultValue = null, ...$methods)
|
||||
{
|
||||
$input = $this->find($index, ...$methods);
|
||||
|
||||
$output = [];
|
||||
|
||||
/* Handle collection */
|
||||
if (\is_array($input) === true) {
|
||||
/* @var $item InputItem */
|
||||
foreach ($input as $item) {
|
||||
$output[] = $item->getValue();
|
||||
}
|
||||
|
||||
return (\count($output) === 0) ? $defaultValue : $output;
|
||||
if ($input instanceof IInputItem) {
|
||||
$input = $input->getValue();
|
||||
}
|
||||
|
||||
return ($input === null || ($input !== null && trim($input->getValue()) === '')) ? $defaultValue : $input->getValue();
|
||||
/* Handle collection */
|
||||
if (is_array($input) === true) {
|
||||
$output = $this->getValueFromArray($input);
|
||||
|
||||
return (count($output) === 0) ? $defaultValue : $output;
|
||||
}
|
||||
|
||||
return ($input === null || (is_string($input) && trim($input) === '')) ? $defaultValue : $input;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a input-item exist
|
||||
* Check if a input-item exist.
|
||||
* If an array is as $index parameter the method returns true if all elements exist.
|
||||
*
|
||||
* @param string $index
|
||||
* @param string|array $index
|
||||
* @param array ...$methods
|
||||
* @return bool
|
||||
*/
|
||||
public function exists(string $index, ...$methods): bool
|
||||
public function exists($index, ...$methods): bool
|
||||
{
|
||||
// Check array
|
||||
if(is_array($index) === true) {
|
||||
foreach($index as $key) {
|
||||
if($this->value($key, null, ...$methods) === null) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return $this->value($index, null, ...$methods) !== null;
|
||||
}
|
||||
|
||||
@@ -253,10 +320,10 @@ class InputHandler
|
||||
* Find post-value by index or return default value.
|
||||
*
|
||||
* @param string $index
|
||||
* @param string|null $defaultValue
|
||||
* @param mixed|null $defaultValue
|
||||
* @return InputItem|array|string|null
|
||||
*/
|
||||
public function post(string $index, ?string $defaultValue = null)
|
||||
public function post(string $index, $defaultValue = null)
|
||||
{
|
||||
return $this->post[$index] ?? $defaultValue;
|
||||
}
|
||||
@@ -265,10 +332,10 @@ class InputHandler
|
||||
* Find file by index or return default value.
|
||||
*
|
||||
* @param string $index
|
||||
* @param string|null $defaultValue
|
||||
* @param mixed|null $defaultValue
|
||||
* @return InputFile|array|string|null
|
||||
*/
|
||||
public function file(string $index, ?string $defaultValue = null)
|
||||
public function file(string $index, $defaultValue = null)
|
||||
{
|
||||
return $this->file[$index] ?? $defaultValue;
|
||||
}
|
||||
@@ -277,10 +344,10 @@ class InputHandler
|
||||
* Find parameter/query-string by index or return default value.
|
||||
*
|
||||
* @param string $index
|
||||
* @param string|null $defaultValue
|
||||
* @param mixed|null $defaultValue
|
||||
* @return InputItem|array|string|null
|
||||
*/
|
||||
public function get(string $index, ?string $defaultValue = null)
|
||||
public function get(string $index, $defaultValue = null)
|
||||
{
|
||||
return $this->get[$index] ?? $defaultValue;
|
||||
}
|
||||
@@ -290,30 +357,114 @@ class InputHandler
|
||||
* @param array $filter Only take items in filter
|
||||
* @return array
|
||||
*/
|
||||
public function all(array $filter): array
|
||||
public function all(array $filter = []): array
|
||||
{
|
||||
$output = $_GET;
|
||||
$output = $this->originalParams + $this->originalPost + $this->originalFile;
|
||||
$output = (count($filter) > 0) ? array_intersect_key($output, array_flip($filter)) : $output;
|
||||
|
||||
if ($this->request->getMethod() === 'post') {
|
||||
|
||||
// Append POST data
|
||||
$output += $_POST;
|
||||
|
||||
if (\in_array($this->request->getMethod(), ['put', 'patch', 'delete'], false) === true) {
|
||||
|
||||
$contents = file_get_contents('php://input');
|
||||
|
||||
// Append any PHP-input json
|
||||
if (strpos(trim($contents), '{') === 0) {
|
||||
$post = json_decode($contents, true);
|
||||
if ($post !== false) {
|
||||
$output += $post;
|
||||
}
|
||||
}
|
||||
foreach ($filter as $filterKey) {
|
||||
if (array_key_exists($filterKey, $output) === false) {
|
||||
$output[$filterKey] = null;
|
||||
}
|
||||
}
|
||||
|
||||
return ($filter !== null) ? array_intersect_key($output, array_flip($filter)) : $output;
|
||||
return $output;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add GET parameter
|
||||
*
|
||||
* @param string $key
|
||||
* @param InputItem $item
|
||||
*/
|
||||
public function addGet(string $key, InputItem $item): void
|
||||
{
|
||||
$this->get[$key] = $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add POST parameter
|
||||
*
|
||||
* @param string $key
|
||||
* @param InputItem $item
|
||||
*/
|
||||
public function addPost(string $key, InputItem $item): void
|
||||
{
|
||||
$this->post[$key] = $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add FILE parameter
|
||||
*
|
||||
* @param string $key
|
||||
* @param InputFile $item
|
||||
*/
|
||||
public function addFile(string $key, InputFile $item): void
|
||||
{
|
||||
$this->file[$key] = $item;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get original post variables
|
||||
* @return array
|
||||
*/
|
||||
public function getOriginalPost(): array
|
||||
{
|
||||
return $this->originalPost;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set original post variables
|
||||
* @param array $post
|
||||
* @return static $this
|
||||
*/
|
||||
public function setOriginalPost(array $post): self
|
||||
{
|
||||
$this->originalPost = $post;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get original get variables
|
||||
* @return array
|
||||
*/
|
||||
public function getOriginalParams(): array
|
||||
{
|
||||
return $this->originalParams;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set original get-variables
|
||||
* @param array $params
|
||||
* @return static $this
|
||||
*/
|
||||
public function setOriginalParams(array $params): self
|
||||
{
|
||||
$this->originalParams = $params;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get original file variables
|
||||
* @return array
|
||||
*/
|
||||
public function getOriginalFile(): array
|
||||
{
|
||||
return $this->originalFile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set original file posts variables
|
||||
* @param array $file
|
||||
* @return static $this
|
||||
*/
|
||||
public function setOriginalFile(array $file): self
|
||||
{
|
||||
$this->originalFile = $file;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,13 +2,17 @@
|
||||
|
||||
namespace Pecee\Http\Input;
|
||||
|
||||
class InputItem implements IInputItem
|
||||
use ArrayAccess;
|
||||
use ArrayIterator;
|
||||
use IteratorAggregate;
|
||||
|
||||
class InputItem implements ArrayAccess, IInputItem, IteratorAggregate
|
||||
{
|
||||
public $index;
|
||||
public $name;
|
||||
public $value;
|
||||
|
||||
public function __construct(string $index, ?string $value = null)
|
||||
public function __construct(string $index, $value = null)
|
||||
{
|
||||
$this->index = $index;
|
||||
$this->value = $value;
|
||||
@@ -53,28 +57,58 @@ class InputItem implements IInputItem
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
* @return mixed
|
||||
*/
|
||||
public function getValue(): ?string
|
||||
public function getValue()
|
||||
{
|
||||
return $this->value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set input value
|
||||
* @param string $value
|
||||
* @param mixed $value
|
||||
* @return static
|
||||
*/
|
||||
public function setValue(string $value): IInputItem
|
||||
public function setValue($value): IInputItem
|
||||
{
|
||||
$this->value = $value;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
public function offsetExists($offset): bool
|
||||
{
|
||||
return (string)$this->value;
|
||||
return isset($this->value[$offset]);
|
||||
}
|
||||
|
||||
public function offsetGet($offset)
|
||||
{
|
||||
if ($this->offsetExists($offset) === true) {
|
||||
return $this->value[$offset];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function offsetSet($offset, $value): void
|
||||
{
|
||||
$this->value[$offset] = $value;
|
||||
}
|
||||
|
||||
public function offsetUnset($offset): void
|
||||
{
|
||||
unset($this->value[$offset]);
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
$value = $this->getValue();
|
||||
|
||||
return (is_array($value) === true) ? json_encode($value) : $value;
|
||||
}
|
||||
|
||||
public function getIterator(): ArrayIterator
|
||||
{
|
||||
return new ArrayIterator($this->getValue());
|
||||
}
|
||||
}
|
||||
@@ -9,15 +9,29 @@ use Pecee\Http\Security\ITokenProvider;
|
||||
|
||||
class BaseCsrfVerifier implements IMiddleware
|
||||
{
|
||||
public const POST_KEY = 'csrf-token';
|
||||
public const POST_KEY = 'csrf_token';
|
||||
public const HEADER_KEY = 'X-CSRF-TOKEN';
|
||||
|
||||
/**
|
||||
* Urls to ignore. You can use * to exclude all sub-urls on a given path.
|
||||
* For example: /admin/*
|
||||
* @var array|null
|
||||
*/
|
||||
protected $except;
|
||||
|
||||
/**
|
||||
* Urls to include. Can be used to include urls from a certain path.
|
||||
* @var array|null
|
||||
*/
|
||||
protected $include;
|
||||
|
||||
/**
|
||||
* @var ITokenProvider
|
||||
*/
|
||||
protected $tokenProvider;
|
||||
|
||||
/**
|
||||
* BaseCsrfVerifier constructor.
|
||||
* @throws \Pecee\Http\Security\Exceptions\SecurityException
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
@@ -31,24 +45,38 @@ class BaseCsrfVerifier implements IMiddleware
|
||||
*/
|
||||
protected function skip(Request $request): bool
|
||||
{
|
||||
if ($this->except === null || \count($this->except) === 0) {
|
||||
if ($this->except === null || count($this->except) === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$max = \count($this->except) - 1;
|
||||
|
||||
for ($i = $max; $i >= 0; $i--) {
|
||||
$url = $this->except[$i];
|
||||
|
||||
foreach($this->except as $url) {
|
||||
$url = rtrim($url, '/');
|
||||
if ($url[\strlen($url) - 1] === '*') {
|
||||
if ($url[strlen($url) - 1] === '*') {
|
||||
$url = rtrim($url, '*');
|
||||
$skip = $request->getUrl()->contains($url);
|
||||
} else {
|
||||
$skip = ($url === $request->getUrl()->getOriginalUrl());
|
||||
$skip = ($url === rtrim($request->getUrl()->getRelativeUrl(false), '/'));
|
||||
}
|
||||
|
||||
if ($skip === true) {
|
||||
|
||||
if(is_array($this->include) === true && count($this->include) > 0) {
|
||||
foreach($this->include as $includeUrl) {
|
||||
$includeUrl = rtrim($includeUrl, '/');
|
||||
if ($includeUrl[strlen($includeUrl) - 1] === '*') {
|
||||
$includeUrl = rtrim($includeUrl, '*');
|
||||
$skip = !$request->getUrl()->contains($includeUrl);
|
||||
break;
|
||||
}
|
||||
|
||||
$skip = !($includeUrl === rtrim($request->getUrl()->getRelativeUrl(false), '/'));
|
||||
}
|
||||
}
|
||||
|
||||
if($skip === false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -64,13 +92,12 @@ class BaseCsrfVerifier implements IMiddleware
|
||||
*/
|
||||
public function handle(Request $request): void
|
||||
{
|
||||
|
||||
if ($this->skip($request) === false && \in_array($request->getMethod(), ['post', 'put', 'delete'], true) === true) {
|
||||
if ($this->skip($request) === false && $request->isPostBack() === true) {
|
||||
|
||||
$token = $request->getInputHandler()->value(
|
||||
static::POST_KEY,
|
||||
$request->getHeader(static::HEADER_KEY),
|
||||
'post'
|
||||
Request::$requestTypesPost
|
||||
);
|
||||
|
||||
if ($this->tokenProvider->validate((string)$token) === false) {
|
||||
@@ -81,7 +108,6 @@ class BaseCsrfVerifier implements IMiddleware
|
||||
|
||||
// Refresh existing token
|
||||
$this->tokenProvider->refresh();
|
||||
|
||||
}
|
||||
|
||||
public function getTokenProvider(): ITokenProvider
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
namespace Pecee\Http\Middleware\Exceptions;
|
||||
|
||||
class TokenMismatchException extends \Exception
|
||||
use Exception;
|
||||
|
||||
class TokenMismatchException extends Exception
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace Pecee\Http\Middleware;
|
||||
|
||||
use Pecee\Http\Request;
|
||||
use Pecee\SimpleRouter\Exceptions\HttpException;
|
||||
|
||||
abstract class IpRestrictAccess implements IMiddleware
|
||||
{
|
||||
protected $ipBlacklist = [];
|
||||
protected $ipWhitelist = [];
|
||||
|
||||
protected function validate(string $ip): bool
|
||||
{
|
||||
// Accept ip that is in white-list
|
||||
if(in_array($ip, $this->ipWhitelist, true) === true) {
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach ($this->ipBlacklist as $blackIp) {
|
||||
|
||||
// Blocks range (8.8.*)
|
||||
if ($blackIp[strlen($blackIp) - 1] === '*' && strpos($ip, trim($blackIp, '*')) === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Blocks exact match
|
||||
if ($blackIp === $ip) {
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @throws HttpException
|
||||
*/
|
||||
public function handle(Request $request): void
|
||||
{
|
||||
if($this->validate((string)$request->getIp()) === false) {
|
||||
throw new HttpException(sprintf('Restricted ip. Access to %s has been blocked', $request->getIp()), 403);
|
||||
}
|
||||
}
|
||||
}
|
||||
+151
-23
@@ -4,12 +4,52 @@ namespace Pecee\Http;
|
||||
|
||||
use Pecee\Http\Exceptions\MalformedUrlException;
|
||||
use Pecee\Http\Input\InputHandler;
|
||||
use Pecee\Http\Middleware\BaseCsrfVerifier;
|
||||
use Pecee\SimpleRouter\Route\ILoadableRoute;
|
||||
use Pecee\SimpleRouter\Route\RouteUrl;
|
||||
use Pecee\SimpleRouter\SimpleRouter;
|
||||
|
||||
class Request
|
||||
{
|
||||
public const REQUEST_TYPE_GET = 'get';
|
||||
public const REQUEST_TYPE_POST = 'post';
|
||||
public const REQUEST_TYPE_PUT = 'put';
|
||||
public const REQUEST_TYPE_PATCH = 'patch';
|
||||
public const REQUEST_TYPE_OPTIONS = 'options';
|
||||
public const REQUEST_TYPE_DELETE = 'delete';
|
||||
public const REQUEST_TYPE_HEAD = 'head';
|
||||
|
||||
public const CONTENT_TYPE_JSON = 'application/json';
|
||||
public const CONTENT_TYPE_FORM_DATA = 'multipart/form-data';
|
||||
public const CONTENT_TYPE_X_FORM_ENCODED = 'application/x-www-form-urlencoded';
|
||||
|
||||
public const FORCE_METHOD_KEY = '_method';
|
||||
|
||||
/**
|
||||
* All request-types
|
||||
* @var string[]
|
||||
*/
|
||||
public static $requestTypes = [
|
||||
self::REQUEST_TYPE_GET,
|
||||
self::REQUEST_TYPE_POST,
|
||||
self::REQUEST_TYPE_PUT,
|
||||
self::REQUEST_TYPE_PATCH,
|
||||
self::REQUEST_TYPE_OPTIONS,
|
||||
self::REQUEST_TYPE_DELETE,
|
||||
self::REQUEST_TYPE_HEAD,
|
||||
];
|
||||
|
||||
/**
|
||||
* Post request-types.
|
||||
* @var string[]
|
||||
*/
|
||||
public static $requestTypesPost = [
|
||||
self::REQUEST_TYPE_POST,
|
||||
self::REQUEST_TYPE_PUT,
|
||||
self::REQUEST_TYPE_PATCH,
|
||||
self::REQUEST_TYPE_DELETE,
|
||||
];
|
||||
|
||||
/**
|
||||
* Additional data
|
||||
*
|
||||
@@ -23,6 +63,12 @@ class Request
|
||||
*/
|
||||
protected $headers = [];
|
||||
|
||||
/**
|
||||
* Request ContentType
|
||||
* @var string
|
||||
*/
|
||||
protected $contentType;
|
||||
|
||||
/**
|
||||
* Request host
|
||||
* @var string
|
||||
@@ -77,21 +123,21 @@ class Request
|
||||
{
|
||||
foreach ($_SERVER as $key => $value) {
|
||||
$this->headers[strtolower($key)] = $value;
|
||||
$this->headers[strtolower(str_replace('_', '-', $key))] = $value;
|
||||
$this->headers[str_replace('_', '-', strtolower($key))] = $value;
|
||||
}
|
||||
|
||||
$this->setHost($this->getHeader('http-host'));
|
||||
|
||||
// Check if special IIS header exist, otherwise use default.
|
||||
$this->setUrl(new Url($this->getHeader('unencoded-url', $this->getHeader('request-uri'))));
|
||||
|
||||
$this->setUrl(new Url($this->getFirstHeader(['unencoded-url', 'request-uri'])));
|
||||
$this->setContentType((string)$this->getHeader('content-type'));
|
||||
$this->setMethod((string)($_POST[static::FORCE_METHOD_KEY] ?? $this->getHeader('request-method')));
|
||||
$this->inputHandler = new InputHandler($this);
|
||||
$this->method = strtolower($this->inputHandler->value('_method', $this->getHeader('request-method')));
|
||||
}
|
||||
|
||||
public function isSecure(): bool
|
||||
{
|
||||
return $this->getHeader('http-x-forwarded-proto') === 'https' || $this->getHeader('https') !== null || $this->getHeader('server-port') === 443;
|
||||
return $this->getHeader('http-x-forwarded-proto') === 'https' || $this->getHeader('https') !== null || (int)$this->getHeader('server-port') === 443;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -146,6 +192,15 @@ class Request
|
||||
return $this->getHeader('php-auth-pw');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the csrf token
|
||||
* @return string|null
|
||||
*/
|
||||
public function getCsrfToken(): ?string
|
||||
{
|
||||
return $this->getHeader(BaseCsrfVerifier::HEADER_KEY);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all headers
|
||||
* @return array
|
||||
@@ -157,19 +212,23 @@ class Request
|
||||
|
||||
/**
|
||||
* Get id address
|
||||
* If $safe is false, this function will detect Proxys. But the user can edit this header to whatever he wants!
|
||||
* https://stackoverflow.com/questions/3003145/how-to-get-the-client-ip-address-in-php#comment-25086804
|
||||
* @param bool $safeMode When enabled, only safe non-spoofable headers will be returned. Note this can cause issues when using proxy.
|
||||
* @return string|null
|
||||
*/
|
||||
public function getIp(): ?string
|
||||
public function getIp(bool $safeMode = false): ?string
|
||||
{
|
||||
if ($this->getHeader('http-cf-connecting-ip') !== null) {
|
||||
return $this->getHeader('http-cf-connecting-ip');
|
||||
$headers = ['remote-addr'];
|
||||
if($safeMode === false) {
|
||||
$headers = array_merge($headers, [
|
||||
'http-cf-connecting-ip',
|
||||
'http-client-ip',
|
||||
'http-x-forwarded-for',
|
||||
]);
|
||||
}
|
||||
|
||||
if ($this->getHeader('http-x-forwarded-for') !== null) {
|
||||
return $this->getHeader('http-x-forwarded_for');
|
||||
}
|
||||
|
||||
return $this->getHeader('remote-addr');
|
||||
return $this->getFirstHeader($headers);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -204,14 +263,72 @@ class Request
|
||||
/**
|
||||
* Get header value by name
|
||||
*
|
||||
* @param string $name
|
||||
* @param string|null $defaultValue
|
||||
* @param string $name Name of the header.
|
||||
* @param string|mixed|null $defaultValue Value to be returned if header is not found.
|
||||
* @param bool $tryParse When enabled the method will try to find the header from both from client (http) and server-side variants, if the header is not found.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getHeader($name, $defaultValue = null): ?string
|
||||
public function getHeader(string $name, $defaultValue = null, bool $tryParse = true): ?string
|
||||
{
|
||||
return $this->headers[strtolower($name)] ?? $defaultValue;
|
||||
$name = strtolower($name);
|
||||
$header = $this->headers[$name] ?? null;
|
||||
|
||||
if ($tryParse === true && $header === null) {
|
||||
if (strpos($name, 'http-') === 0) {
|
||||
// Trying to find client header variant which was not found, searching for header variant without http- prefix.
|
||||
$header = $this->headers[str_replace('http-', '', $name)] ?? null;
|
||||
} else {
|
||||
// Trying to find server variant which was not found, searching for client variant with http- prefix.
|
||||
$header = $this->headers['http-' . $name] ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
return $header ?? $defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Will try to find first header from list of headers.
|
||||
*
|
||||
* @param array $headers
|
||||
* @param mixed|null $defaultValue
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function getFirstHeader(array $headers, $defaultValue = null)
|
||||
{
|
||||
foreach($headers as $header) {
|
||||
$header = $this->getHeader($header);
|
||||
if($header !== null) {
|
||||
return $header;
|
||||
}
|
||||
}
|
||||
|
||||
return $defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get request content-type
|
||||
* @return string|null
|
||||
*/
|
||||
public function getContentType(): ?string
|
||||
{
|
||||
return $this->contentType;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set request content-type
|
||||
* @param string $contentType
|
||||
* @return $this
|
||||
*/
|
||||
protected function setContentType(string $contentType): self
|
||||
{
|
||||
if(strpos($contentType, ';') > 0) {
|
||||
$this->contentType = strtolower(substr($contentType, 0, strpos($contentType, ';')));
|
||||
} else {
|
||||
$this->contentType = strtolower($contentType);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -230,7 +347,7 @@ class Request
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isFormatAccepted($format): bool
|
||||
public function isFormatAccepted(string $format): bool
|
||||
{
|
||||
return ($this->getHeader('http-accept') !== null && stripos($this->getHeader('http-accept'), $format) !== false);
|
||||
}
|
||||
@@ -245,6 +362,16 @@ class Request
|
||||
return (strtolower($this->getHeader('http-x-requested-with')) === 'xmlhttprequest');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true when request-method is type that could contain data in the page body.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isPostBack(): bool
|
||||
{
|
||||
return in_array($this->getMethod(), static::$requestTypesPost, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get accept formats
|
||||
* @return array
|
||||
@@ -264,6 +391,10 @@ class Request
|
||||
if ($this->url->getHost() === null) {
|
||||
$this->url->setHost((string)$this->getHost());
|
||||
}
|
||||
|
||||
if($this->isSecure() === true) {
|
||||
$this->url->setScheme('https');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -348,7 +479,7 @@ class Request
|
||||
*/
|
||||
public function getLoadedRoute(): ?ILoadableRoute
|
||||
{
|
||||
return (\count($this->loadedRoutes) > 0) ? end($this->loadedRoutes) : null;
|
||||
return (count($this->loadedRoutes) > 0) ? end($this->loadedRoutes) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -370,7 +501,6 @@ class Request
|
||||
public function setLoadedRoutes(array $routes): self
|
||||
{
|
||||
$this->loadedRoutes = $routes;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -383,7 +513,6 @@ class Request
|
||||
public function addLoadedRoute(ILoadableRoute $route): self
|
||||
{
|
||||
$this->loadedRoutes[] = $route;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
@@ -406,11 +535,10 @@ class Request
|
||||
public function setHasPendingRewrite(bool $boolean): self
|
||||
{
|
||||
$this->hasPendingRewrite = $boolean;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function __isset($name)
|
||||
public function __isset($name): bool
|
||||
{
|
||||
return array_key_exists($name, $this->data) === true;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Pecee\Http;
|
||||
|
||||
use JsonSerializable;
|
||||
use Pecee\Exceptions\InvalidArgumentException;
|
||||
|
||||
class Response
|
||||
@@ -30,7 +31,7 @@ class Response
|
||||
* Redirect the response
|
||||
*
|
||||
* @param string $url
|
||||
* @param int $httpCode
|
||||
* @param ?int $httpCode
|
||||
*/
|
||||
public function redirect(string $url, ?int $httpCode = null): void
|
||||
{
|
||||
@@ -85,14 +86,14 @@ class Response
|
||||
|
||||
/**
|
||||
* Json encode
|
||||
* @param array|\JsonSerializable $value
|
||||
* @param int $options JSON options Bitmask consisting of JSON_HEX_QUOT, JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_NUMERIC_CHECK, JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES, JSON_FORCE_OBJECT, JSON_PRESERVE_ZERO_FRACTION, JSON_UNESCAPED_UNICODE, JSON_PARTIAL_OUTPUT_ON_ERROR.
|
||||
* @param array|JsonSerializable $value
|
||||
* @param ?int $options JSON options Bitmask consisting of JSON_HEX_QUOT, JSON_HEX_TAG, JSON_HEX_AMP, JSON_HEX_APOS, JSON_NUMERIC_CHECK, JSON_PRETTY_PRINT, JSON_UNESCAPED_SLASHES, JSON_FORCE_OBJECT, JSON_PRESERVE_ZERO_FRACTION, JSON_UNESCAPED_UNICODE, JSON_PARTIAL_OUTPUT_ON_ERROR.
|
||||
* @param int $dept JSON debt.
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function json($value, ?int $options = null, int $dept = 512): void
|
||||
{
|
||||
if (($value instanceof \JsonSerializable) === false && \is_array($value) === false) {
|
||||
if (($value instanceof JsonSerializable) === false && is_array($value) === false) {
|
||||
throw new InvalidArgumentException('Invalid type for parameter "value". Must be of type array or object implementing the \JsonSerializable interface.');
|
||||
}
|
||||
|
||||
|
||||
@@ -2,13 +2,21 @@
|
||||
|
||||
namespace Pecee\Http\Security;
|
||||
|
||||
use Exception;
|
||||
use Pecee\Http\Security\Exceptions\SecurityException;
|
||||
|
||||
class CookieTokenProvider implements ITokenProvider
|
||||
{
|
||||
public const CSRF_KEY = 'CSRF-TOKEN';
|
||||
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $token;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
protected $cookieTimeoutMinutes = 120;
|
||||
|
||||
/**
|
||||
@@ -17,7 +25,7 @@ class CookieTokenProvider implements ITokenProvider
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->token = $this->getToken();
|
||||
$this->token = ($this->hasToken() === true) ? $_COOKIE[static::CSRF_KEY] : null;
|
||||
|
||||
if ($this->token === null) {
|
||||
$this->token = $this->generateToken();
|
||||
@@ -34,7 +42,7 @@ class CookieTokenProvider implements ITokenProvider
|
||||
{
|
||||
try {
|
||||
return bin2hex(random_bytes(32));
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
throw new SecurityException($e->getMessage(), (int)$e->getCode(), $e->getPrevious());
|
||||
}
|
||||
}
|
||||
@@ -63,7 +71,7 @@ class CookieTokenProvider implements ITokenProvider
|
||||
public function setToken(string $token): void
|
||||
{
|
||||
$this->token = $token;
|
||||
setcookie(static::CSRF_KEY, $token, (int)((time() + 60) * $this->cookieTimeoutMinutes), '/', ini_get('session.cookie_domain'), ini_get('session.cookie_secure'), ini_get('session.cookie_httponly'));
|
||||
setcookie(static::CSRF_KEY, $token, time() + (60 * $this->cookieTimeoutMinutes), '/', ini_get('session.cookie_domain'), ini_get('session.cookie_secure'), ini_get('session.cookie_httponly'));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -73,8 +81,6 @@ class CookieTokenProvider implements ITokenProvider
|
||||
*/
|
||||
public function getToken(?string $defaultValue = null): ?string
|
||||
{
|
||||
$this->token = ($this->hasToken() === true) ? $_COOKIE[static::CSRF_KEY] : null;
|
||||
|
||||
return $this->token ?? $defaultValue;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
namespace Pecee\Http\Security\Exceptions;
|
||||
|
||||
class SecurityException extends \Exception
|
||||
use Exception;
|
||||
|
||||
class SecurityException extends Exception
|
||||
{
|
||||
|
||||
}
|
||||
+57
-16
@@ -2,25 +2,60 @@
|
||||
|
||||
namespace Pecee\Http;
|
||||
|
||||
use JsonSerializable;
|
||||
use Pecee\Http\Exceptions\MalformedUrlException;
|
||||
|
||||
class Url implements \JsonSerializable
|
||||
class Url implements JsonSerializable
|
||||
{
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $originalUrl;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $scheme;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $host;
|
||||
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
private $port;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $username;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $password;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $path;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $params = [];
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
private $fragment;
|
||||
|
||||
/**
|
||||
* Url constructor.
|
||||
*
|
||||
* @param string $url
|
||||
* @param ?string $url
|
||||
* @throws MalformedUrlException
|
||||
*/
|
||||
public function __construct(?string $url)
|
||||
@@ -247,8 +282,9 @@ class Url implements \JsonSerializable
|
||||
public function setQueryString(string $queryString): self
|
||||
{
|
||||
$params = [];
|
||||
parse_str($queryString, $params);
|
||||
|
||||
if(parse_str($queryString, $params) !== false) {
|
||||
if(count($params) > 0) {
|
||||
return $this->setParams($params);
|
||||
}
|
||||
|
||||
@@ -340,7 +376,7 @@ class Url implements \JsonSerializable
|
||||
*/
|
||||
public function removeParams(...$names): self
|
||||
{
|
||||
$params = array_diff_key($this->getParams(), array_flip($names));
|
||||
$params = array_diff_key($this->getParams(), array_flip(...$names));
|
||||
$this->setParams($params);
|
||||
|
||||
return $this;
|
||||
@@ -371,7 +407,7 @@ class Url implements \JsonSerializable
|
||||
*/
|
||||
public function getParam(string $name, ?string $defaultValue = null): ?string
|
||||
{
|
||||
return isset($this->getParams()[$name]) ?? $defaultValue;
|
||||
return (isset($this->getParams()[$name]) === true) ? $this->getParams()[$name] : $defaultValue;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -385,7 +421,7 @@ class Url implements \JsonSerializable
|
||||
{
|
||||
$encodedUrl = preg_replace_callback(
|
||||
'/[^:\/@?&=#]+/u',
|
||||
function ($matches) {
|
||||
static function ($matches): string {
|
||||
return urlencode($matches[0]);
|
||||
},
|
||||
$url
|
||||
@@ -409,10 +445,10 @@ class Url implements \JsonSerializable
|
||||
*/
|
||||
public static function arrayToParams(array $getParams = [], bool $includeEmpty = true): string
|
||||
{
|
||||
if (\count($getParams) !== 0) {
|
||||
if (count($getParams) !== 0) {
|
||||
|
||||
if ($includeEmpty === false) {
|
||||
$getParams = array_filter($getParams, function ($item) {
|
||||
$getParams = array_filter($getParams, static function ($item): bool {
|
||||
return (trim($item) !== '');
|
||||
});
|
||||
}
|
||||
@@ -426,14 +462,18 @@ class Url implements \JsonSerializable
|
||||
/**
|
||||
* Returns the relative url
|
||||
*
|
||||
* @param bool $includeParams
|
||||
* @return string
|
||||
*/
|
||||
public function getRelativeUrl(): string
|
||||
public function getRelativeUrl(bool $includeParams = true): string
|
||||
{
|
||||
$params = $this->getQueryString();
|
||||
$path = $this->path ?? '/';
|
||||
|
||||
$path = $this->path ?? '';
|
||||
$query = $params !== '' ? '?' . $params : '';
|
||||
if($includeParams === false) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
$query = $this->getQueryString() !== '' ? '?' . $this->getQueryString() : '';
|
||||
$fragment = $this->fragment !== null ? '#' . $this->fragment : '';
|
||||
|
||||
return $path . $query . $fragment;
|
||||
@@ -442,24 +482,25 @@ class Url implements \JsonSerializable
|
||||
/**
|
||||
* Returns the absolute url
|
||||
*
|
||||
* @param bool $includeParams
|
||||
* @return string
|
||||
*/
|
||||
public function getAbsoluteUrl(): string
|
||||
public function getAbsoluteUrl(bool $includeParams = true): string
|
||||
{
|
||||
$scheme = $this->scheme !== null ? $this->scheme . '://' : '';
|
||||
$host = $this->host ?? '';
|
||||
$port = $this->port !== null ? ':' . $this->port : '';
|
||||
$user = $this->username ?? '';
|
||||
$pass = $this->password !== null ? ':' . $this->password : '';
|
||||
$pass = ($user || $pass) ? $pass . '@' : '';
|
||||
$pass = ($user !== '' || $pass !== '') ? $pass . '@' : '';
|
||||
|
||||
return $scheme . $user . $pass . $host . $port . $this->getRelativeUrl();
|
||||
return $scheme . $user . $pass . $host . $port . $this->getRelativeUrl($includeParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Specify data which should be serialized to JSON
|
||||
* @link http://php.net/manual/en/jsonserializable.jsonserialize.php
|
||||
* @return mixed data which can be serialized by <b>json_encode</b>,
|
||||
* @return string data which can be serialized by <b>json_encode</b>,
|
||||
* which is a value of any type other than a resource.
|
||||
* @since 5.4.0
|
||||
*/
|
||||
|
||||
@@ -2,117 +2,48 @@
|
||||
|
||||
namespace Pecee\SimpleRouter\ClassLoader;
|
||||
|
||||
use DI\Container;
|
||||
use Pecee\SimpleRouter\Exceptions\NotFoundHttpException;
|
||||
use Pecee\SimpleRouter\Exceptions\ClassNotFoundHttpException;
|
||||
|
||||
class ClassLoader implements IClassLoader
|
||||
{
|
||||
/**
|
||||
* Dependency injection enabled
|
||||
* @var bool
|
||||
*/
|
||||
protected $useDependencyInjection = false;
|
||||
|
||||
/**
|
||||
* @var Container|null
|
||||
*/
|
||||
protected $container;
|
||||
|
||||
/**
|
||||
* Load class
|
||||
*
|
||||
* @param string $class
|
||||
* @return mixed
|
||||
* @throws NotFoundHttpException
|
||||
* @return object
|
||||
* @throws ClassNotFoundHttpException
|
||||
*/
|
||||
public function loadClass(string $class)
|
||||
{
|
||||
if (class_exists($class) === false) {
|
||||
throw new NotFoundHttpException(sprintf('Class "%s" does not exist', $class), 404);
|
||||
}
|
||||
|
||||
if ($this->useDependencyInjection === true) {
|
||||
$container = $this->getContainer();
|
||||
if ($container !== null) {
|
||||
try {
|
||||
return $container->get($class);
|
||||
} catch (\Exception $e) {
|
||||
throw new NotFoundHttpException($e->getMessage(), (int)$e->getCode(), $e->getPrevious());
|
||||
}
|
||||
}
|
||||
throw new ClassNotFoundHttpException($class, null, sprintf('Class "%s" does not exist', $class), 404, null);
|
||||
}
|
||||
|
||||
return new $class();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when loading class method
|
||||
* @param object $class
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
* @return object
|
||||
*/
|
||||
public function loadClassMethod($class, string $method, array $parameters)
|
||||
{
|
||||
return call_user_func_array([$class, $method], array_values($parameters));
|
||||
}
|
||||
|
||||
/**
|
||||
* Load closure
|
||||
*
|
||||
* @param \Closure $closure
|
||||
* @param Callable $closure
|
||||
* @param array $parameters
|
||||
* @return mixed
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public function loadClosure(\Closure $closure, array $parameters)
|
||||
public function loadClosure(Callable $closure, array $parameters)
|
||||
{
|
||||
if ($this->useDependencyInjection === true) {
|
||||
$container = $this->getContainer();
|
||||
if ($container !== null) {
|
||||
try {
|
||||
return $container->call($closure, $parameters);
|
||||
} catch (\Exception $e) {
|
||||
throw new NotFoundHttpException($e->getMessage(), (int)$e->getCode(), $e->getPrevious());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return \call_user_func_array($closure, $parameters);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get dependency injector container.
|
||||
*
|
||||
* @return Container|null
|
||||
*/
|
||||
public function getContainer(): ?Container
|
||||
{
|
||||
return $this->container;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the dependency-injector container.
|
||||
*
|
||||
* @param Container $container
|
||||
* @return ClassLoader
|
||||
*/
|
||||
public function setContainer(Container $container): self
|
||||
{
|
||||
$this->container = $container;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable dependency injection.
|
||||
*
|
||||
* @param bool $enabled
|
||||
* @return static
|
||||
*/
|
||||
public function useDependencyInjection(bool $enabled): self
|
||||
{
|
||||
$this->useDependencyInjection = $enabled;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return true if dependency injection is enabled.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isDependencyInjectionEnabled(): bool
|
||||
{
|
||||
return $this->useDependencyInjection;
|
||||
return call_user_func_array($closure, array_values($parameters));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -5,8 +5,29 @@ namespace Pecee\SimpleRouter\ClassLoader;
|
||||
interface IClassLoader
|
||||
{
|
||||
|
||||
/**
|
||||
* Called when loading class
|
||||
* @param string $class
|
||||
* @return object
|
||||
*/
|
||||
public function loadClass(string $class);
|
||||
|
||||
public function loadClosure(\Closure $closure, array $parameters);
|
||||
/**
|
||||
* Called when loading class method
|
||||
* @param object $class
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
* @return object
|
||||
*/
|
||||
public function loadClassMethod($class, string $method, array $parameters);
|
||||
|
||||
/**
|
||||
* Called when loading method
|
||||
*
|
||||
* @param callable $closure
|
||||
* @param array $parameters
|
||||
* @return mixed
|
||||
*/
|
||||
public function loadClosure(Callable $closure, array $parameters);
|
||||
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Pecee\SimpleRouter\Event;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Pecee\Http\Request;
|
||||
use Pecee\SimpleRouter\Router;
|
||||
|
||||
@@ -23,7 +24,7 @@ class EventArgument implements IEventArgument
|
||||
*/
|
||||
protected $arguments = [];
|
||||
|
||||
public function __construct($eventName, $router, array $arguments = [])
|
||||
public function __construct(string $eventName, Router $router, array $arguments = [])
|
||||
{
|
||||
$this->eventName = $eventName;
|
||||
$this->router = $router;
|
||||
@@ -74,7 +75,7 @@ class EventArgument implements IEventArgument
|
||||
* @param string $name
|
||||
* @return mixed
|
||||
*/
|
||||
public function __get($name)
|
||||
public function __get(string $name)
|
||||
{
|
||||
return $this->arguments[$name] ?? null;
|
||||
}
|
||||
@@ -83,7 +84,7 @@ class EventArgument implements IEventArgument
|
||||
* @param string $name
|
||||
* @return bool
|
||||
*/
|
||||
public function __isset($name)
|
||||
public function __isset(string $name): bool
|
||||
{
|
||||
return array_key_exists($name, $this->arguments);
|
||||
}
|
||||
@@ -91,11 +92,11 @@ class EventArgument implements IEventArgument
|
||||
/**
|
||||
* @param string $name
|
||||
* @param mixed $value
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function __set($name, $value)
|
||||
public function __set(string $name, $value): void
|
||||
{
|
||||
throw new \InvalidArgumentException('Not supported');
|
||||
throw new InvalidArgumentException('Not supported');
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace Pecee\SimpleRouter\Exceptions;
|
||||
|
||||
use Throwable;
|
||||
|
||||
class ClassNotFoundHttpException extends NotFoundHttpException
|
||||
{
|
||||
/**
|
||||
* @var string
|
||||
*/
|
||||
protected $class;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
protected $method;
|
||||
|
||||
public function __construct(string $class, ?string $method = null, string $message = "", int $code = 0, Throwable $previous = null)
|
||||
{
|
||||
parent::__construct($message, $code, $previous);
|
||||
|
||||
$this->class = $class;
|
||||
$this->method = $method;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get class name
|
||||
* @return string
|
||||
*/
|
||||
public function getClass(): string
|
||||
{
|
||||
return $this->class;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get method
|
||||
* @return string|null
|
||||
*/
|
||||
public function getMethod(): ?string
|
||||
{
|
||||
return $this->method;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
namespace Pecee\SimpleRouter\Exceptions;
|
||||
|
||||
class HttpException extends \Exception
|
||||
use Exception;
|
||||
|
||||
class HttpException extends Exception
|
||||
{
|
||||
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace Pecee\SimpleRouter\Handlers;
|
||||
|
||||
use Closure;
|
||||
use Exception;
|
||||
use Pecee\Http\Request;
|
||||
|
||||
/**
|
||||
@@ -15,21 +17,24 @@ use Pecee\Http\Request;
|
||||
class CallbackExceptionHandler implements IExceptionHandler
|
||||
{
|
||||
|
||||
/**
|
||||
* @var Closure
|
||||
*/
|
||||
protected $callback;
|
||||
|
||||
public function __construct(\Closure $callback)
|
||||
public function __construct(Closure $callback)
|
||||
{
|
||||
$this->callback = $callback;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param \Exception $error
|
||||
* @param Exception $error
|
||||
*/
|
||||
public function handleError(Request $request, \Exception $error): void
|
||||
public function handleError(Request $request, Exception $error): void
|
||||
{
|
||||
/* Fire exceptions */
|
||||
\call_user_func($this->callback,
|
||||
call_user_func($this->callback,
|
||||
$request,
|
||||
$error
|
||||
);
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Pecee\SimpleRouter\Handlers;
|
||||
|
||||
use Closure;
|
||||
use Pecee\SimpleRouter\Event\EventArgument;
|
||||
use Pecee\SimpleRouter\Router;
|
||||
|
||||
@@ -10,13 +11,13 @@ class DebugEventHandler implements IEventHandler
|
||||
|
||||
/**
|
||||
* Debug callback
|
||||
* @var \Closure
|
||||
* @var Closure
|
||||
*/
|
||||
protected $callback;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->callback = function (EventArgument $argument) {
|
||||
$this->callback = static function (EventArgument $argument): void {
|
||||
// todo: log in database
|
||||
};
|
||||
}
|
||||
@@ -46,15 +47,15 @@ class DebugEventHandler implements IEventHandler
|
||||
public function fireEvents(Router $router, string $name, array $eventArgs = []): void
|
||||
{
|
||||
$callback = $this->callback;
|
||||
$callback(new EventArgument($router, $eventArgs));
|
||||
$callback(new EventArgument($name, $router, $eventArgs));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set debug callback
|
||||
*
|
||||
* @param \Closure $event
|
||||
* @param Closure $event
|
||||
*/
|
||||
public function setCallback(\Closure $event): void
|
||||
public function setCallback(Closure $event): void
|
||||
{
|
||||
$this->callback = $event;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Pecee\SimpleRouter\Handlers;
|
||||
|
||||
use Closure;
|
||||
use Pecee\SimpleRouter\Event\EventArgument;
|
||||
use Pecee\SimpleRouter\Router;
|
||||
|
||||
@@ -125,10 +126,10 @@ class EventHandler implements IEventHandler
|
||||
* Register new event
|
||||
*
|
||||
* @param string $name
|
||||
* @param \Closure $callback
|
||||
* @param Closure $callback
|
||||
* @return static
|
||||
*/
|
||||
public function register(string $name, \Closure $callback): IEventHandler
|
||||
public function register(string $name, Closure $callback): IEventHandler
|
||||
{
|
||||
if (isset($this->registeredEvents[$name]) === true) {
|
||||
$this->registeredEvents[$name][] = $callback;
|
||||
@@ -143,7 +144,7 @@ class EventHandler implements IEventHandler
|
||||
* Get events.
|
||||
*
|
||||
* @param string|null $name Filter events by name.
|
||||
* @param array ...$names Add multiple names...
|
||||
* @param array|string ...$names Add multiple names...
|
||||
* @return array
|
||||
*/
|
||||
public function getEvents(?string $name, ...$names): array
|
||||
@@ -175,7 +176,7 @@ class EventHandler implements IEventHandler
|
||||
{
|
||||
$events = $this->getEvents(static::EVENT_ALL, $name);
|
||||
|
||||
/* @var $event \Closure */
|
||||
/* @var $event Closure */
|
||||
foreach ($events as $event) {
|
||||
$event(new EventArgument($name, $router, $eventArgs));
|
||||
}
|
||||
|
||||
@@ -2,14 +2,15 @@
|
||||
|
||||
namespace Pecee\SimpleRouter\Handlers;
|
||||
|
||||
use Exception;
|
||||
use Pecee\Http\Request;
|
||||
|
||||
interface IExceptionHandler
|
||||
{
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param \Exception $error
|
||||
* @param Exception $error
|
||||
*/
|
||||
public function handleError(Request $request, \Exception $error): void;
|
||||
public function handleError(Request $request, Exception $error): void;
|
||||
|
||||
}
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
namespace Pecee\SimpleRouter\Route;
|
||||
|
||||
interface IControllerRoute extends IRoute
|
||||
interface IControllerRoute extends ILoadableRoute
|
||||
{
|
||||
/**
|
||||
* Get controller class-name
|
||||
|
||||
@@ -29,7 +29,22 @@ interface IGroupRoute extends IRoute
|
||||
* @param array $handlers
|
||||
* @return static
|
||||
*/
|
||||
public function setExceptionHandlers(array $handlers);
|
||||
public function setExceptionHandlers(array $handlers): self;
|
||||
|
||||
/**
|
||||
* Returns true if group should overwrite existing exception-handlers.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getMergeExceptionHandlers(): bool;
|
||||
|
||||
/**
|
||||
* When enabled group will overwrite any existing exception-handlers.
|
||||
*
|
||||
* @param bool $merge
|
||||
* @return static
|
||||
*/
|
||||
public function setMergeExceptionHandlers(bool $merge): self;
|
||||
|
||||
/**
|
||||
* Get exception-handlers for group
|
||||
@@ -53,13 +68,21 @@ interface IGroupRoute extends IRoute
|
||||
*/
|
||||
public function setDomains(array $domains): self;
|
||||
|
||||
/**
|
||||
* Prepends prefix while ensuring that the url has the correct formatting.
|
||||
*
|
||||
* @param string $url
|
||||
* @return static
|
||||
*/
|
||||
public function prependPrefix(string $url): self;
|
||||
|
||||
/**
|
||||
* Set prefix that child-routes will inherit.
|
||||
*
|
||||
* @param string $prefix
|
||||
* @return static
|
||||
*/
|
||||
public function setPrefix($prefix): self;
|
||||
public function setPrefix(string $prefix): self;
|
||||
|
||||
/**
|
||||
* Get prefix.
|
||||
|
||||
@@ -40,7 +40,7 @@ interface ILoadableRoute extends IRoute
|
||||
public function setUrl(string $url): self;
|
||||
|
||||
/**
|
||||
* Prepend url
|
||||
* Prepends url while ensuring that the url has the correct formatting.
|
||||
* @param string $url
|
||||
* @return ILoadableRoute
|
||||
*/
|
||||
@@ -82,6 +82,6 @@ interface ILoadableRoute extends IRoute
|
||||
* @param string $regex
|
||||
* @return static
|
||||
*/
|
||||
public function setMatch($regex): self;
|
||||
public function setMatch(string $regex): self;
|
||||
|
||||
}
|
||||
@@ -10,11 +10,11 @@ interface IRoute
|
||||
/**
|
||||
* Method called to check if a domain matches
|
||||
*
|
||||
* @param string $route
|
||||
* @param string $url
|
||||
* @param Request $request
|
||||
* @return bool
|
||||
*/
|
||||
public function matchRoute($route, Request $request): bool;
|
||||
public function matchRoute(string $url, Request $request): bool;
|
||||
|
||||
/**
|
||||
* Called when route is matched.
|
||||
@@ -22,8 +22,8 @@ interface IRoute
|
||||
*
|
||||
* @param Request $request
|
||||
* @param Router $router
|
||||
* @throws \Pecee\SimpleRouter\Exceptions\NotFoundHttpException
|
||||
* @return string
|
||||
* @throws \Pecee\SimpleRouter\Exceptions\NotFoundHttpException
|
||||
*/
|
||||
public function renderRoute(Request $request, Router $router): ?string;
|
||||
|
||||
@@ -82,7 +82,7 @@ interface IRoute
|
||||
/**
|
||||
* Set callback
|
||||
*
|
||||
* @param string $callback
|
||||
* @param string|array|\Closure $callback
|
||||
* @return static
|
||||
*/
|
||||
public function setCallback($callback): self;
|
||||
@@ -129,7 +129,7 @@ interface IRoute
|
||||
* @param string $namespace
|
||||
* @return static
|
||||
*/
|
||||
public function setDefaultNamespace($namespace): IRoute;
|
||||
public function setDefaultNamespace(string $namespace): IRoute;
|
||||
|
||||
/**
|
||||
* Get default namespace
|
||||
@@ -196,7 +196,7 @@ interface IRoute
|
||||
* @param string $middleware
|
||||
* @return static
|
||||
*/
|
||||
public function addMiddleware($middleware): self;
|
||||
public function addMiddleware(string $middleware): self;
|
||||
|
||||
/**
|
||||
* Set middlewares array
|
||||
@@ -206,4 +206,18 @@ interface IRoute
|
||||
*/
|
||||
public function setMiddlewares(array $middlewares): self;
|
||||
|
||||
/**
|
||||
* If enabled parameters containing null-value will not be passed along to the callback.
|
||||
*
|
||||
* @param bool $enabled
|
||||
* @return static $this
|
||||
*/
|
||||
public function setFilterEmptyParams(bool $enabled): self;
|
||||
|
||||
/**
|
||||
* Status if filtering of empty params is enabled or disabled
|
||||
* @return bool
|
||||
*/
|
||||
public function getFilterEmptyParams(): bool;
|
||||
|
||||
}
|
||||
@@ -19,6 +19,9 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
*/
|
||||
protected $name;
|
||||
|
||||
/**
|
||||
* @var string|null
|
||||
*/
|
||||
protected $regex;
|
||||
|
||||
/**
|
||||
@@ -34,7 +37,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
|
||||
foreach ($this->getMiddlewares() as $middleware) {
|
||||
|
||||
if (\is_object($middleware) === false) {
|
||||
if (is_object($middleware) === false) {
|
||||
$middleware = $router->getClassLoader()->loadClass($middleware);
|
||||
}
|
||||
|
||||
@@ -42,7 +45,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
throw new HttpException($middleware . ' must be inherit the IMiddleware interface');
|
||||
}
|
||||
|
||||
$className = \get_class($middleware);
|
||||
$className = get_class($middleware);
|
||||
|
||||
$router->debug('Loading middleware "%s"', $className);
|
||||
$middleware->handle($request);
|
||||
@@ -55,12 +58,18 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
public function matchRegex(Request $request, $url): ?bool
|
||||
{
|
||||
/* Match on custom defined regular expression */
|
||||
|
||||
if ($this->regex === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return ((bool)preg_match($this->regex, $request->getHost() . $url) !== false);
|
||||
$parameters = [];
|
||||
if ((bool)preg_match($this->regex, $url, $parameters) !== false) {
|
||||
$this->setParameters($parameters);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,7 +95,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepend url
|
||||
* Prepends url while ensuring that the url has the correct formatting.
|
||||
*
|
||||
* @param string $url
|
||||
* @return ILoadableRoute
|
||||
@@ -101,6 +110,18 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if group is defined and matches the given url.
|
||||
*
|
||||
* @param string $url
|
||||
* @param Request $request
|
||||
* @return bool
|
||||
*/
|
||||
protected function matchGroup(string $url, Request $request): bool
|
||||
{
|
||||
return ($this->getGroup() === null || $this->getGroup()->matchRoute($url, $request) === true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Find url that matches method, parameters or name.
|
||||
* Used when calling the url() helper.
|
||||
@@ -116,7 +137,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
|
||||
$group = $this->getGroup();
|
||||
|
||||
if ($group !== null && \count($group->getDomains()) !== 0) {
|
||||
if ($group !== null && count($group->getDomains()) !== 0) {
|
||||
$url = '//' . $group->getDomains()[0] . $url;
|
||||
}
|
||||
|
||||
@@ -132,7 +153,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
|
||||
foreach (array_keys($params) as $param) {
|
||||
|
||||
if ($parameters === '' || (\is_array($parameters) === true && \count($parameters) === 0)) {
|
||||
if ($parameters === '' || (is_array($parameters) === true && count($parameters) === 0)) {
|
||||
$value = '';
|
||||
} else {
|
||||
$p = (array)$parameters;
|
||||
@@ -183,7 +204,7 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
* @param string $regex
|
||||
* @return static
|
||||
*/
|
||||
public function setMatch($regex): ILoadableRoute
|
||||
public function setMatch(string $regex): ILoadableRoute
|
||||
{
|
||||
$this->regex = $regex;
|
||||
|
||||
@@ -204,9 +225,9 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
* Sets the router name, which makes it easier to obtain the url or router at a later point.
|
||||
* Alias for LoadableRoute::setName().
|
||||
*
|
||||
* @see LoadableRoute::setName()
|
||||
* @param string|array $name
|
||||
* @return static
|
||||
* @see LoadableRoute::setName()
|
||||
*/
|
||||
public function name($name): ILoadableRoute
|
||||
{
|
||||
@@ -229,15 +250,15 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
/**
|
||||
* Merge with information from another route.
|
||||
*
|
||||
* @param array $values
|
||||
* @param array $settings
|
||||
* @param bool $merge
|
||||
* @return static
|
||||
*/
|
||||
public function setSettings(array $values, bool $merge = false): IRoute
|
||||
public function setSettings(array $settings, bool $merge = false): IRoute
|
||||
{
|
||||
if (isset($values['as']) === true) {
|
||||
if (isset($settings['as']) === true) {
|
||||
|
||||
$name = $values['as'];
|
||||
$name = $settings['as'];
|
||||
|
||||
if ($this->name !== null && $merge !== false) {
|
||||
$name .= '.' . $this->name;
|
||||
@@ -246,11 +267,11 @@ abstract class LoadableRoute extends Route implements ILoadableRoute
|
||||
$this->setName($name);
|
||||
}
|
||||
|
||||
if (isset($values['prefix']) === true) {
|
||||
$this->prependUrl($values['prefix']);
|
||||
if (isset($settings['prefix']) === true) {
|
||||
$this->prependUrl($settings['prefix']);
|
||||
}
|
||||
|
||||
return parent::setSettings($values, $merge);
|
||||
return parent::setSettings($settings, $merge);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,31 +2,15 @@
|
||||
|
||||
namespace Pecee\SimpleRouter\Route;
|
||||
|
||||
use Pecee\Http\Middleware\IMiddleware;
|
||||
use Pecee\Http\Request;
|
||||
use Pecee\SimpleRouter\Exceptions\ClassNotFoundHttpException;
|
||||
use Pecee\SimpleRouter\Exceptions\NotFoundHttpException;
|
||||
use Pecee\SimpleRouter\Router;
|
||||
|
||||
abstract class Route implements IRoute
|
||||
{
|
||||
protected const PARAMETERS_REGEX_FORMAT = '%s([\w]+)(\%s?)%s';
|
||||
protected const PARAMETERS_DEFAULT_REGEX = '[\w]+';
|
||||
|
||||
public const REQUEST_TYPE_GET = 'get';
|
||||
public const REQUEST_TYPE_POST = 'post';
|
||||
public const REQUEST_TYPE_PUT = 'put';
|
||||
public const REQUEST_TYPE_PATCH = 'patch';
|
||||
public const REQUEST_TYPE_OPTIONS = 'options';
|
||||
public const REQUEST_TYPE_DELETE = 'delete';
|
||||
|
||||
public static $requestTypes = [
|
||||
self::REQUEST_TYPE_GET,
|
||||
self::REQUEST_TYPE_POST,
|
||||
self::REQUEST_TYPE_PUT,
|
||||
self::REQUEST_TYPE_PATCH,
|
||||
self::REQUEST_TYPE_OPTIONS,
|
||||
self::REQUEST_TYPE_DELETE,
|
||||
];
|
||||
protected const PARAMETERS_DEFAULT_REGEX = '[\w-]+';
|
||||
|
||||
/**
|
||||
* If enabled parameters containing null-value
|
||||
@@ -46,6 +30,9 @@ abstract class Route implements IRoute
|
||||
protected $urlRegex = '/^%s\/?$/u';
|
||||
protected $group;
|
||||
protected $parent;
|
||||
/**
|
||||
* @var string|callable|null
|
||||
*/
|
||||
protected $callback;
|
||||
protected $defaultNamespace;
|
||||
|
||||
@@ -67,7 +54,7 @@ abstract class Route implements IRoute
|
||||
*/
|
||||
public function renderRoute(Request $request, Router $router): ?string
|
||||
{
|
||||
$router->debug('Starting rendering route "%s"', \get_class($this));
|
||||
$router->debug('Starting rendering route "%s"', get_class($this));
|
||||
|
||||
$callback = $this->getCallback();
|
||||
|
||||
@@ -83,64 +70,72 @@ abstract class Route implements IRoute
|
||||
|
||||
/* Filter parameters with null-value */
|
||||
if ($this->filterEmptyParams === true) {
|
||||
$parameters = array_filter($parameters, function ($var) {
|
||||
$parameters = array_filter($parameters, static function ($var): bool {
|
||||
return ($var !== null);
|
||||
});
|
||||
}
|
||||
|
||||
/* Render callback function */
|
||||
if (\is_callable($callback) === true) {
|
||||
if (is_callable($callback) === true) {
|
||||
$router->debug('Executing callback');
|
||||
|
||||
/* Load class from type hinting */
|
||||
if (is_array($callback) === true && isset($callback[0], $callback[1]) === true) {
|
||||
$callback[0] = $router->getClassLoader()->loadClass($callback[0]);
|
||||
}
|
||||
|
||||
/* When the callback is a function */
|
||||
|
||||
return $router->getClassLoader()->loadClosure($callback, $parameters);
|
||||
}
|
||||
|
||||
/* When the callback is a class + method */
|
||||
$controller = explode('@', $callback);
|
||||
$controller = $this->getClass();
|
||||
$method = $this->getMethod();
|
||||
|
||||
$namespace = $this->getNamespace();
|
||||
|
||||
$className = ($namespace !== null && $controller[0][0] !== '\\') ? $namespace . '\\' . $controller[0] : $controller[0];
|
||||
$className = ($namespace !== null && $controller[0] !== '\\') ? $namespace . '\\' . $controller : $controller;
|
||||
|
||||
$router->debug('Loading class %s', $className);
|
||||
$class = $router->getClassLoader()->loadClass($className);
|
||||
|
||||
$method = $controller[1];
|
||||
if ($method === null) {
|
||||
$controller[1] = '__invoke';
|
||||
}
|
||||
|
||||
if (method_exists($class, $method) === false) {
|
||||
throw new NotFoundHttpException(sprintf('Method "%s" does not exist in class "%s"', $method, $className), 404);
|
||||
throw new ClassNotFoundHttpException($className, $method, sprintf('Method "%s" does not exist in class "%s"', $method, $className), 404, null);
|
||||
}
|
||||
|
||||
$router->debug('Executing callback');
|
||||
$router->debug('Executing callback %s -> %s', $className, $method);
|
||||
|
||||
return \call_user_func_array([$class, $method], $parameters);
|
||||
return $router->getClassLoader()->loadClassMethod($class, $method, $parameters);
|
||||
}
|
||||
|
||||
protected function parseParameters($route, $url, $parameterRegex = null)
|
||||
protected function parseParameters($route, $url, $parameterRegex = null): ?array
|
||||
{
|
||||
$regex = null;
|
||||
if (strpos($route, $this->paramModifiers[0]) !== false) {
|
||||
$regex = sprintf(static::PARAMETERS_REGEX_FORMAT, $this->paramModifiers[0], $this->paramOptionalSymbol, $this->paramModifiers[1]);
|
||||
}
|
||||
$regex = (strpos($route, $this->paramModifiers[0]) === false) ? null :
|
||||
sprintf
|
||||
(
|
||||
static::PARAMETERS_REGEX_FORMAT,
|
||||
$this->paramModifiers[0],
|
||||
$this->paramOptionalSymbol,
|
||||
$this->paramModifiers[1]
|
||||
);
|
||||
|
||||
// Ensures that host names/domains will work with parameters
|
||||
$url = '/' . ltrim($url, '/');
|
||||
$urlRegex = null;
|
||||
$urlRegex = '';
|
||||
$parameters = [];
|
||||
|
||||
if ($regex === null || (bool)preg_match_all('/' . $regex . '/u', $route, $parameters) === false) {
|
||||
$urlRegex = preg_quote($route, '/');
|
||||
} else {
|
||||
|
||||
$urlParts = preg_split('/((\-?\/?)\{[^}]+\})/', $route);
|
||||
|
||||
foreach ($urlParts as $key => $t) {
|
||||
foreach (preg_split('/((-?\/?){[^}]+})/', $route) as $key => $t) {
|
||||
|
||||
$regex = '';
|
||||
|
||||
if ($key < \count($parameters[1])) {
|
||||
if ($key < count($parameters[1])) {
|
||||
|
||||
$name = $parameters[1][$key];
|
||||
|
||||
@@ -148,23 +143,17 @@ abstract class Route implements IRoute
|
||||
if (isset($this->where[$name]) === true) {
|
||||
$regex = $this->where[$name];
|
||||
} else {
|
||||
|
||||
/* If method specific regex is defined use that, otherwise use the default parameter regex */
|
||||
if ($parameterRegex !== null) {
|
||||
$regex = $parameterRegex;
|
||||
} else {
|
||||
$regex = $this->defaultParameterRegex ?? static::PARAMETERS_DEFAULT_REGEX;
|
||||
}
|
||||
$regex = $parameterRegex ?? $this->defaultParameterRegex ?? static::PARAMETERS_DEFAULT_REGEX;
|
||||
}
|
||||
|
||||
$regex = sprintf('(?:\/|\-)%1$s(?P<%2$s>%3$s)%1$s', $parameters[2][$key], $name, $regex);
|
||||
$regex = sprintf('((\/|-)(?P<%2$s>%3$s))%1$s', $parameters[2][$key], $name, $regex);
|
||||
}
|
||||
|
||||
$urlRegex .= preg_quote($t, '/') . $regex;
|
||||
}
|
||||
}
|
||||
|
||||
if ($urlRegex === null || (bool)preg_match(sprintf($this->urlRegex, $urlRegex), $url, $matches) === false) {
|
||||
if (trim($urlRegex) === '' || (bool)preg_match(sprintf($this->urlRegex, $urlRegex), $url, $matches) === false) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@@ -172,12 +161,27 @@ abstract class Route implements IRoute
|
||||
|
||||
if (isset($parameters[1]) === true) {
|
||||
|
||||
$groupParameters = $this->getGroup() !== null ? $this->getGroup()->getParameters() : [];
|
||||
|
||||
$lastParams = [];
|
||||
|
||||
/* Only take matched parameters with name */
|
||||
foreach ((array)$parameters[1] as $name) {
|
||||
$values[$name] = (isset($matches[$name]) && $matches[$name] !== '') ? $matches[$name] : null;
|
||||
|
||||
// Ignore parent parameters
|
||||
if (isset($groupParameters[$name]) === true) {
|
||||
$lastParams[$name] = $matches[$name];
|
||||
continue;
|
||||
}
|
||||
|
||||
$values[$name] = (isset($matches[$name]) === true && $matches[$name] !== '') ? $matches[$name] : null;
|
||||
}
|
||||
|
||||
$values = array_merge($values, $lastParams);
|
||||
}
|
||||
|
||||
$this->originalParameters = $values;
|
||||
|
||||
return $values;
|
||||
}
|
||||
|
||||
@@ -190,7 +194,7 @@ abstract class Route implements IRoute
|
||||
*/
|
||||
public function getIdentifier(): string
|
||||
{
|
||||
if (\is_string($this->callback) === true && strpos($this->callback, '@') !== false) {
|
||||
if (is_string($this->callback) === true && strpos($this->callback, '@') !== false) {
|
||||
return $this->callback;
|
||||
}
|
||||
|
||||
@@ -269,7 +273,7 @@ abstract class Route implements IRoute
|
||||
/**
|
||||
* Set callback
|
||||
*
|
||||
* @param string $callback
|
||||
* @param string|array|\Closure $callback
|
||||
* @return static
|
||||
*/
|
||||
public function setCallback($callback): IRoute
|
||||
@@ -280,7 +284,7 @@ abstract class Route implements IRoute
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|callable
|
||||
* @return string|callable|null
|
||||
*/
|
||||
public function getCallback()
|
||||
{
|
||||
@@ -289,7 +293,11 @@ abstract class Route implements IRoute
|
||||
|
||||
public function getMethod(): ?string
|
||||
{
|
||||
if (\is_string($this->callback) === true && strpos($this->callback, '@') !== false) {
|
||||
if (is_array($this->callback) === true && count($this->callback) > 1) {
|
||||
return $this->callback[1];
|
||||
}
|
||||
|
||||
if (is_string($this->callback) === true && strpos($this->callback, '@') !== false) {
|
||||
$tmp = explode('@', $this->callback);
|
||||
|
||||
return $tmp[1];
|
||||
@@ -300,7 +308,11 @@ abstract class Route implements IRoute
|
||||
|
||||
public function getClass(): ?string
|
||||
{
|
||||
if (\is_string($this->callback) === true && strpos($this->callback, '@') !== false) {
|
||||
if (is_array($this->callback) === true && count($this->callback) > 0) {
|
||||
return $this->callback[0];
|
||||
}
|
||||
|
||||
if (is_string($this->callback) === true && strpos($this->callback, '@') !== false) {
|
||||
$tmp = explode('@', $this->callback);
|
||||
|
||||
return $tmp[0];
|
||||
@@ -311,14 +323,14 @@ abstract class Route implements IRoute
|
||||
|
||||
public function setMethod(string $method): IRoute
|
||||
{
|
||||
$this->callback = sprintf('%s@%s', $this->getClass(), $method);
|
||||
$this->callback = [$this->getClass(), $method];
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function setClass(string $class): IRoute
|
||||
{
|
||||
$this->callback = sprintf('%s@%s', $class, $this->getMethod());
|
||||
$this->callback = [$class, $this->getMethod()];
|
||||
|
||||
return $this;
|
||||
}
|
||||
@@ -329,6 +341,22 @@ abstract class Route implements IRoute
|
||||
*/
|
||||
public function setNamespace(string $namespace): IRoute
|
||||
{
|
||||
// Do not set namespace when class-hinting is used
|
||||
if (is_array($this->callback) === true) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$ns = $this->getNamespace();
|
||||
|
||||
if ($ns !== null) {
|
||||
// Don't overwrite namespaces that starts with \
|
||||
if ($ns[0] !== '\\') {
|
||||
$namespace .= '\\' . $ns;
|
||||
} else {
|
||||
$namespace = $ns;
|
||||
}
|
||||
}
|
||||
|
||||
$this->namespace = $namespace;
|
||||
|
||||
return $this;
|
||||
@@ -338,7 +366,7 @@ abstract class Route implements IRoute
|
||||
* @param string $namespace
|
||||
* @return static
|
||||
*/
|
||||
public function setDefaultNamespace($namespace): IRoute
|
||||
public function setDefaultNamespace(string $namespace): IRoute
|
||||
{
|
||||
$this->defaultNamespace = $namespace;
|
||||
|
||||
@@ -371,15 +399,15 @@ abstract class Route implements IRoute
|
||||
$values['namespace'] = $this->namespace;
|
||||
}
|
||||
|
||||
if (\count($this->requestMethods) !== 0) {
|
||||
if (count($this->requestMethods) !== 0) {
|
||||
$values['method'] = $this->requestMethods;
|
||||
}
|
||||
|
||||
if (\count($this->where) !== 0) {
|
||||
if (count($this->where) !== 0) {
|
||||
$values['where'] = $this->where;
|
||||
}
|
||||
|
||||
if (\count($this->middlewares) !== 0) {
|
||||
if (count($this->middlewares) !== 0) {
|
||||
$values['middleware'] = $this->middlewares;
|
||||
}
|
||||
|
||||
@@ -393,35 +421,35 @@ abstract class Route implements IRoute
|
||||
/**
|
||||
* Merge with information from another route.
|
||||
*
|
||||
* @param array $values
|
||||
* @param array $settings
|
||||
* @param bool $merge
|
||||
* @return static
|
||||
*/
|
||||
public function setSettings(array $values, bool $merge = false): IRoute
|
||||
public function setSettings(array $settings, bool $merge = false): IRoute
|
||||
{
|
||||
if ($this->namespace === null && isset($values['namespace']) === true) {
|
||||
$this->setNamespace($values['namespace']);
|
||||
if (isset($settings['namespace']) === true) {
|
||||
$this->setNamespace($settings['namespace']);
|
||||
}
|
||||
|
||||
if (isset($values['method']) === true) {
|
||||
$this->setRequestMethods(array_merge($this->requestMethods, (array)$values['method']));
|
||||
if (isset($settings['method']) === true) {
|
||||
$this->setRequestMethods(array_merge($this->requestMethods, (array)$settings['method']));
|
||||
}
|
||||
|
||||
if (isset($values['where']) === true) {
|
||||
$this->setWhere(array_merge($this->where, (array)$values['where']));
|
||||
if (isset($settings['where']) === true) {
|
||||
$this->setWhere(array_merge($this->where, (array)$settings['where']));
|
||||
}
|
||||
|
||||
if (isset($values['parameters']) === true) {
|
||||
$this->setParameters(array_merge($this->parameters, (array)$values['parameters']));
|
||||
if (isset($settings['parameters']) === true) {
|
||||
$this->setParameters(array_merge($this->parameters, (array)$settings['parameters']));
|
||||
}
|
||||
|
||||
// Push middleware if multiple
|
||||
if (isset($values['middleware']) === true) {
|
||||
$this->setMiddlewares(array_merge((array)$values['middleware'], $this->middlewares));
|
||||
if (isset($settings['middleware']) === true) {
|
||||
$this->setMiddlewares(array_merge((array)$settings['middleware'], $this->middlewares));
|
||||
}
|
||||
|
||||
if (isset($values['defaultParameterRegex']) === true) {
|
||||
$this->setDefaultParameterRegex($values['defaultParameterRegex']);
|
||||
if (isset($settings['defaultParameterRegex']) === true) {
|
||||
$this->setDefaultParameterRegex($settings['defaultParameterRegex']);
|
||||
}
|
||||
|
||||
return $this;
|
||||
@@ -454,9 +482,9 @@ abstract class Route implements IRoute
|
||||
* Add regular expression parameter match.
|
||||
* Alias for LoadableRoute::where()
|
||||
*
|
||||
* @see LoadableRoute::where()
|
||||
* @param array $options
|
||||
* @return static
|
||||
* @see LoadableRoute::where()
|
||||
*/
|
||||
public function where(array $options)
|
||||
{
|
||||
@@ -473,7 +501,7 @@ abstract class Route implements IRoute
|
||||
/* Sort the parameters after the user-defined param order, if any */
|
||||
$parameters = [];
|
||||
|
||||
if (\count($this->originalParameters) !== 0) {
|
||||
if (count($this->originalParameters) !== 0) {
|
||||
$parameters = $this->originalParameters;
|
||||
}
|
||||
|
||||
@@ -488,14 +516,6 @@ abstract class Route implements IRoute
|
||||
*/
|
||||
public function setParameters(array $parameters): IRoute
|
||||
{
|
||||
/*
|
||||
* If this is the first time setting parameters we store them so we
|
||||
* later can organize the array, in case somebody tried to sort the array.
|
||||
*/
|
||||
if (\count($parameters) !== 0 && \count($this->originalParameters) === 0) {
|
||||
$this->originalParameters = $parameters;
|
||||
}
|
||||
|
||||
$this->parameters = array_merge($this->parameters, $parameters);
|
||||
|
||||
return $this;
|
||||
@@ -504,11 +524,11 @@ abstract class Route implements IRoute
|
||||
/**
|
||||
* Add middleware class-name
|
||||
*
|
||||
* @deprecated This method is deprecated and will be removed in the near future.
|
||||
* @param IMiddleware|string $middleware
|
||||
* @param string $middleware
|
||||
* @return static
|
||||
* @deprecated This method is deprecated and will be removed in the near future.
|
||||
*/
|
||||
public function setMiddleware($middleware)
|
||||
public function setMiddleware(string $middleware): self
|
||||
{
|
||||
$this->middlewares[] = $middleware;
|
||||
|
||||
@@ -518,10 +538,10 @@ abstract class Route implements IRoute
|
||||
/**
|
||||
* Add middleware class-name
|
||||
*
|
||||
* @param IMiddleware|string $middleware
|
||||
* @param string $middleware
|
||||
* @return static
|
||||
*/
|
||||
public function addMiddleware($middleware): IRoute
|
||||
public function addMiddleware(string $middleware): IRoute
|
||||
{
|
||||
$this->middlewares[] = $middleware;
|
||||
|
||||
@@ -556,7 +576,7 @@ abstract class Route implements IRoute
|
||||
* @param string $regex
|
||||
* @return static
|
||||
*/
|
||||
public function setDefaultParameterRegex($regex)
|
||||
public function setDefaultParameterRegex(string $regex): self
|
||||
{
|
||||
$this->defaultParameterRegex = $regex;
|
||||
|
||||
@@ -573,4 +593,26 @@ abstract class Route implements IRoute
|
||||
return $this->defaultParameterRegex;
|
||||
}
|
||||
|
||||
/**
|
||||
* If enabled parameters containing null-value will not be passed along to the callback.
|
||||
*
|
||||
* @param bool $enabled
|
||||
* @return static $this
|
||||
*/
|
||||
public function setFilterEmptyParams(bool $enabled): IRoute
|
||||
{
|
||||
$this->filterEmptyParams = $enabled;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Status if filtering of empty params is enabled or disabled
|
||||
* @return bool
|
||||
*/
|
||||
public function getFilterEmptyParams(): bool
|
||||
{
|
||||
return $this->filterEmptyParams;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -35,7 +35,7 @@ class RouteController extends LoadableRoute implements IControllerRoute
|
||||
$method = substr($name, strrpos($name, '.') + 1);
|
||||
$newName = substr($name, 0, strrpos($name, '.'));
|
||||
|
||||
if (\in_array($method, $this->names, true) === true && strtolower($this->name) === strtolower($newName)) {
|
||||
if (in_array($method, $this->names, true) === true && strtolower($this->name) === strtolower($newName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,7 @@ class RouteController extends LoadableRoute implements IControllerRoute
|
||||
public function findUrl(?string $method = null, $parameters = null, ?string $name = null): string
|
||||
{
|
||||
if (strpos($name, '.') !== false) {
|
||||
$found = array_search(substr($name, strrpos($name, '.') + 1), $this->names, false);
|
||||
$found = array_search(substr($name, strrpos($name, '.') + 1), $this->names, true);
|
||||
if ($found !== false) {
|
||||
$method = (string)$found;
|
||||
}
|
||||
@@ -64,10 +64,10 @@ class RouteController extends LoadableRoute implements IControllerRoute
|
||||
if ($method !== null) {
|
||||
|
||||
/* Remove requestType from method-name, if it exists */
|
||||
foreach (static::$requestTypes as $requestType) {
|
||||
foreach (Request::$requestTypes as $requestType) {
|
||||
|
||||
if (stripos($method, $requestType) === 0) {
|
||||
$method = (string)substr($method, \strlen($requestType));
|
||||
$method = substr($method, strlen($requestType));
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -77,7 +77,7 @@ class RouteController extends LoadableRoute implements IControllerRoute
|
||||
|
||||
$group = $this->getGroup();
|
||||
|
||||
if ($group !== null && \count($group->getDomains()) !== 0) {
|
||||
if ($group !== null && count($group->getDomains()) !== 0) {
|
||||
$url .= '//' . $group->getDomains()[0];
|
||||
}
|
||||
|
||||
@@ -86,9 +86,9 @@ class RouteController extends LoadableRoute implements IControllerRoute
|
||||
return '/' . trim($url, '/') . '/';
|
||||
}
|
||||
|
||||
public function matchRoute($url, Request $request): bool
|
||||
public function matchRoute(string $url, Request $request): bool
|
||||
{
|
||||
if ($this->getGroup() !== null && $this->getGroup()->matchRoute($url, $request) === false) {
|
||||
if ($this->matchGroup($url, $request) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -102,15 +102,15 @@ class RouteController extends LoadableRoute implements IControllerRoute
|
||||
$strippedUrl = trim(str_ireplace($this->url, '/', $url), '/');
|
||||
$path = explode('/', $strippedUrl);
|
||||
|
||||
if (\count($path) !== 0) {
|
||||
if (count($path) !== 0) {
|
||||
|
||||
$method = (isset($path[0]) === false || trim($path[0]) === '') ? $this->defaultMethod : $path[0];
|
||||
$this->method = $request->getMethod() . ucfirst($method);
|
||||
|
||||
$this->parameters = \array_slice($path, 1);
|
||||
$this->parameters = array_slice($path, 1);
|
||||
|
||||
// Set callback
|
||||
$this->setCallback($this->controller . '@' . $this->method);
|
||||
$this->setCallback([$this->controller, $this->method]);
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -167,17 +167,17 @@ class RouteController extends LoadableRoute implements IControllerRoute
|
||||
/**
|
||||
* Merge with information from another route.
|
||||
*
|
||||
* @param array $values
|
||||
* @param array $settings
|
||||
* @param bool $merge
|
||||
* @return static
|
||||
*/
|
||||
public function setSettings(array $values, bool $merge = false): IRoute
|
||||
public function setSettings(array $settings, bool $merge = false): IRoute
|
||||
{
|
||||
if (isset($values['names']) === true) {
|
||||
$this->names = $values['names'];
|
||||
if (isset($settings['names']) === true) {
|
||||
$this->names = $settings['names'];
|
||||
}
|
||||
|
||||
return parent::setSettings($values, $merge);
|
||||
return parent::setSettings($settings, $merge);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -7,10 +7,12 @@ use Pecee\SimpleRouter\Handlers\IExceptionHandler;
|
||||
|
||||
class RouteGroup extends Route implements IGroupRoute
|
||||
{
|
||||
protected $urlRegex = '/^%s\/?/u';
|
||||
protected $prefix;
|
||||
protected $name;
|
||||
protected $domains = [];
|
||||
protected $exceptionHandlers = [];
|
||||
protected $mergeExceptionHandlers = true;
|
||||
|
||||
/**
|
||||
* Method called to check if a domain matches
|
||||
@@ -20,16 +22,20 @@ class RouteGroup extends Route implements IGroupRoute
|
||||
*/
|
||||
public function matchDomain(Request $request): bool
|
||||
{
|
||||
if ($this->domains === null || \count($this->domains) === 0) {
|
||||
if ($this->domains === null || count($this->domains) === 0) {
|
||||
return true;
|
||||
}
|
||||
|
||||
foreach ($this->domains as $domain) {
|
||||
|
||||
// If domain has no parameters but matches
|
||||
if ($domain === $request->getHost()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$parameters = $this->parseParameters($domain, $request->getHost(), '.*');
|
||||
|
||||
if ($parameters !== null && \count($parameters) !== 0) {
|
||||
|
||||
if ($parameters !== null && count($parameters) !== 0) {
|
||||
$this->parameters = $parameters;
|
||||
|
||||
return true;
|
||||
@@ -46,14 +52,33 @@ class RouteGroup extends Route implements IGroupRoute
|
||||
* @param Request $request
|
||||
* @return bool
|
||||
*/
|
||||
public function matchRoute($url, Request $request): bool
|
||||
public function matchRoute(string $url, Request $request): bool
|
||||
{
|
||||
if ($this->getGroup() !== null && $this->getGroup()->matchRoute($url, $request) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->prefix !== null) {
|
||||
/* Parse parameters from current route */
|
||||
$parameters = $this->parseParameters($this->prefix, $url);
|
||||
|
||||
/* If no custom regular expression or parameters was found on this route, we stop */
|
||||
if ($parameters === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Set the parameters */
|
||||
$this->setParameters($parameters);
|
||||
}
|
||||
|
||||
$parsedPrefix = $this->prefix;
|
||||
|
||||
foreach ($this->getParameters() as $parameter => $value) {
|
||||
$parsedPrefix = str_ireplace('{' . $parameter . '}', $value, $parsedPrefix);
|
||||
}
|
||||
|
||||
/* Skip if prefix doesn't match */
|
||||
if ($this->prefix !== null && stripos($url, $this->prefix) === false) {
|
||||
if ($this->prefix !== null && stripos($url, rtrim($parsedPrefix, '/') . '/') === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -123,13 +148,24 @@ class RouteGroup extends Route implements IGroupRoute
|
||||
* @param string $prefix
|
||||
* @return static
|
||||
*/
|
||||
public function setPrefix($prefix): IGroupRoute
|
||||
public function setPrefix(string $prefix): IGroupRoute
|
||||
{
|
||||
$this->prefix = '/' . trim($prefix, '/');
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepends prefix while ensuring that the url has the correct formatting.
|
||||
*
|
||||
* @param string $url
|
||||
* @return static
|
||||
*/
|
||||
public function prependPrefix(string $url): IGroupRoute
|
||||
{
|
||||
return $this->setPrefix(rtrim($url, '/') . $this->prefix);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set prefix that child-routes will inherit.
|
||||
*
|
||||
@@ -141,30 +177,56 @@ class RouteGroup extends Route implements IGroupRoute
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge with information from another route.
|
||||
* When enabled group will overwrite any existing exception-handlers.
|
||||
*
|
||||
* @param array $values
|
||||
* @param bool $merge
|
||||
* @return static
|
||||
*/
|
||||
public function setSettings(array $values, bool $merge = false): IRoute
|
||||
public function setMergeExceptionHandlers(bool $merge): IGroupRoute
|
||||
{
|
||||
$this->mergeExceptionHandlers = $merge;
|
||||
|
||||
if (isset($values['prefix']) === true) {
|
||||
$this->setPrefix($values['prefix'] . $this->prefix);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if group should overwrite existing exception-handlers.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getMergeExceptionHandlers(): bool
|
||||
{
|
||||
return $this->mergeExceptionHandlers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Merge with information from another route.
|
||||
*
|
||||
* @param array $settings
|
||||
* @param bool $merge
|
||||
* @return static
|
||||
*/
|
||||
public function setSettings(array $settings, bool $merge = false): IRoute
|
||||
{
|
||||
if (isset($settings['prefix']) === true) {
|
||||
$this->setPrefix($settings['prefix'] . $this->prefix);
|
||||
}
|
||||
|
||||
if ($merge === false && isset($values['exceptionHandler']) === true) {
|
||||
$this->setExceptionHandlers((array)$values['exceptionHandler']);
|
||||
if (isset($settings['mergeExceptionHandlers']) === true) {
|
||||
$this->setMergeExceptionHandlers($settings['mergeExceptionHandlers']);
|
||||
}
|
||||
|
||||
if ($merge === false && isset($values['domain']) === true) {
|
||||
$this->setDomains((array)$values['domain']);
|
||||
if ($merge === false && isset($settings['exceptionHandler']) === true) {
|
||||
$this->setExceptionHandlers((array)$settings['exceptionHandler']);
|
||||
}
|
||||
|
||||
if (isset($values['as']) === true) {
|
||||
if ($merge === false && isset($settings['domain']) === true) {
|
||||
$this->setDomains((array)$settings['domain']);
|
||||
}
|
||||
|
||||
$name = $values['as'];
|
||||
if (isset($settings['as']) === true) {
|
||||
|
||||
$name = $settings['as'];
|
||||
|
||||
if ($this->name !== null && $merge !== false) {
|
||||
$name .= '.' . $this->name;
|
||||
@@ -173,7 +235,7 @@ class RouteGroup extends Route implements IGroupRoute
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
return parent::setSettings($values, $merge);
|
||||
return parent::setSettings($settings, $merge);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -193,7 +255,7 @@ class RouteGroup extends Route implements IGroupRoute
|
||||
$values['as'] = $this->name;
|
||||
}
|
||||
|
||||
if (\count($this->parameters) !== 0) {
|
||||
if (count($this->parameters) !== 0) {
|
||||
$values['parameters'] = $this->parameters;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,47 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Pecee\SimpleRouter\Route;
|
||||
|
||||
use Pecee\Http\Request;
|
||||
|
||||
class RoutePartialGroup extends RouteGroup implements IPartialGroupRoute
|
||||
{
|
||||
|
||||
/**
|
||||
* RoutePartialGroup constructor.
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
$this->urlRegex = '/^%s\/?/u';
|
||||
}
|
||||
|
||||
/**
|
||||
* Method called to check if route matches
|
||||
*
|
||||
* @param string $url
|
||||
* @param Request $request
|
||||
* @return bool
|
||||
*/
|
||||
public function matchRoute($url, Request $request): bool
|
||||
{
|
||||
if ($this->getGroup() !== null && $this->getGroup()->matchRoute($url, $request) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if ($this->prefix !== null) {
|
||||
/* Parse parameters from current route */
|
||||
$parameters = $this->parseParameters($this->prefix, $url);
|
||||
|
||||
/* If no custom regular expression or parameters was found on this route, we stop */
|
||||
if ($parameters === null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Set the parameters */
|
||||
$this->setParameters((array)$parameters);
|
||||
}
|
||||
|
||||
return $this->matchDomain($request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -54,7 +54,7 @@ class RouteResource extends LoadableRoute implements IControllerRoute
|
||||
|
||||
/* Remove method/type */
|
||||
if (strpos($name, '.') !== false) {
|
||||
$name = (string)substr($name, 0, strrpos($name, '.'));
|
||||
$name = substr($name, 0, strrpos($name, '.'));
|
||||
}
|
||||
|
||||
return (strtolower($this->name) === strtolower($name));
|
||||
@@ -68,7 +68,7 @@ class RouteResource extends LoadableRoute implements IControllerRoute
|
||||
*/
|
||||
public function findUrl(?string $method = null, $parameters = null, ?string $name = null): string
|
||||
{
|
||||
$url = array_search($name, $this->names, false);
|
||||
$url = array_search($name, $this->names, true);
|
||||
if ($url !== false) {
|
||||
return rtrim($this->url . $this->urls[$url], '/') . '/';
|
||||
}
|
||||
@@ -76,16 +76,16 @@ class RouteResource extends LoadableRoute implements IControllerRoute
|
||||
return $this->url;
|
||||
}
|
||||
|
||||
protected function call($method)
|
||||
protected function call($method): bool
|
||||
{
|
||||
$this->setCallback($this->controller . '@' . $method);
|
||||
$this->setCallback([$this->controller, $method]);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function matchRoute($url, Request $request): bool
|
||||
public function matchRoute(string $url, Request $request): bool
|
||||
{
|
||||
if ($this->getGroup() !== null && $this->getGroup()->matchRoute($url, $request) === false) {
|
||||
if ($this->matchGroup($url, $request) === false) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -115,32 +115,32 @@ class RouteResource extends LoadableRoute implements IControllerRoute
|
||||
$method = $request->getMethod();
|
||||
|
||||
// Delete
|
||||
if ($method === static::REQUEST_TYPE_DELETE && $id !== null) {
|
||||
if ($method === Request::REQUEST_TYPE_DELETE && $id !== null) {
|
||||
return $this->call($this->methodNames['destroy']);
|
||||
}
|
||||
|
||||
// Update
|
||||
if ($id !== null && \in_array($method, [static::REQUEST_TYPE_PATCH, static::REQUEST_TYPE_PUT], true) === true) {
|
||||
if ($id !== null && in_array($method, [Request::REQUEST_TYPE_PATCH, Request::REQUEST_TYPE_PUT], true) === true) {
|
||||
return $this->call($this->methodNames['update']);
|
||||
}
|
||||
|
||||
// Edit
|
||||
if ($method === static::REQUEST_TYPE_GET && $id !== null && $action === 'edit') {
|
||||
if ($method === Request::REQUEST_TYPE_GET && $id !== null && $action === 'edit') {
|
||||
return $this->call($this->methodNames['edit']);
|
||||
}
|
||||
|
||||
// Create
|
||||
if ($method === static::REQUEST_TYPE_GET && $id === 'create') {
|
||||
if ($method === Request::REQUEST_TYPE_GET && $id === 'create') {
|
||||
return $this->call($this->methodNames['create']);
|
||||
}
|
||||
|
||||
// Save
|
||||
if ($method === static::REQUEST_TYPE_POST) {
|
||||
if ($method === Request::REQUEST_TYPE_POST) {
|
||||
return $this->call($this->methodNames['store']);
|
||||
}
|
||||
|
||||
// Show
|
||||
if ($method === static::REQUEST_TYPE_GET && $id !== null) {
|
||||
if ($method === Request::REQUEST_TYPE_GET && $id !== null) {
|
||||
return $this->call($this->methodNames['show']);
|
||||
}
|
||||
|
||||
@@ -190,7 +190,7 @@ class RouteResource extends LoadableRoute implements IControllerRoute
|
||||
* @param array $names
|
||||
* @return static $this
|
||||
*/
|
||||
public function setMethodNames(array $names)
|
||||
public function setMethodNames(array $names): RouteResource
|
||||
{
|
||||
$this->methodNames = $names;
|
||||
|
||||
@@ -210,21 +210,21 @@ class RouteResource extends LoadableRoute implements IControllerRoute
|
||||
/**
|
||||
* Merge with information from another route.
|
||||
*
|
||||
* @param array $values
|
||||
* @param array $settings
|
||||
* @param bool $merge
|
||||
* @return static
|
||||
*/
|
||||
public function setSettings(array $values, bool $merge = false): IRoute
|
||||
public function setSettings(array $settings, bool $merge = false): IRoute
|
||||
{
|
||||
if (isset($values['names']) === true) {
|
||||
$this->names = $values['names'];
|
||||
if (isset($settings['names']) === true) {
|
||||
$this->names = $settings['names'];
|
||||
}
|
||||
|
||||
if (isset($values['methods']) === true) {
|
||||
$this->methodNames = $values['methods'];
|
||||
if (isset($settings['methods']) === true) {
|
||||
$this->methodNames = $settings['methods'];
|
||||
}
|
||||
|
||||
return parent::setSettings($values, $merge);
|
||||
return parent::setSettings($settings, $merge);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,13 +6,18 @@ use Pecee\Http\Request;
|
||||
|
||||
class RouteUrl extends LoadableRoute
|
||||
{
|
||||
public function __construct($url, $callback)
|
||||
/**
|
||||
* RouteUrl constructor.
|
||||
* @param string $url
|
||||
* @param \Closure|string $callback
|
||||
*/
|
||||
public function __construct(string $url, $callback)
|
||||
{
|
||||
$this->setUrl($url);
|
||||
$this->setCallback($callback);
|
||||
}
|
||||
|
||||
public function matchRoute($url, Request $request): bool
|
||||
public function matchRoute(string $url, Request $request): bool
|
||||
{
|
||||
if ($this->getGroup() !== null && $this->getGroup()->matchRoute($url, $request) === false) {
|
||||
return false;
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace Pecee\SimpleRouter;
|
||||
|
||||
use Exception;
|
||||
use Pecee\Exceptions\InvalidArgumentException;
|
||||
use Pecee\Http\Exceptions\MalformedUrlException;
|
||||
use Pecee\Http\Middleware\BaseCsrfVerifier;
|
||||
@@ -43,7 +44,7 @@ class Router
|
||||
|
||||
/**
|
||||
* List of processed routes
|
||||
* @var array
|
||||
* @var array|ILoadableRoute[]
|
||||
*/
|
||||
protected $processedRoutes = [];
|
||||
|
||||
@@ -62,7 +63,7 @@ class Router
|
||||
|
||||
/**
|
||||
* Csrf verifier class
|
||||
* @var BaseCsrfVerifier
|
||||
* @var BaseCsrfVerifier|null
|
||||
*/
|
||||
protected $csrfVerifier;
|
||||
|
||||
@@ -106,10 +107,17 @@ class Router
|
||||
|
||||
/**
|
||||
* Class loader instance
|
||||
* @var ClassLoader
|
||||
* @var IClassLoader
|
||||
*/
|
||||
protected $classLoader;
|
||||
|
||||
/**
|
||||
* When enabled the router will render all routes that matches.
|
||||
* When disabled the router will stop execution when first route is found.
|
||||
* @var bool
|
||||
*/
|
||||
protected $renderMultipleRoutes = true;
|
||||
|
||||
/**
|
||||
* Router constructor.
|
||||
*/
|
||||
@@ -152,7 +160,8 @@ class Router
|
||||
public function addRoute(IRoute $route): IRoute
|
||||
{
|
||||
$this->fireEvents(EventHandler::EVENT_ADD_ROUTE, [
|
||||
'route' => $route,
|
||||
'route' => $route,
|
||||
'isSubRoute' => $this->isProcessingRoute,
|
||||
]);
|
||||
|
||||
/*
|
||||
@@ -176,26 +185,25 @@ class Router
|
||||
*/
|
||||
protected function renderAndProcess(IRoute $route): void
|
||||
{
|
||||
|
||||
$this->isProcessingRoute = true;
|
||||
$route->renderRoute($this->request, $this);
|
||||
$this->isProcessingRoute = false;
|
||||
|
||||
if (\count($this->routeStack) !== 0) {
|
||||
if (count($this->routeStack) !== 0) {
|
||||
|
||||
/* Pop and grab the routes added when executing group callback earlier */
|
||||
$stack = $this->routeStack;
|
||||
$this->routeStack = [];
|
||||
|
||||
/* Route any routes added to the stack */
|
||||
$this->processRoutes($stack, $route);
|
||||
$this->processRoutes($stack, ($route instanceof IGroupRoute) ? $route : null);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Process added routes.
|
||||
*
|
||||
* @param array $routes
|
||||
* @param array|IRoute[] $routes
|
||||
* @param IGroupRoute|null $group
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
@@ -203,11 +211,8 @@ class Router
|
||||
{
|
||||
$this->debug('Processing routes');
|
||||
|
||||
// Loop through each route-request
|
||||
$exceptionHandlers = [];
|
||||
|
||||
// Stop processing routes if no valid route is found.
|
||||
if ($this->request->getRewriteRoute() === null && $this->request->getUrl() === null) {
|
||||
if ($this->request->getRewriteRoute() === null && $this->request->getUrl()->getOriginalUrl() === '') {
|
||||
$this->debug('Halted route-processing as no valid route was found');
|
||||
|
||||
return;
|
||||
@@ -215,10 +220,10 @@ class Router
|
||||
|
||||
$url = $this->request->getRewriteUrl() ?? $this->request->getUrl()->getPath();
|
||||
|
||||
/* @var $route IRoute */
|
||||
// Loop through each route-request
|
||||
foreach ($routes as $route) {
|
||||
|
||||
$this->debug('Processing route "%s"', \get_class($route));
|
||||
$this->debug('Processing route "%s"', get_class($route));
|
||||
|
||||
if ($group !== null) {
|
||||
/* Add the parent group */
|
||||
@@ -231,14 +236,23 @@ class Router
|
||||
if ($route->matchRoute($url, $this->request) === true) {
|
||||
|
||||
/* Add exception handlers */
|
||||
if (\count($route->getExceptionHandlers()) !== 0) {
|
||||
/** @noinspection AdditionOperationOnArraysInspection */
|
||||
$exceptionHandlers += $route->getExceptionHandlers();
|
||||
if (count($route->getExceptionHandlers()) !== 0) {
|
||||
|
||||
if ($route->getMergeExceptionHandlers() === true) {
|
||||
|
||||
foreach ($route->getExceptionHandlers() as $handler) {
|
||||
$this->exceptionHandlers[] = $handler;
|
||||
}
|
||||
|
||||
} else {
|
||||
$this->exceptionHandlers = $route->getExceptionHandlers();
|
||||
}
|
||||
}
|
||||
|
||||
/* Only render partial group if it matches */
|
||||
if ($route instanceof IPartialGroupRoute === true) {
|
||||
$this->renderAndProcess($route);
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -256,19 +270,24 @@ class Router
|
||||
$this->processedRoutes[] = $route;
|
||||
}
|
||||
}
|
||||
|
||||
$this->exceptionHandlers = array_merge($exceptionHandlers, $this->exceptionHandlers);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load routes
|
||||
* @throws NotFoundHttpException
|
||||
* @return void
|
||||
* @throws NotFoundHttpException
|
||||
*/
|
||||
public function loadRoutes(): void
|
||||
{
|
||||
$this->debug('Loading routes');
|
||||
|
||||
$this->fireEvents(EventHandler::EVENT_LOAD_ROUTES, [
|
||||
'routes' => $this->routes,
|
||||
]);
|
||||
|
||||
/* Loop through each route-request */
|
||||
$this->processRoutes($this->routes);
|
||||
|
||||
$this->fireEvents(EventHandler::EVENT_BOOT, [
|
||||
'bootmanagers' => $this->bootManagers,
|
||||
]);
|
||||
@@ -278,7 +297,7 @@ class Router
|
||||
/* @var $manager IRouterBootManager */
|
||||
foreach ($this->bootManagers as $manager) {
|
||||
|
||||
$className = \get_class($manager);
|
||||
$className = get_class($manager);
|
||||
$this->debug('Rendering bootmanager "%s"', $className);
|
||||
$this->fireEvents(EventHandler::EVENT_RENDER_BOOTMANAGER, [
|
||||
'bootmanagers' => $this->bootManagers,
|
||||
@@ -291,13 +310,6 @@ class Router
|
||||
$this->debug('Finished rendering bootmanager "%s"', $className);
|
||||
}
|
||||
|
||||
$this->fireEvents(EventHandler::EVENT_LOAD_ROUTES, [
|
||||
'routes' => $this->routes,
|
||||
]);
|
||||
|
||||
/* Loop through each route-request */
|
||||
$this->processRoutes($this->routes);
|
||||
|
||||
$this->debug('Finished loading routes');
|
||||
}
|
||||
|
||||
@@ -305,10 +317,10 @@ class Router
|
||||
* Start the routing
|
||||
*
|
||||
* @return string|null
|
||||
* @throws \Pecee\SimpleRouter\Exceptions\NotFoundHttpException
|
||||
* @throws NotFoundHttpException
|
||||
* @throws \Pecee\Http\Middleware\Exceptions\TokenMismatchException
|
||||
* @throws HttpException
|
||||
* @throws \Exception
|
||||
* @throws Exception
|
||||
*/
|
||||
public function start(): ?string
|
||||
{
|
||||
@@ -344,13 +356,13 @@ class Router
|
||||
*
|
||||
* @return string|null
|
||||
* @throws HttpException
|
||||
* @throws \Exception
|
||||
* @throws Exception
|
||||
*/
|
||||
public function routeRequest(): ?string
|
||||
{
|
||||
$this->debug('Routing request');
|
||||
|
||||
$methodNotAllowed = false;
|
||||
$methodNotAllowed = null;
|
||||
|
||||
try {
|
||||
$url = $this->request->getRewriteUrl() ?? $this->request->getUrl()->getPath();
|
||||
@@ -358,7 +370,7 @@ class Router
|
||||
/* @var $route ILoadableRoute */
|
||||
foreach ($this->processedRoutes as $key => $route) {
|
||||
|
||||
$this->debug('Matching route "%s"', \get_class($route));
|
||||
$this->debug('Matching route "%s"', get_class($route));
|
||||
|
||||
/* If the route matches */
|
||||
if ($route->matchRoute($url, $this->request) === true) {
|
||||
@@ -368,9 +380,14 @@ class Router
|
||||
]);
|
||||
|
||||
/* Check if request method matches */
|
||||
if (\count($route->getRequestMethods()) !== 0 && \in_array($this->request->getMethod(), $route->getRequestMethods(), true) === false) {
|
||||
if (count($route->getRequestMethods()) !== 0 && in_array($this->request->getMethod(), $route->getRequestMethods(), true) === false) {
|
||||
$this->debug('Method "%s" not allowed', $this->request->getMethod());
|
||||
$methodNotAllowed = true;
|
||||
|
||||
// Only set method not allowed is not already set
|
||||
if ($methodNotAllowed === null) {
|
||||
$methodNotAllowed = true;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -394,28 +411,35 @@ class Router
|
||||
'route' => $route,
|
||||
]);
|
||||
|
||||
$output = $route->renderRoute($this->request, $this);
|
||||
if ($output !== null) {
|
||||
return $output;
|
||||
}
|
||||
$routeOutput = $route->renderRoute($this->request, $this);
|
||||
|
||||
$output = $this->handleRouteRewrite($key, $url);
|
||||
if ($output !== null) {
|
||||
return $output;
|
||||
if ($this->renderMultipleRoutes === true) {
|
||||
if ($routeOutput !== null) {
|
||||
return $routeOutput;
|
||||
}
|
||||
|
||||
$output = $this->handleRouteRewrite($key, $url);
|
||||
if ($output !== null) {
|
||||
return $output;
|
||||
}
|
||||
} else {
|
||||
$output = $this->handleRouteRewrite($key, $url);
|
||||
|
||||
return $output ?? $routeOutput;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
$this->handleException($e);
|
||||
}
|
||||
|
||||
if ($methodNotAllowed === true) {
|
||||
$message = sprintf('Route "%s" or method "%s" not allowed.', $this->request->getUrl()->getPath(), $this->request->getMethod());
|
||||
$this->handleException(new HttpException($message, 403));
|
||||
$this->handleException(new NotFoundHttpException($message, 403));
|
||||
}
|
||||
|
||||
if (\count($this->request->getLoadedRoutes()) === 0) {
|
||||
if (count($this->request->getLoadedRoutes()) === 0) {
|
||||
|
||||
$rewriteUrl = $this->request->getRewriteUrl();
|
||||
|
||||
@@ -440,9 +464,9 @@ class Router
|
||||
* @param string $url
|
||||
* @return string|null
|
||||
* @throws HttpException
|
||||
* @throws \Exception
|
||||
* @throws Exception
|
||||
*/
|
||||
protected function handleRouteRewrite($key, string $url): ?string
|
||||
protected function handleRouteRewrite(string $key, string $url): ?string
|
||||
{
|
||||
/* If the request has changed */
|
||||
if ($this->request->hasPendingRewrite() === false) {
|
||||
@@ -457,7 +481,9 @@ class Router
|
||||
}
|
||||
|
||||
if ($this->request->getRewriteUrl() !== $url) {
|
||||
|
||||
unset($this->processedRoutes[$key]);
|
||||
|
||||
$this->request->setHasPendingRewrite(false);
|
||||
|
||||
$this->fireEvents(EventHandler::EVENT_REWRITE, [
|
||||
@@ -472,14 +498,14 @@ class Router
|
||||
}
|
||||
|
||||
/**
|
||||
* @param \Exception $e
|
||||
* @throws HttpException
|
||||
* @throws \Exception
|
||||
* @param Exception $e
|
||||
* @return string|null
|
||||
* @throws Exception
|
||||
* @throws HttpException
|
||||
*/
|
||||
protected function handleException(\Exception $e): ?string
|
||||
protected function handleException(Exception $e): ?string
|
||||
{
|
||||
$this->debug('Starting exception handling for "%s"', \get_class($e));
|
||||
$this->debug('Starting exception handling for "%s"', get_class($e));
|
||||
|
||||
$this->fireEvents(EventHandler::EVENT_LOAD_EXCEPTIONS, [
|
||||
'exception' => $e,
|
||||
@@ -487,9 +513,9 @@ class Router
|
||||
]);
|
||||
|
||||
/* @var $handler IExceptionHandler */
|
||||
foreach ($this->exceptionHandlers as $key => $handler) {
|
||||
foreach (array_reverse($this->exceptionHandlers) as $key => $handler) {
|
||||
|
||||
if (\is_object($handler) === false) {
|
||||
if (is_object($handler) === false) {
|
||||
$handler = new $handler();
|
||||
}
|
||||
|
||||
@@ -499,7 +525,7 @@ class Router
|
||||
'exceptionHandlers' => $this->exceptionHandlers,
|
||||
]);
|
||||
|
||||
$this->debug('Processing exception-handler "%s"', \get_class($handler));
|
||||
$this->debug('Processing exception-handler "%s"', get_class($handler));
|
||||
|
||||
if (($handler instanceof IExceptionHandler) === false) {
|
||||
throw new HttpException('Exception handler must implement the IExceptionHandler interface.', 500);
|
||||
@@ -528,7 +554,7 @@ class Router
|
||||
return $this->routeRequest();
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
|
||||
}
|
||||
|
||||
@@ -553,7 +579,6 @@ class Router
|
||||
'name' => $name,
|
||||
]);
|
||||
|
||||
/* @var $route ILoadableRoute */
|
||||
foreach ($this->processedRoutes as $route) {
|
||||
|
||||
/* Check if the name matches with a name on the route. Should match either router alias or controller alias. */
|
||||
@@ -571,7 +596,7 @@ class Router
|
||||
}
|
||||
|
||||
/* Using @ is most definitely a controller@method or alias@method */
|
||||
if (\is_string($name) === true && strpos($name, '@') !== false) {
|
||||
if (strpos($name, '@') !== false) {
|
||||
[$controller, $method] = array_map('strtolower', explode('@', $name));
|
||||
|
||||
if ($controller === strtolower($route->getClass()) && $method === strtolower($route->getMethod())) {
|
||||
@@ -583,7 +608,7 @@ class Router
|
||||
|
||||
/* Check if callback matches (if it's not a function) */
|
||||
$callback = $route->getCallback();
|
||||
if (\is_string($name) === true && \is_string($callback) === true && strpos($name, '@') !== false && strpos($callback, '@') !== false && \is_callable($callback) === false) {
|
||||
if (is_string($callback) === true && is_callable($callback) === false && strpos($name, '@') !== false && strpos($callback, '@') !== false) {
|
||||
|
||||
/* Check if the entire callback is matching */
|
||||
if (strpos($callback, $name) === 0 || strtolower($callback) === strtolower($name)) {
|
||||
@@ -623,11 +648,10 @@ class Router
|
||||
* @param array|null $getParams
|
||||
* @return Url
|
||||
* @throws InvalidArgumentException
|
||||
* @throws \Pecee\Http\Exceptions\MalformedUrlException
|
||||
*/
|
||||
public function getUrl(?string $name = null, $parameters = null, ?array $getParams = null): Url
|
||||
{
|
||||
$this->debug('Finding url', \func_get_args());
|
||||
$this->debug('Finding url', func_get_args());
|
||||
|
||||
$this->fireEvents(EventHandler::EVENT_GET_URL, [
|
||||
'name' => $name,
|
||||
@@ -635,20 +659,12 @@ class Router
|
||||
'getParams' => $getParams,
|
||||
]);
|
||||
|
||||
if ($getParams !== null && \is_array($getParams) === false) {
|
||||
throw new InvalidArgumentException('Invalid type for getParams. Must be array or null');
|
||||
}
|
||||
|
||||
if ($name === '' && $parameters === '') {
|
||||
return new Url('/');
|
||||
}
|
||||
|
||||
/* Only merge $_GET when all parameters are null */
|
||||
if ($name === null && $parameters === null && $getParams === null) {
|
||||
$getParams = $_GET;
|
||||
} else {
|
||||
$getParams = (array)$getParams;
|
||||
}
|
||||
$getParams = ($name === null && $parameters === null && $getParams === null) ? $_GET : (array)$getParams;
|
||||
|
||||
/* Return current route if no options has been specified */
|
||||
if ($name === null && $parameters === null) {
|
||||
@@ -667,38 +683,40 @@ class Router
|
||||
->setParams($getParams);
|
||||
}
|
||||
|
||||
/* We try to find a match on the given name */
|
||||
$route = $this->findRoute($name);
|
||||
if ($name !== null) {
|
||||
/* We try to find a match on the given name */
|
||||
$route = $this->findRoute($name);
|
||||
|
||||
if ($route !== null) {
|
||||
return $this->request
|
||||
->getUrlCopy()
|
||||
->setPath($route->findUrl($route->getMethod(), $parameters, $name))
|
||||
->setParams($getParams);
|
||||
if ($route !== null) {
|
||||
return $this->request
|
||||
->getUrlCopy()
|
||||
->setPath($route->findUrl($route->getMethod(), $parameters, $name))
|
||||
->setParams($getParams);
|
||||
}
|
||||
}
|
||||
|
||||
/* Using @ is most definitely a controller@method or alias@method */
|
||||
if (\is_string($name) === true && strpos($name, '@') !== false) {
|
||||
if (is_string($name) === true && strpos($name, '@') !== false) {
|
||||
[$controller, $method] = explode('@', $name);
|
||||
|
||||
/* Loop through all the routes to see if we can find a match */
|
||||
|
||||
/* @var $route ILoadableRoute */
|
||||
foreach ($this->processedRoutes as $route) {
|
||||
foreach ($this->processedRoutes as $processedRoute) {
|
||||
|
||||
/* Check if the route contains the name/alias */
|
||||
if ($route->hasName($controller) === true) {
|
||||
if ($processedRoute->hasName($controller) === true) {
|
||||
return $this->request
|
||||
->getUrlCopy()
|
||||
->setPath($route->findUrl($method, $parameters, $name))
|
||||
->setPath($processedRoute->findUrl($method, $parameters, $name))
|
||||
->setParams($getParams);
|
||||
}
|
||||
|
||||
/* Check if the route controller is equal to the name */
|
||||
if ($route instanceof IControllerRoute && strtolower($route->getController()) === strtolower($controller)) {
|
||||
if ($processedRoute instanceof IControllerRoute && strtolower($processedRoute->getController()) === strtolower($controller)) {
|
||||
return $this->request
|
||||
->getUrlCopy()
|
||||
->setPath($route->findUrl($method, $parameters, $name))
|
||||
->setPath($processedRoute->findUrl($method, $parameters, $name))
|
||||
->setParams($getParams);
|
||||
}
|
||||
|
||||
@@ -823,7 +841,7 @@ class Router
|
||||
/**
|
||||
* Get class loader
|
||||
*
|
||||
* @return ClassLoader
|
||||
* @return IClassLoader
|
||||
*/
|
||||
public function getClassLoader(): IClassLoader
|
||||
{
|
||||
@@ -856,9 +874,9 @@ class Router
|
||||
* @param string $name
|
||||
* @param array $arguments
|
||||
*/
|
||||
protected function fireEvents($name, array $arguments = []): void
|
||||
protected function fireEvents(string $name, array $arguments = []): void
|
||||
{
|
||||
if (\count($this->eventHandlers) === 0) {
|
||||
if (count($this->eventHandlers) === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -910,4 +928,26 @@ class Router
|
||||
return $this->debugList;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the rendering behavior of the router.
|
||||
* When enabled the router will render all routes that matches.
|
||||
* When disabled the router will stop rendering at the first route that matches.
|
||||
*
|
||||
* @param bool $bool
|
||||
* @return $this
|
||||
*/
|
||||
public function setRenderMultipleRoutes(bool $bool): self
|
||||
{
|
||||
$this->renderMultipleRoutes = $bool;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function addExceptionHandler(IExceptionHandler $handler): self
|
||||
{
|
||||
$this->exceptionHandlers[] = $handler;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,15 +4,15 @@
|
||||
* Router helper class
|
||||
* ---------------------------
|
||||
*
|
||||
* This class is added so calls can be made statically like Router::get() making the code look pretty.
|
||||
* It also adds some extra functionality like default-namespace.
|
||||
* This class is added so calls can be made statically like SimpleRouter::get() making the code look pretty.
|
||||
* It also adds some extra functionality like default-namespace etc.
|
||||
*/
|
||||
|
||||
namespace Pecee\SimpleRouter;
|
||||
|
||||
use DI\Container;
|
||||
use Closure;
|
||||
use Exception;
|
||||
use Pecee\Exceptions\InvalidArgumentException;
|
||||
use Pecee\Http\Exceptions\MalformedUrlException;
|
||||
use Pecee\Http\Middleware\BaseCsrfVerifier;
|
||||
use Pecee\Http\Request;
|
||||
use Pecee\Http\Response;
|
||||
@@ -22,9 +22,9 @@ use Pecee\SimpleRouter\Exceptions\HttpException;
|
||||
use Pecee\SimpleRouter\Handlers\CallbackExceptionHandler;
|
||||
use Pecee\SimpleRouter\Handlers\IEventHandler;
|
||||
use Pecee\SimpleRouter\Route\IGroupRoute;
|
||||
use Pecee\SimpleRouter\Route\ILoadableRoute;
|
||||
use Pecee\SimpleRouter\Route\IPartialGroupRoute;
|
||||
use Pecee\SimpleRouter\Route\IRoute;
|
||||
use Pecee\SimpleRouter\Route\Route;
|
||||
use Pecee\SimpleRouter\Route\RouteController;
|
||||
use Pecee\SimpleRouter\Route\RouteGroup;
|
||||
use Pecee\SimpleRouter\Route\RoutePartialGroup;
|
||||
@@ -57,10 +57,15 @@ class SimpleRouter
|
||||
* @throws \Pecee\SimpleRouter\Exceptions\NotFoundHttpException
|
||||
* @throws \Pecee\Http\Middleware\Exceptions\TokenMismatchException
|
||||
* @throws HttpException
|
||||
* @throws \Exception
|
||||
* @throws Exception
|
||||
*/
|
||||
public static function start(): void
|
||||
{
|
||||
// Set default namespaces
|
||||
foreach (static::router()->getRoutes() as $route) {
|
||||
static::addDefaultNamespace($route);
|
||||
}
|
||||
|
||||
echo static::router()->start();
|
||||
}
|
||||
|
||||
@@ -75,22 +80,20 @@ class SimpleRouter
|
||||
|
||||
try {
|
||||
ob_start();
|
||||
static::router()->setDebugEnabled(true);
|
||||
static::start();
|
||||
$routerOutput = ob_get_contents();
|
||||
ob_end_clean();
|
||||
} catch (\Exception $e) {
|
||||
static::router()->setDebugEnabled(true)->start();
|
||||
$routerOutput = ob_get_clean();
|
||||
} catch (Exception $e) {
|
||||
|
||||
}
|
||||
|
||||
// Try to parse library version
|
||||
$composerFile = \dirname(__DIR__, 3) . '/composer.lock';
|
||||
$composerFile = dirname(__DIR__, 3) . '/composer.lock';
|
||||
$version = false;
|
||||
|
||||
if (is_file($composerFile) === true) {
|
||||
$composerInfo = json_decode(file_get_contents($composerFile), true);
|
||||
|
||||
if (isset($composerInfo['packages']) === true && \is_array($composerInfo['packages']) === true) {
|
||||
if (isset($composerInfo['packages']) === true && is_array($composerInfo['packages']) === true) {
|
||||
foreach ($composerInfo['packages'] as $package) {
|
||||
if (isset($package['name']) === true && strtolower($package['name']) === 'pecee/simple-router') {
|
||||
$version = $package['version'];
|
||||
@@ -169,9 +172,9 @@ class SimpleRouter
|
||||
* @param int $httpCode
|
||||
* @return IRoute
|
||||
*/
|
||||
public static function redirect($where, $to, $httpCode = 301): IRoute
|
||||
public static function redirect(string $where, string $to, int $httpCode = 301): IRoute
|
||||
{
|
||||
return static::get($where, function () use ($to, $httpCode) {
|
||||
return static::get($where, static function () use ($to, $httpCode): void {
|
||||
static::response()->redirect($to, $httpCode);
|
||||
});
|
||||
}
|
||||
@@ -180,95 +183,91 @@ class SimpleRouter
|
||||
* Route the given url to your callback on GET request method.
|
||||
*
|
||||
* @param string $url
|
||||
* @param string|\Closure $callback
|
||||
* @param string|array|Closure $callback
|
||||
* @param array|null $settings
|
||||
*
|
||||
* @return RouteUrl
|
||||
* @return RouteUrl|IRoute
|
||||
*/
|
||||
public static function get(string $url, $callback, array $settings = null): IRoute
|
||||
{
|
||||
return static::match([Route::REQUEST_TYPE_GET], $url, $callback, $settings);
|
||||
return static::match([Request::REQUEST_TYPE_GET], $url, $callback, $settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Route the given url to your callback on POST request method.
|
||||
*
|
||||
* @param string $url
|
||||
* @param string|\Closure $callback
|
||||
* @param string|array|Closure $callback
|
||||
* @param array|null $settings
|
||||
* @return RouteUrl
|
||||
* @return RouteUrl|IRoute
|
||||
*/
|
||||
public static function post(string $url, $callback, array $settings = null): IRoute
|
||||
{
|
||||
return static::match([Route::REQUEST_TYPE_POST], $url, $callback, $settings);
|
||||
return static::match([Request::REQUEST_TYPE_POST], $url, $callback, $settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Route the given url to your callback on PUT request method.
|
||||
*
|
||||
* @param string $url
|
||||
* @param string|\Closure $callback
|
||||
* @param string|array|Closure $callback
|
||||
* @param array|null $settings
|
||||
* @return RouteUrl
|
||||
* @return RouteUrl|IRoute
|
||||
*/
|
||||
public static function put(string $url, $callback, array $settings = null): IRoute
|
||||
{
|
||||
return static::match([Route::REQUEST_TYPE_PUT], $url, $callback, $settings);
|
||||
return static::match([Request::REQUEST_TYPE_PUT], $url, $callback, $settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Route the given url to your callback on PATCH request method.
|
||||
*
|
||||
* @param string $url
|
||||
* @param string|\Closure $callback
|
||||
* @param string|array|Closure $callback
|
||||
* @param array|null $settings
|
||||
* @return RouteUrl
|
||||
* @return RouteUrl|IRoute
|
||||
*/
|
||||
public static function patch(string $url, $callback, array $settings = null): IRoute
|
||||
{
|
||||
return static::match([Route::REQUEST_TYPE_PATCH], $url, $callback, $settings);
|
||||
return static::match([Request::REQUEST_TYPE_PATCH], $url, $callback, $settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Route the given url to your callback on OPTIONS request method.
|
||||
*
|
||||
* @param string $url
|
||||
* @param string|\Closure $callback
|
||||
* @param string|array|Closure $callback
|
||||
* @param array|null $settings
|
||||
* @return RouteUrl
|
||||
* @return RouteUrl|IRoute
|
||||
*/
|
||||
public static function options(string $url, $callback, array $settings = null): IRoute
|
||||
{
|
||||
return static::match([Route::REQUEST_TYPE_OPTIONS], $url, $callback, $settings);
|
||||
return static::match([Request::REQUEST_TYPE_OPTIONS], $url, $callback, $settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Route the given url to your callback on DELETE request method.
|
||||
*
|
||||
* @param string $url
|
||||
* @param string|\Closure $callback
|
||||
* @param string|array|Closure $callback
|
||||
* @param array|null $settings
|
||||
* @return RouteUrl
|
||||
* @return RouteUrl|IRoute
|
||||
*/
|
||||
public static function delete(string $url, $callback, array $settings = null): IRoute
|
||||
{
|
||||
return static::match(['delete'], $url, $callback, $settings);
|
||||
return static::match([Request::REQUEST_TYPE_DELETE], $url, $callback, $settings);
|
||||
}
|
||||
|
||||
/**
|
||||
* Groups allows for encapsulating routes with special settings.
|
||||
*
|
||||
* @param array $settings
|
||||
* @param \Closure $callback
|
||||
* @return RouteGroup
|
||||
* @param Closure $callback
|
||||
* @return RouteGroup|IGroupRoute
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public static function group(array $settings = [], \Closure $callback): IGroupRoute
|
||||
public static function group(array $settings, Closure $callback): IGroupRoute
|
||||
{
|
||||
if (\is_callable($callback) === false) {
|
||||
throw new InvalidArgumentException('Invalid callback provided. Only functions or methods supported');
|
||||
}
|
||||
|
||||
$group = new RouteGroup();
|
||||
$group->setCallback($callback);
|
||||
$group->setSettings($settings);
|
||||
@@ -283,17 +282,13 @@ class SimpleRouter
|
||||
* parameters and which are only rendered when the url matches.
|
||||
*
|
||||
* @param string $url
|
||||
* @param \Closure $callback
|
||||
* @param Closure $callback
|
||||
* @param array $settings
|
||||
* @return RoutePartialGroup
|
||||
* @return RoutePartialGroup|IPartialGroupRoute
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public static function partialGroup(string $url, \Closure $callback, array $settings = []): IPartialGroupRoute
|
||||
public static function partialGroup(string $url, Closure $callback, array $settings = []): IPartialGroupRoute
|
||||
{
|
||||
if (\is_callable($callback) === false) {
|
||||
throw new InvalidArgumentException('Invalid callback provided. Only functions or methods supported');
|
||||
}
|
||||
|
||||
$settings['prefix'] = $url;
|
||||
|
||||
$group = new RoutePartialGroup();
|
||||
@@ -309,14 +304,14 @@ class SimpleRouter
|
||||
* Alias for the form method
|
||||
*
|
||||
* @param string $url
|
||||
* @param callable $callback
|
||||
* @param string|array|Closure $callback
|
||||
* @param array|null $settings
|
||||
* @return RouteUrl|IRoute
|
||||
* @see SimpleRouter::form
|
||||
* @return RouteUrl
|
||||
*/
|
||||
public static function basic(string $url, $callback, array $settings = null): IRoute
|
||||
{
|
||||
return static::match(['get', 'post'], $url, $callback, $settings);
|
||||
return static::form($url, $callback, $settings);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -324,14 +319,17 @@ class SimpleRouter
|
||||
* Route the given url to your callback on POST and GET request method.
|
||||
*
|
||||
* @param string $url
|
||||
* @param string|\Closure $callback
|
||||
* @param string|array|Closure $callback
|
||||
* @param array|null $settings
|
||||
* @return RouteUrl|IRoute
|
||||
* @see SimpleRouter::form
|
||||
* @return RouteUrl
|
||||
*/
|
||||
public static function form(string $url, $callback, array $settings = null): IRoute
|
||||
{
|
||||
return static::match(['get', 'post'], $url, $callback, $settings);
|
||||
return static::match([
|
||||
Request::REQUEST_TYPE_GET,
|
||||
Request::REQUEST_TYPE_POST,
|
||||
], $url, $callback, $settings);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -339,15 +337,14 @@ class SimpleRouter
|
||||
*
|
||||
* @param array $requestMethods
|
||||
* @param string $url
|
||||
* @param string|\Closure $callback
|
||||
* @param string|array|Closure $callback
|
||||
* @param array|null $settings
|
||||
* @return RouteUrl|IRoute
|
||||
*/
|
||||
public static function match(array $requestMethods, string $url, $callback, array $settings = null)
|
||||
public static function match(array $requestMethods, string $url, $callback, array $settings = null): IRoute
|
||||
{
|
||||
$route = new RouteUrl($url, $callback);
|
||||
$route->setRequestMethods($requestMethods);
|
||||
$route = static::addDefaultNamespace($route);
|
||||
|
||||
if ($settings !== null) {
|
||||
$route->setSettings($settings);
|
||||
@@ -360,14 +357,13 @@ class SimpleRouter
|
||||
* This type will route the given url to your callback and allow any type of request method
|
||||
*
|
||||
* @param string $url
|
||||
* @param string|\Closure $callback
|
||||
* @param string|array|Closure $callback
|
||||
* @param array|null $settings
|
||||
* @return RouteUrl|IRoute
|
||||
*/
|
||||
public static function all(string $url, $callback, array $settings = null)
|
||||
public static function all(string $url, $callback, array $settings = null): IRoute
|
||||
{
|
||||
$route = new RouteUrl($url, $callback);
|
||||
$route = static::addDefaultNamespace($route);
|
||||
|
||||
if ($settings !== null) {
|
||||
$route->setSettings($settings);
|
||||
@@ -384,10 +380,9 @@ class SimpleRouter
|
||||
* @param array|null $settings
|
||||
* @return RouteController|IRoute
|
||||
*/
|
||||
public static function controller(string $url, $controller, array $settings = null)
|
||||
public static function controller(string $url, string $controller, array $settings = null): IRoute
|
||||
{
|
||||
$route = new RouteController($url, $controller);
|
||||
$route = static::addDefaultNamespace($route);
|
||||
|
||||
if ($settings !== null) {
|
||||
$route->setSettings($settings);
|
||||
@@ -404,10 +399,9 @@ class SimpleRouter
|
||||
* @param array|null $settings
|
||||
* @return RouteResource|IRoute
|
||||
*/
|
||||
public static function resource(string $url, $controller, array $settings = null)
|
||||
public static function resource(string $url, string $controller, array $settings = null): IRoute
|
||||
{
|
||||
$route = new RouteResource($url, $controller);
|
||||
$route = static::addDefaultNamespace($route);
|
||||
|
||||
if ($settings !== null) {
|
||||
$route->setSettings($settings);
|
||||
@@ -419,21 +413,14 @@ class SimpleRouter
|
||||
/**
|
||||
* Add exception callback handler.
|
||||
*
|
||||
* @param \Closure $callback
|
||||
* @param Closure $callback
|
||||
* @return CallbackExceptionHandler $callbackHandler
|
||||
*/
|
||||
public static function error(\Closure $callback): CallbackExceptionHandler
|
||||
public static function error(Closure $callback): CallbackExceptionHandler
|
||||
{
|
||||
$routes = static::router()->getRoutes();
|
||||
|
||||
$callbackHandler = new CallbackExceptionHandler($callback);
|
||||
|
||||
$group = new RouteGroup();
|
||||
$group->addExceptionHandler($callbackHandler);
|
||||
|
||||
array_unshift($routes, $group);
|
||||
|
||||
static::router()->setRoutes($routes);
|
||||
static::router()->addExceptionHandler($callbackHandler);
|
||||
|
||||
return $callbackHandler;
|
||||
}
|
||||
@@ -459,22 +446,15 @@ class SimpleRouter
|
||||
{
|
||||
try {
|
||||
return static::router()->getUrl($name, $parameters, $getParams);
|
||||
} catch (\Exception $e) {
|
||||
try {
|
||||
return new Url('/');
|
||||
} catch (MalformedUrlException $e) {
|
||||
|
||||
}
|
||||
} catch (Exception $e) {
|
||||
return new Url('/');
|
||||
}
|
||||
|
||||
// This will never happen...
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the request
|
||||
*
|
||||
* @return \Pecee\Http\Request
|
||||
* @return Request
|
||||
*/
|
||||
public static function request(): Request
|
||||
{
|
||||
@@ -512,46 +492,37 @@ class SimpleRouter
|
||||
/**
|
||||
* Prepends the default namespace to all new routes added.
|
||||
*
|
||||
* @param IRoute $route
|
||||
* @param ILoadableRoute|IRoute $route
|
||||
* @return IRoute
|
||||
*/
|
||||
public static function addDefaultNamespace(IRoute $route): IRoute
|
||||
{
|
||||
if (static::$defaultNamespace !== null) {
|
||||
|
||||
$callback = $route->getCallback();
|
||||
|
||||
/* Only add default namespace on relative callbacks */
|
||||
if ($callback === null || (\is_string($callback) === true && $callback[0] !== '\\')) {
|
||||
|
||||
$namespace = static::$defaultNamespace;
|
||||
|
||||
$currentNamespace = $route->getNamespace();
|
||||
|
||||
if ($currentNamespace !== null) {
|
||||
$namespace .= '\\' . $currentNamespace;
|
||||
}
|
||||
|
||||
$route->setDefaultNamespace($namespace);
|
||||
|
||||
}
|
||||
$route->setNamespace(static::$defaultNamespace);
|
||||
}
|
||||
|
||||
return $route;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable dependency injection
|
||||
* Changes the rendering behavior of the router.
|
||||
* When enabled the router will render all routes that matches.
|
||||
* When disabled the router will stop rendering at the first route that matches.
|
||||
*
|
||||
* @param Container $container
|
||||
* @return IClassLoader
|
||||
* @param bool $bool
|
||||
*/
|
||||
public static function enableDependencyInjection(Container $container): IClassLoader
|
||||
public static function enableMultiRouteRendering(bool $bool): void
|
||||
{
|
||||
return static::router()
|
||||
->getClassLoader()
|
||||
->useDependencyInjection(true)
|
||||
->setContainer($container);
|
||||
static::router()->setRenderMultipleRoutes($bool);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set custom class-loader class used.
|
||||
* @param IClassLoader $classLoader
|
||||
*/
|
||||
public static function setCustomClassLoader(IClassLoader $classLoader): void
|
||||
{
|
||||
static::router()->setClassLoader($classLoader);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
require_once 'Dummy/DummyMiddleware.php';
|
||||
require_once 'Dummy/DummyController.php';
|
||||
require_once 'Dummy/Handler/ExceptionHandler.php';
|
||||
require_once 'Dummy/Managers/TestBootManager.php';
|
||||
require_once 'Dummy/Managers/FindUrlBootManager.php';
|
||||
|
||||
class BootManagerTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
|
||||
public function testBootManagerRoutes()
|
||||
{
|
||||
$result = false;
|
||||
|
||||
TestRouter::get('/', function () use (&$result) {
|
||||
$result = true;
|
||||
});
|
||||
TestRouter::get('/about', 'DummyController@method2');
|
||||
TestRouter::get('/contact', 'DummyController@method3');
|
||||
|
||||
// Add boot-manager
|
||||
TestRouter::addBootManager(new TestBootManager([
|
||||
'/con' => '/about',
|
||||
'/contact' => '/',
|
||||
]));
|
||||
|
||||
TestRouter::debug('/contact');
|
||||
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
public function testFindUrlFromBootManager()
|
||||
{
|
||||
TestRouter::get('/', 'DummyController@method1');
|
||||
TestRouter::get('/about', 'DummyController@method2')->name('about');
|
||||
TestRouter::get('/contact', 'DummyController@method3')->name('contact');
|
||||
|
||||
$result = false;
|
||||
|
||||
// Add boot-manager
|
||||
TestRouter::addBootManager(new FindUrlBootManager($result));
|
||||
|
||||
TestRouter::debug('/');
|
||||
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
require_once 'Dummy/DummyMiddleware.php';
|
||||
require_once 'Dummy/DummyController.php';
|
||||
require_once 'Dummy/ClassLoader/CustomClassLoader.php';
|
||||
|
||||
class ClassLoaderTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
|
||||
public function testCustomClassLoader()
|
||||
{
|
||||
$result = false;
|
||||
|
||||
TestRouter::setCustomClassLoader(new CustomClassLoader());
|
||||
|
||||
TestRouter::get('/', 'NonExistingClass@method3');
|
||||
TestRouter::get('/test-closure', function($status) use(&$result) {
|
||||
$result = $status;
|
||||
});
|
||||
|
||||
$classLoaderClass = TestRouter::debugOutput('/', 'get', false);
|
||||
TestRouter::debugOutput('/test-closure');
|
||||
|
||||
$this->assertEquals('method3', $classLoaderClass);
|
||||
$this->assertTrue($result);
|
||||
|
||||
TestRouter::router()->reset();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
<?php
|
||||
require_once 'Dummy/CsrfVerifier/DummyCsrfVerifier.php';
|
||||
require_once 'Dummy/Security/SilentTokenProvider.php';
|
||||
|
||||
class CsrfVerifierTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
|
||||
public function testTokenPass()
|
||||
{
|
||||
global $_POST;
|
||||
|
||||
$tokenProvider = new SilentTokenProvider();
|
||||
|
||||
$_POST[DummyCsrfVerifier::POST_KEY] = $tokenProvider->getToken();
|
||||
|
||||
TestRouter::router()->reset();
|
||||
|
||||
$router = TestRouter::router();
|
||||
$router->getRequest()->setMethod(\Pecee\Http\Request::REQUEST_TYPE_POST);
|
||||
$router->getRequest()->setUrl(new \Pecee\Http\Url('/page'));
|
||||
$csrf = new DummyCsrfVerifier();
|
||||
$csrf->setTokenProvider($tokenProvider);
|
||||
|
||||
$csrf->handle($router->getRequest());
|
||||
|
||||
// If handle doesn't throw exception, the test has passed
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
public function testTokenFail()
|
||||
{
|
||||
$this->expectException(\Pecee\Http\Middleware\Exceptions\TokenMismatchException::class);
|
||||
|
||||
global $_POST;
|
||||
|
||||
$tokenProvider = new SilentTokenProvider();
|
||||
|
||||
$router = TestRouter::router();
|
||||
$router->getRequest()->setMethod(\Pecee\Http\Request::REQUEST_TYPE_POST);
|
||||
$router->getRequest()->setUrl(new \Pecee\Http\Url('/page'));
|
||||
$csrf = new DummyCsrfVerifier();
|
||||
$csrf->setTokenProvider($tokenProvider);
|
||||
|
||||
$csrf->handle($router->getRequest());
|
||||
}
|
||||
|
||||
public function testExcludeInclude()
|
||||
{
|
||||
$router = TestRouter::router();
|
||||
$csrf = new DummyCsrfVerifier();
|
||||
$request = $router->getRequest();
|
||||
|
||||
$request->setUrl(new \Pecee\Http\Url('/exclude-page'));
|
||||
$this->assertTrue($csrf->testSkip($router->getRequest()));
|
||||
|
||||
$request->setUrl(new \Pecee\Http\Url('/exclude-all/page'));
|
||||
$this->assertTrue($csrf->testSkip($router->getRequest()));
|
||||
|
||||
$request->setUrl(new \Pecee\Http\Url('/exclude-all/include-page'));
|
||||
$this->assertFalse($csrf->testSkip($router->getRequest()));
|
||||
|
||||
$request->setUrl(new \Pecee\Http\Url('/include-page'));
|
||||
$this->assertFalse($csrf->testSkip($router->getRequest()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
<?php
|
||||
|
||||
require_once 'Dummy/DummyController.php';
|
||||
require_once 'Dummy/Middleware/IpRestrictMiddleware.php';
|
||||
|
||||
class CustomMiddlewareTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
|
||||
public function testIpBlock() {
|
||||
|
||||
$this->expectException(\Pecee\SimpleRouter\Exceptions\HttpException::class);
|
||||
|
||||
global $_SERVER;
|
||||
|
||||
// Test exact ip
|
||||
|
||||
$_SERVER['remote-addr'] = '5.5.5.5';
|
||||
|
||||
TestRouter::group(['middleware' => IpRestrictMiddleware::class], function() {
|
||||
TestRouter::get('/fail', 'DummyController@method1');
|
||||
});
|
||||
|
||||
TestRouter::debug('/fail');
|
||||
|
||||
// Test ip-range
|
||||
|
||||
$_SERVER['remote-addr'] = '8.8.4.4';
|
||||
|
||||
TestRouter::router()->reset();
|
||||
|
||||
TestRouter::group(['middleware' => IpRestrictMiddleware::class], function() {
|
||||
TestRouter::get('/fail', 'DummyController@method1');
|
||||
});
|
||||
|
||||
TestRouter::debug('/fail');
|
||||
|
||||
}
|
||||
|
||||
public function testIpSuccess() {
|
||||
|
||||
global $_SERVER;
|
||||
|
||||
// Test ip that is not blocked
|
||||
|
||||
$_SERVER['remote-addr'] = '6.6.6.6';
|
||||
|
||||
TestRouter::router()->reset();
|
||||
|
||||
TestRouter::group(['middleware' => IpRestrictMiddleware::class], function() {
|
||||
TestRouter::get('/success', 'DummyController@method1');
|
||||
});
|
||||
|
||||
TestRouter::debug('/success');
|
||||
|
||||
// Test ip in whitelist
|
||||
|
||||
$_SERVER['remote-addr'] = '8.8.2.2';
|
||||
|
||||
TestRouter::router()->reset();
|
||||
|
||||
TestRouter::group(['middleware' => IpRestrictMiddleware::class], function() {
|
||||
TestRouter::get('/success', 'DummyController@method1');
|
||||
});
|
||||
|
||||
TestRouter::debug('/success');
|
||||
|
||||
$this->assertTrue(true);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
<?php
|
||||
|
||||
require_once 'Dummy/DummyMiddleware.php';
|
||||
|
||||
class DependencyInjectionTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
public function testDependencyInjectionDevelopment()
|
||||
{
|
||||
$builder = new \DI\ContainerBuilder();
|
||||
$container = $builder
|
||||
->useAutowiring(true)
|
||||
->ignorePhpDocErrors(true)
|
||||
->build();
|
||||
|
||||
TestRouter::enableDependencyInjection($container);
|
||||
|
||||
$className = null;
|
||||
|
||||
TestRouter::get('/', function (DummyMiddleware $url) use (&$className) {
|
||||
$className = \get_class($url);
|
||||
});
|
||||
|
||||
TestRouter::debug('/');
|
||||
|
||||
$this->assertEquals(DummyMiddleware::class, $className);
|
||||
}
|
||||
|
||||
public function testDependencyInjectionProduction()
|
||||
{
|
||||
$cacheDir = dirname(__DIR__, 2) . '/tmp';
|
||||
|
||||
$builder = new \DI\ContainerBuilder();
|
||||
$builder
|
||||
->enableCompilation($cacheDir)
|
||||
->writeProxiesToFile(true, $cacheDir . '/proxies')
|
||||
->ignorePhpDocErrors(true)
|
||||
->useAutowiring(true);
|
||||
|
||||
$container = $builder->build();
|
||||
|
||||
TestRouter::enableDependencyInjection($container);
|
||||
|
||||
$className = null;
|
||||
|
||||
TestRouter::get('/', function (DummyMiddleware $url) use (&$className) {
|
||||
$className = \get_class($url);
|
||||
});
|
||||
|
||||
TestRouter::debug('/');
|
||||
|
||||
$this->assertEquals(DummyMiddleware::class, $className);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
class CustomClassLoader implements \Pecee\SimpleRouter\ClassLoader\IClassLoader
|
||||
{
|
||||
public function loadClass(string $class)
|
||||
{
|
||||
return new DummyController();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when loading class method
|
||||
* @param object $class
|
||||
* @param string $method
|
||||
* @param array $parameters
|
||||
* @return object
|
||||
*/
|
||||
public function loadClassMethod($class, string $method, array $parameters)
|
||||
{
|
||||
return call_user_func_array([$class, $method], [true]);
|
||||
}
|
||||
|
||||
public function loadClosure(callable $closure, array $parameters)
|
||||
{
|
||||
return call_user_func_array($closure, [true]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
class DummyCsrfVerifier extends \Pecee\Http\Middleware\BaseCsrfVerifier {
|
||||
|
||||
protected $except = [
|
||||
'/exclude-page',
|
||||
'/exclude-all/*',
|
||||
];
|
||||
|
||||
protected $include = [
|
||||
'/exclude-all/include-page',
|
||||
];
|
||||
|
||||
public function testSkip(\Pecee\Http\Request $request) {
|
||||
return $this->skip($request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,6 +2,12 @@
|
||||
|
||||
class DummyController
|
||||
{
|
||||
public function index()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
public function method1()
|
||||
{
|
||||
|
||||
@@ -10,6 +16,11 @@ class DummyController
|
||||
public function method2()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function method3()
|
||||
{
|
||||
return 'method3';
|
||||
}
|
||||
|
||||
public function param($params = null)
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<?php
|
||||
|
||||
class FindUrlBootManager implements \Pecee\SimpleRouter\IRouterBootManager
|
||||
{
|
||||
protected $result;
|
||||
|
||||
public function __construct(&$result)
|
||||
{
|
||||
$this->result = &$result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when router loads it's routes
|
||||
*
|
||||
* @param \Pecee\SimpleRouter\Router $router
|
||||
* @param \Pecee\Http\Request $request
|
||||
*/
|
||||
public function boot(\Pecee\SimpleRouter\Router $router, \Pecee\Http\Request $request): void
|
||||
{
|
||||
$contact = $router->findRoute('contact');
|
||||
|
||||
if($contact !== null) {
|
||||
$this->result = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,13 +3,11 @@
|
||||
class TestBootManager implements \Pecee\SimpleRouter\IRouterBootManager
|
||||
{
|
||||
|
||||
protected $routes;
|
||||
protected $aliasUrl;
|
||||
protected $rewrite;
|
||||
|
||||
public function __construct(array $routes, string $aliasUrl)
|
||||
public function __construct(array $rewrite)
|
||||
{
|
||||
$this->routes = $routes;
|
||||
$this->aliasUrl = $aliasUrl;
|
||||
$this->rewrite = $rewrite;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -20,11 +18,11 @@ class TestBootManager implements \Pecee\SimpleRouter\IRouterBootManager
|
||||
*/
|
||||
public function boot(\Pecee\SimpleRouter\Router $router, \Pecee\Http\Request $request): void
|
||||
{
|
||||
foreach ($this->routes as $url) {
|
||||
foreach ($this->rewrite as $url => $rewrite) {
|
||||
// If the current url matches the rewrite url, we use our custom route
|
||||
|
||||
if ($request->getUrl()->contains($url) === true) {
|
||||
$request->setRewriteUrl($this->aliasUrl);
|
||||
$request->setRewriteUrl($rewrite);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
<?php
|
||||
|
||||
class IpRestrictMiddleware extends \Pecee\Http\Middleware\IpRestrictAccess {
|
||||
|
||||
protected $ipBlacklist = [
|
||||
'5.5.5.5',
|
||||
'8.8.*',
|
||||
];
|
||||
|
||||
protected $ipWhitelist = [
|
||||
'8.8.2.2',
|
||||
];
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
<?php
|
||||
namespace MyNamespace;
|
||||
|
||||
class NSController {
|
||||
|
||||
public function method()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,43 +4,36 @@ class ResourceController implements \Pecee\Controllers\IResourceController
|
||||
|
||||
public function index() : ?string
|
||||
{
|
||||
echo 'index';
|
||||
return null;
|
||||
return 'index';
|
||||
}
|
||||
|
||||
public function show($id) : ?string
|
||||
{
|
||||
echo 'show ' . $id;
|
||||
return null;
|
||||
return 'show ' . $id;
|
||||
}
|
||||
|
||||
public function store() : ?string
|
||||
{
|
||||
echo 'store';
|
||||
return null;
|
||||
return 'store';
|
||||
}
|
||||
|
||||
public function create() : ?string
|
||||
{
|
||||
echo 'create';
|
||||
return null;
|
||||
return 'create';
|
||||
}
|
||||
|
||||
public function edit($id) : ?string
|
||||
{
|
||||
echo 'edit ' . $id;
|
||||
return null;
|
||||
return 'edit ' . $id;
|
||||
}
|
||||
|
||||
public function update($id) : ?string
|
||||
{
|
||||
echo 'update ' . $id;
|
||||
return null;
|
||||
return 'update ' . $id;
|
||||
}
|
||||
|
||||
public function destroy($id) : ?string
|
||||
{
|
||||
echo 'destroy ' . $id;
|
||||
return null;
|
||||
return 'destroy ' . $id;
|
||||
}
|
||||
}
|
||||
@@ -50,8 +50,8 @@ class EventHandlerTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
// Add boot-manager
|
||||
TestRouter::addBootManager(new TestBootManager([
|
||||
'/test',
|
||||
], '/'));
|
||||
'/test' => '/',
|
||||
]));
|
||||
|
||||
// Start router
|
||||
TestRouter::debug('/non-existing');
|
||||
@@ -61,7 +61,6 @@ class EventHandlerTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
public function testAllEvent()
|
||||
{
|
||||
|
||||
$status = false;
|
||||
|
||||
$eventHandler = new EventHandler();
|
||||
@@ -104,4 +103,49 @@ class EventHandlerTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
}
|
||||
|
||||
public function testCustomBasePath() {
|
||||
|
||||
$basePath = '/basepath/';
|
||||
|
||||
$eventHandler = new EventHandler();
|
||||
$eventHandler->register(EventHandler::EVENT_ADD_ROUTE, function(EventArgument $data) use($basePath) {
|
||||
|
||||
// Skip routes added by group
|
||||
if($data->isSubRoute === false) {
|
||||
|
||||
switch (true) {
|
||||
case $data->route instanceof \Pecee\SimpleRouter\Route\ILoadableRoute:
|
||||
$data->route->prependUrl($basePath);
|
||||
break;
|
||||
case $data->route instanceof \Pecee\SimpleRouter\Route\IGroupRoute:
|
||||
$data->route->prependPrefix($basePath);
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
$results = [];
|
||||
|
||||
TestRouter::addEventHandler($eventHandler);
|
||||
|
||||
TestRouter::get('/about', function() use(&$results) {
|
||||
$results[] = 'about';
|
||||
});
|
||||
|
||||
TestRouter::group(['prefix' => '/admin'], function() use(&$results) {
|
||||
TestRouter::get('/', function() use(&$results) {
|
||||
$results[] = 'admin';
|
||||
});
|
||||
});
|
||||
|
||||
TestRouter::router()->setRenderMultipleRoutes(false);
|
||||
TestRouter::debugNoReset('/basepath/about');
|
||||
TestRouter::debugNoReset('/basepath/admin');
|
||||
|
||||
$this->assertEquals(['about', 'admin'], $results);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +1,44 @@
|
||||
<?php
|
||||
|
||||
use Pecee\Http\Input\InputFile;
|
||||
|
||||
require_once 'Dummy/DummyMiddleware.php';
|
||||
require_once 'Dummy/DummyController.php';
|
||||
require_once 'Dummy/Handler/ExceptionHandler.php';
|
||||
|
||||
class InputHandlerTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
protected $names = [
|
||||
'Lester',
|
||||
'Michael',
|
||||
'Franklin',
|
||||
'Trevor',
|
||||
];
|
||||
|
||||
protected $brands = [
|
||||
'Samsung',
|
||||
'Apple',
|
||||
'HP',
|
||||
'Canon',
|
||||
];
|
||||
|
||||
protected $sodas = [
|
||||
0 => 'Pepsi',
|
||||
1 => 'Coca Cola',
|
||||
2 => 'Harboe',
|
||||
3 => 'Mountain Dew',
|
||||
];
|
||||
|
||||
protected $day = 'monday';
|
||||
|
||||
public function testPost()
|
||||
{
|
||||
global $_POST;
|
||||
|
||||
$names = [
|
||||
'Lester',
|
||||
'Michael',
|
||||
'Franklin',
|
||||
'Trevor',
|
||||
];
|
||||
|
||||
$day = 'monday';
|
||||
|
||||
$_POST = [
|
||||
'names' => $names,
|
||||
'day' => $day,
|
||||
'names' => $this->names,
|
||||
'day' => $this->day,
|
||||
'sodas' => $this->sodas,
|
||||
];
|
||||
|
||||
$router = TestRouter::router();
|
||||
@@ -31,29 +47,34 @@ class InputHandlerTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
$handler = TestRouter::request()->getInputHandler();
|
||||
|
||||
$this->assertEquals($names, $handler->value('names'));
|
||||
$this->assertEquals($names, $handler->all(['names'])['names']);
|
||||
$this->assertEquals($day, $handler->value('day'));
|
||||
$this->assertEquals($this->names, $handler->value('names'));
|
||||
$this->assertEquals($this->names, $handler->all(['names'])['names']);
|
||||
$this->assertEquals($this->day, $handler->value('day'));
|
||||
$this->assertInstanceOf(\Pecee\Http\Input\InputItem::class, $handler->find('day'));
|
||||
$this->assertInstanceOf(\Pecee\Http\Input\InputItem::class, $handler->post('day'));
|
||||
$this->assertInstanceOf(\Pecee\Http\Input\InputItem::class, $handler->find('day', 'post'));
|
||||
|
||||
// Check non-existing and wrong request-type
|
||||
$this->assertEmpty($handler->all(['non-existing']));
|
||||
$this->assertCount(1, $handler->all(['non-existing']));
|
||||
$this->assertEmpty($handler->all(['non-existing'])['non-existing']);
|
||||
$this->assertNull($handler->value('non-existing'));
|
||||
$this->assertNull($handler->find('non-existing'));
|
||||
$this->assertNull($handler->value('names', null, 'get'));
|
||||
$this->assertNull($handler->find('names', 'get'));
|
||||
$this->assertEquals($this->sodas, $handler->value('sodas'));
|
||||
|
||||
$objects = $handler->find('names');
|
||||
|
||||
$this->assertInstanceOf(\Pecee\Http\Input\InputItem::class, $objects);
|
||||
$this->assertCount(4, $objects);
|
||||
|
||||
/* @var $object \Pecee\Http\Input\InputItem */
|
||||
foreach($objects as $i => $object) {
|
||||
$this->assertInstanceOf(\Pecee\Http\Input\InputItem::class, $object);
|
||||
$this->assertEquals($names[$i], $object->getValue());
|
||||
$this->assertEquals($this->names[$i], $object->getValue());
|
||||
}
|
||||
|
||||
// Reset
|
||||
$_POST = [];
|
||||
}
|
||||
|
||||
@@ -61,18 +82,9 @@ class InputHandlerTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
global $_GET;
|
||||
|
||||
$names = [
|
||||
'Lester',
|
||||
'Michael',
|
||||
'Franklin',
|
||||
'Trevor',
|
||||
];
|
||||
|
||||
$day = 'monday';
|
||||
|
||||
$_GET = [
|
||||
'names' => $names,
|
||||
'day' => $day,
|
||||
'names' => $this->names,
|
||||
'day' => $this->day,
|
||||
];
|
||||
|
||||
$router = TestRouter::router();
|
||||
@@ -81,14 +93,15 @@ class InputHandlerTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
$handler = TestRouter::request()->getInputHandler();
|
||||
|
||||
$this->assertEquals($names, $handler->value('names'));
|
||||
$this->assertEquals($names, $handler->all(['names'])['names']);
|
||||
$this->assertEquals($day, $handler->value('day'));
|
||||
$this->assertEquals($this->names, $handler->value('names'));
|
||||
$this->assertEquals($this->names, $handler->all(['names'])['names']);
|
||||
$this->assertEquals($this->day, $handler->value('day'));
|
||||
$this->assertInstanceOf(\Pecee\Http\Input\InputItem::class, $handler->find('day'));
|
||||
$this->assertInstanceOf(\Pecee\Http\Input\InputItem::class, $handler->get('day'));
|
||||
|
||||
// Check non-existing and wrong request-type
|
||||
$this->assertEmpty($handler->all(['non-existing']));
|
||||
$this->assertCount(1, $handler->all(['non-existing']));
|
||||
$this->assertEmpty($handler->all(['non-existing'])['non-existing']);
|
||||
$this->assertNull($handler->value('non-existing'));
|
||||
$this->assertNull($handler->find('non-existing'));
|
||||
$this->assertNull($handler->value('names', null, 'post'));
|
||||
@@ -96,30 +109,179 @@ class InputHandlerTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
$objects = $handler->find('names');
|
||||
|
||||
$this->assertInstanceOf(\Pecee\Http\Input\InputItem::class, $objects);
|
||||
$this->assertCount(4, $objects);
|
||||
|
||||
/* @var $object \Pecee\Http\Input\InputItem */
|
||||
foreach($objects as $i => $object) {
|
||||
$this->assertInstanceOf(\Pecee\Http\Input\InputItem::class, $object);
|
||||
$this->assertEquals($names[$i], $object->getValue());
|
||||
$this->assertEquals($this->names[$i], $object->getValue());
|
||||
}
|
||||
|
||||
// Reset
|
||||
$_GET = [];
|
||||
}
|
||||
|
||||
public function testFindInput() {
|
||||
|
||||
global $_POST;
|
||||
$_POST['hello'] = 'motto';
|
||||
|
||||
$router = TestRouter::router();
|
||||
$router->reset();
|
||||
$router->getRequest()->setMethod('post');
|
||||
$inputHandler = TestRouter::request()->getInputHandler();
|
||||
|
||||
$value = $inputHandler->value('hello', null, \Pecee\Http\Request::$requestTypesPost);
|
||||
|
||||
$this->assertEquals($_POST['hello'], $value);
|
||||
}
|
||||
|
||||
public function testFile()
|
||||
{
|
||||
$this->assertEquals(true, true);
|
||||
global $_FILES;
|
||||
|
||||
$testFile = $this->generateFile();
|
||||
|
||||
$_FILES = [
|
||||
'test_input' => $testFile,
|
||||
];
|
||||
|
||||
$router = TestRouter::router();
|
||||
$router->reset();
|
||||
$router->getRequest()->setMethod('post');
|
||||
$inputHandler = TestRouter::request()->getInputHandler();
|
||||
|
||||
$testFileContent = md5(uniqid('test', false));
|
||||
|
||||
$file = $inputHandler->file('test_input');
|
||||
|
||||
$this->assertInstanceOf(InputFile::class, $file);
|
||||
$this->assertEquals($testFile['name'], $file->getFilename());
|
||||
$this->assertEquals($testFile['type'], $file->getType());
|
||||
$this->assertEquals($testFile['tmp_name'], $file->getTmpName());
|
||||
$this->assertEquals($testFile['error'], $file->getError());
|
||||
$this->assertEquals($testFile['size'], $file->getSize());
|
||||
$this->assertEquals(pathinfo($testFile['name'], PATHINFO_EXTENSION), $file->getExtension());
|
||||
|
||||
file_put_contents($testFile['tmp_name'], $testFileContent);
|
||||
$this->assertEquals($testFileContent, $file->getContents());
|
||||
|
||||
// Cleanup
|
||||
unlink($testFile['tmp_name']);
|
||||
}
|
||||
|
||||
public function testFiles()
|
||||
public function testFilesArray()
|
||||
{
|
||||
$this->assertEquals(true, true);
|
||||
global $_FILES;
|
||||
|
||||
$testFiles = [
|
||||
$file = $this->generateFile(),
|
||||
$file = $this->generateFile(),
|
||||
$file = $this->generateFile(),
|
||||
$file = $this->generateFile(),
|
||||
$file = $this->generateFile(),
|
||||
];
|
||||
|
||||
$_FILES = [
|
||||
'my_files' => $testFiles,
|
||||
];
|
||||
|
||||
$router = TestRouter::router();
|
||||
$router->reset();
|
||||
$router->getRequest()->setMethod('post');
|
||||
$inputHandler = TestRouter::request()->getInputHandler();
|
||||
|
||||
$files = $inputHandler->file('my_files');
|
||||
$this->assertCount(5, $files);
|
||||
|
||||
/* @var $file InputFile */
|
||||
foreach ($files as $key => $file) {
|
||||
|
||||
$testFileContent = md5(uniqid('test', false));
|
||||
|
||||
$this->assertInstanceOf(InputFile::class, $file);
|
||||
$this->assertEquals($testFiles[$key]['name'], $file->getFilename());
|
||||
$this->assertEquals($testFiles[$key]['type'], $file->getType());
|
||||
$this->assertEquals($testFiles[$key]['tmp_name'], $file->getTmpName());
|
||||
$this->assertEquals($testFiles[$key]['error'], $file->getError());
|
||||
$this->assertEquals($testFiles[$key]['size'], $file->getSize());
|
||||
$this->assertEquals(pathinfo($testFiles[$key]['name'], PATHINFO_EXTENSION), $file->getExtension());
|
||||
|
||||
file_put_contents($testFiles[$key]['tmp_name'], $testFileContent);
|
||||
|
||||
$this->assertEquals($testFileContent, $file->getContents());
|
||||
|
||||
// Cleanup
|
||||
unlink($testFiles[$key]['tmp_name']);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public function testAll()
|
||||
{
|
||||
$this->assertEquals(true, true);
|
||||
global $_POST;
|
||||
global $_GET;
|
||||
|
||||
$_POST = [
|
||||
'names' => $this->names,
|
||||
'is_sad' => true,
|
||||
];
|
||||
|
||||
$_GET = [
|
||||
'brands' => $this->brands,
|
||||
'is_happy' => true,
|
||||
];
|
||||
|
||||
$router = TestRouter::router();
|
||||
$router->reset();
|
||||
$router->getRequest()->setMethod('post');
|
||||
|
||||
$handler = TestRouter::request()->getInputHandler();
|
||||
|
||||
// GET
|
||||
$brandsFound = $handler->all(['brands', 'nothing']);
|
||||
|
||||
$this->assertArrayHasKey('brands', $brandsFound);
|
||||
$this->assertArrayHasKey('nothing', $brandsFound);
|
||||
$this->assertEquals($this->brands, $brandsFound['brands']);
|
||||
$this->assertNull($brandsFound['nothing']);
|
||||
|
||||
// POST
|
||||
$namesFound = $handler->all(['names', 'nothing']);
|
||||
|
||||
$this->assertArrayHasKey('names', $namesFound);
|
||||
$this->assertArrayHasKey('nothing', $namesFound);
|
||||
$this->assertEquals($this->names, $namesFound['names']);
|
||||
$this->assertNull($namesFound['nothing']);
|
||||
|
||||
// DEFAULT VALUE
|
||||
$nonExisting = $handler->all([
|
||||
'non-existing'
|
||||
]);
|
||||
|
||||
$this->assertArrayHasKey('non-existing', $nonExisting);
|
||||
$this->assertNull($nonExisting['non-existing']);
|
||||
|
||||
// Reset
|
||||
$_GET = [];
|
||||
$_POST = [];
|
||||
}
|
||||
|
||||
protected function generateFile()
|
||||
{
|
||||
return [
|
||||
'name' => uniqid('', false) . '.txt',
|
||||
'type' => 'text/plain',
|
||||
'tmp_name' => sys_get_temp_dir() . '/phpYfWUiw',
|
||||
'error' => 0,
|
||||
'size' => rand(3, 40),
|
||||
];
|
||||
}
|
||||
|
||||
protected function generateFileContent()
|
||||
{
|
||||
return md5(uniqid('', false));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
use Pecee\Http\Input\InputFile;
|
||||
|
||||
require_once 'Dummy/DummyMiddleware.php';
|
||||
require_once 'Dummy/DummyController.php';
|
||||
require_once 'Dummy/Handler/ExceptionHandler.php';
|
||||
|
||||
class RequestTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
|
||||
protected function processHeader($name, $value, callable $callback)
|
||||
{
|
||||
global $_SERVER;
|
||||
|
||||
$_SERVER[$name] = $value;
|
||||
|
||||
$router = TestRouter::router();
|
||||
$router->reset();
|
||||
|
||||
$request = $router->getRequest();
|
||||
|
||||
$callback($request);
|
||||
|
||||
// Reset everything
|
||||
$_SERVER[$name] = null;
|
||||
$router->reset();
|
||||
}
|
||||
|
||||
public function testContentTypeParse()
|
||||
{
|
||||
global $_SERVER;
|
||||
|
||||
// Test normal content-type
|
||||
|
||||
$contentType = 'application/x-www-form-urlencoded';
|
||||
|
||||
$this->processHeader('content_type', $contentType, function(\Pecee\Http\Request $request) use($contentType) {
|
||||
$this->assertEquals($contentType, $request->getContentType());
|
||||
});
|
||||
|
||||
// Test special content-type with encoding
|
||||
|
||||
$contentTypeWithEncoding = 'application/x-www-form-urlencoded; charset=UTF-8';
|
||||
|
||||
$this->processHeader('content_type', $contentTypeWithEncoding, function(\Pecee\Http\Request $request) use($contentType) {
|
||||
$this->assertEquals($contentType, $request->getContentType());
|
||||
});
|
||||
}
|
||||
|
||||
public function testGetIp()
|
||||
{
|
||||
$ip = '1.1.1.1';
|
||||
$this->processHeader('remote_addr', $ip, function(\Pecee\Http\Request $request) use($ip) {
|
||||
$this->assertEquals($ip, $request->getIp());
|
||||
});
|
||||
|
||||
$ip = '2.2.2.2';
|
||||
$this->processHeader('http-cf-connecting-ip', $ip, function(\Pecee\Http\Request $request) use($ip) {
|
||||
$this->assertEquals($ip, $request->getIp());
|
||||
});
|
||||
|
||||
$ip = '3.3.3.3';
|
||||
$this->processHeader('http-client-ip', $ip, function(\Pecee\Http\Request $request) use($ip) {
|
||||
$this->assertEquals($ip, $request->getIp());
|
||||
});
|
||||
|
||||
$ip = '4.4.4.4';
|
||||
$this->processHeader('http-x-forwarded-for', $ip, function(\Pecee\Http\Request $request) use($ip) {
|
||||
$this->assertEquals($ip, $request->getIp());
|
||||
});
|
||||
|
||||
// Test safe
|
||||
|
||||
$ip = '5.5.5.5';
|
||||
$this->processHeader('http-x-forwarded-for', $ip, function(\Pecee\Http\Request $request) {
|
||||
$this->assertEquals(null, $request->getIp(true));
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// TODO: implement more test-cases
|
||||
|
||||
}
|
||||
@@ -19,10 +19,29 @@ class RouterCallbackExceptionHandlerTest extends \PHPUnit\Framework\TestCase
|
||||
throw new ExceptionHandlerException();
|
||||
});
|
||||
|
||||
TestRouter::debugNoReset('/404-url', 'get');
|
||||
TestRouter::router()->reset();
|
||||
TestRouter::debug('/404-url');
|
||||
}
|
||||
|
||||
$this->assertTrue(true);
|
||||
public function testExceptionHandlerCallback() {
|
||||
|
||||
TestRouter::group(['prefix' => null], function() {
|
||||
TestRouter::get('/', function() {
|
||||
return 'Hello world';
|
||||
});
|
||||
|
||||
TestRouter::get('/not-found', 'DummyController@method1');
|
||||
TestRouter::error(function(\Pecee\Http\Request $request, \Exception $exception) {
|
||||
|
||||
if($exception instanceof \Pecee\SimpleRouter\Exceptions\NotFoundHttpException && $exception->getCode() === 404) {
|
||||
return $request->setRewriteCallback(static function() {
|
||||
return 'success';
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
$result = TestRouter::debugOutput('/thisdoes-not/existssss', 'get');
|
||||
$this->assertEquals('success', $result);
|
||||
}
|
||||
|
||||
}
|
||||
+39
-3
@@ -3,20 +3,20 @@
|
||||
require_once 'Dummy/DummyMiddleware.php';
|
||||
require_once 'Dummy/DummyController.php';
|
||||
|
||||
class GroupTest extends \PHPUnit\Framework\TestCase
|
||||
class RouterGroupTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
|
||||
public function testGroupLoad()
|
||||
{
|
||||
$result = false;
|
||||
|
||||
TestRouter::group(['prefix' => '/group'], function () use(&$result) {
|
||||
TestRouter::group(['prefix' => '/group'], function () use (&$result) {
|
||||
$result = true;
|
||||
});
|
||||
|
||||
try {
|
||||
TestRouter::debug('/', 'get');
|
||||
} catch(\Exception $e) {
|
||||
} catch (\Exception $e) {
|
||||
|
||||
}
|
||||
$this->assertTrue($result);
|
||||
@@ -81,4 +81,40 @@ class GroupTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
}
|
||||
|
||||
public function testNamespaceExtend()
|
||||
{
|
||||
TestRouter::group(['namespace' => '\My\Namespace'], function () use (&$result) {
|
||||
|
||||
TestRouter::group(['namespace' => 'Service'], function () use (&$result) {
|
||||
|
||||
TestRouter::get('/test', function () use (&$result) {
|
||||
return \Pecee\SimpleRouter\SimpleRouter::router()->getRequest()->getLoadedRoute()->getNamespace();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
$namespace = TestRouter::debugOutput('/test');
|
||||
$this->assertEquals('\My\Namespace\Service', $namespace);
|
||||
}
|
||||
|
||||
public function testNamespaceOverwrite()
|
||||
{
|
||||
TestRouter::group(['namespace' => '\My\Namespace'], function () use (&$result) {
|
||||
|
||||
TestRouter::group(['namespace' => '\Service'], function () use (&$result) {
|
||||
|
||||
TestRouter::get('/test', function () use (&$result) {
|
||||
return \Pecee\SimpleRouter\SimpleRouter::router()->getRequest()->getLoadedRoute()->getNamespace();
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
$namespace = TestRouter::debugOutput('/test');
|
||||
$this->assertEquals('\Service', $namespace);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -25,4 +25,92 @@ class RouterPartialGroupTest extends \PHPUnit\Framework\TestCase
|
||||
$this->assertEquals('param2', $result2);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fixed issue with partial routes not loading child groups.
|
||||
* Reported in issue: #456
|
||||
*/
|
||||
public function testPartialGroupWithGroup() {
|
||||
|
||||
$lang = null;
|
||||
|
||||
$route1 = '/lang/da/test/';
|
||||
$route2 = '/lang/da/auth';
|
||||
$route3 = '/lang/da/auth/test';
|
||||
|
||||
TestRouter::partialGroup(
|
||||
'/lang/{test}/',
|
||||
function ($lang = 'en') use($route1, $route2, $route3) {
|
||||
|
||||
TestRouter::get('/test/', function () use($route1) {
|
||||
return $route1;
|
||||
});
|
||||
|
||||
TestRouter::group(['prefix' => '/auth/'], function () use($route2, $route3) {
|
||||
|
||||
TestRouter::get('/', function() use($route2) {
|
||||
return $route2;
|
||||
});
|
||||
|
||||
TestRouter::get('/test', function () use($route3){
|
||||
return $route3;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
);
|
||||
|
||||
$test1 = TestRouter::debugOutput('/lang/da/test', 'get', false);
|
||||
$test2 = TestRouter::debugOutput('/lang/da/auth', 'get', false);
|
||||
$test3 = TestRouter::debugOutput('/lang/da/auth/test', 'get', false);
|
||||
|
||||
$this->assertEquals($test1, $route1);
|
||||
$this->assertEquals($test2, $route2);
|
||||
$this->assertEquals($test3, $route3);
|
||||
|
||||
}
|
||||
|
||||
public function testPhp8CallUserFunc() {
|
||||
|
||||
TestRouter::router()->reset();
|
||||
|
||||
$result = false;
|
||||
$lang = 'de';
|
||||
|
||||
TestRouter::group(['prefix' => '/lang'], function() use(&$result) {
|
||||
TestRouter::get('/{lang}', function ($lang) use(&$result) {
|
||||
$result = $lang;
|
||||
});
|
||||
});
|
||||
|
||||
TestRouter::debug("/lang/$lang");
|
||||
|
||||
$this->assertEquals($lang, $result);
|
||||
|
||||
// Test partial group
|
||||
|
||||
$lang = 'de';
|
||||
$userId = 22;
|
||||
|
||||
$result1 = false;
|
||||
$result2 = false;
|
||||
|
||||
TestRouter::partialGroup(
|
||||
'/lang/{lang}/',
|
||||
function ($lang) use(&$result1, &$result2) {
|
||||
|
||||
$result1 = $lang;
|
||||
|
||||
TestRouter::get('/user/{userId}', function ($userId) use(&$result2) {
|
||||
$result2 = $userId;
|
||||
});
|
||||
});
|
||||
|
||||
TestRouter::debug("/lang/$lang/user/$userId");
|
||||
|
||||
$this->assertEquals($lang, $result1);
|
||||
$this->assertEquals($userId, $result2);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
@@ -6,7 +6,7 @@ require_once 'Dummy/Handler/ExceptionHandlerSecond.php';
|
||||
require_once 'Dummy/Handler/ExceptionHandlerThird.php';
|
||||
require_once 'Dummy/Middleware/RewriteMiddleware.php';
|
||||
|
||||
class RouteRewriteTest extends \PHPUnit\Framework\TestCase
|
||||
class RouterRewriteTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
|
||||
/**
|
||||
@@ -33,9 +33,9 @@ class RouteRewriteTest extends \PHPUnit\Framework\TestCase
|
||||
global $stack;
|
||||
$stack = [];
|
||||
|
||||
TestRouter::group(['exceptionHandler' => [ExceptionHandlerFirst::class, ExceptionHandlerSecond::class]], function () use ($stack) {
|
||||
TestRouter::group(['exceptionHandler' => [ExceptionHandlerFirst::class, ExceptionHandlerSecond::class]], function () {
|
||||
|
||||
TestRouter::group(['exceptionHandler' => ExceptionHandlerThird::class], function () use ($stack) {
|
||||
TestRouter::group(['prefix' => '/test', 'exceptionHandler' => ExceptionHandlerThird::class], function () {
|
||||
|
||||
TestRouter::get('/my-path', 'DummyController@method1');
|
||||
|
||||
@@ -43,21 +43,48 @@ class RouteRewriteTest extends \PHPUnit\Framework\TestCase
|
||||
});
|
||||
|
||||
try {
|
||||
TestRouter::debug('/my-non-existing-path', 'get');
|
||||
TestRouter::debug('/test/non-existing', 'get');
|
||||
} catch (\ResponseException $e) {
|
||||
|
||||
}
|
||||
|
||||
$expectedStack = [
|
||||
ExceptionHandlerFirst::class,
|
||||
ExceptionHandlerSecond::class,
|
||||
ExceptionHandlerThird::class,
|
||||
ExceptionHandlerSecond::class,
|
||||
ExceptionHandlerFirst::class,
|
||||
];
|
||||
|
||||
$this->assertEquals($expectedStack, $stack);
|
||||
|
||||
}
|
||||
|
||||
public function testStopMergeExceptionHandlers()
|
||||
{
|
||||
global $stack;
|
||||
$stack = [];
|
||||
|
||||
TestRouter::group(['prefix' => '/', 'exceptionHandler' => ExceptionHandlerFirst::class], function () {
|
||||
|
||||
TestRouter::group(['prefix' => '/admin', 'exceptionHandler' => ExceptionHandlerSecond::class, 'mergeExceptionHandlers' => false], function () {
|
||||
|
||||
TestRouter::get('/my-path', 'DummyController@method1');
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
try {
|
||||
TestRouter::debug('/admin/my-path-test', 'get');
|
||||
} catch (\Pecee\SimpleRouter\Exceptions\NotFoundHttpException $e) {
|
||||
|
||||
}
|
||||
|
||||
$expectedStack = [
|
||||
ExceptionHandlerSecond::class,
|
||||
];
|
||||
|
||||
$this->assertEquals($expectedStack, $stack);
|
||||
}
|
||||
|
||||
public function testRewriteExceptionMessage()
|
||||
{
|
||||
$this->expectException(\Pecee\SimpleRouter\Exceptions\NotFoundHttpException::class);
|
||||
|
||||
@@ -2,14 +2,33 @@
|
||||
|
||||
require_once 'Dummy/DummyMiddleware.php';
|
||||
require_once 'Dummy/DummyController.php';
|
||||
require_once 'Dummy/NSController.php';
|
||||
require_once 'Dummy/Exception/ExceptionHandlerException.php';
|
||||
|
||||
class RouterRouteTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
|
||||
/**
|
||||
* Issue #421: Incorrectly optional character in route
|
||||
*
|
||||
* @throws Exception
|
||||
*/
|
||||
public function testOptionalCharacterRoute()
|
||||
{
|
||||
$result = false;
|
||||
TestRouter::get('/api/v1/users/{userid}/projects/{id}/pages/{pageid?}', function () use (&$result) {
|
||||
$result = true;
|
||||
});
|
||||
|
||||
TestRouter::debug('/api/v1/users/1/projects/8399421535/pages/43/', 'get');
|
||||
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
public function testMultiParam()
|
||||
{
|
||||
$result = false;
|
||||
TestRouter::get('/test-{param1}-{param2}', function ($param1, $param2) use(&$result) {
|
||||
TestRouter::get('/test-{param1}-{param2}', function ($param1, $param2) use (&$result) {
|
||||
|
||||
if ($param1 === 'param1' && $param2 === 'param2') {
|
||||
$result = true;
|
||||
@@ -83,24 +102,59 @@ class RouterRouteTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
public function testPathParamRegex()
|
||||
{
|
||||
TestRouter::get('/{lang}/productscategories/{name}', 'DummyController@param', ['where' => ['lang' => '[a-z]+', 'name' => '[A-Za-z0-9\-]+']]);
|
||||
TestRouter::get('/{lang}/productscategories/{name}', 'DummyController@param', ['where' => ['lang' => '[a-z]+', 'name' => '[A-Za-z0-9-]+']]);
|
||||
$response = TestRouter::debugOutput('/it/productscategories/system', 'get');
|
||||
|
||||
$this->assertEquals('it, system', $response);
|
||||
}
|
||||
|
||||
public function testFixedDomain()
|
||||
{
|
||||
$result = false;
|
||||
TestRouter::request()->setHost('admin.world.com');
|
||||
|
||||
TestRouter::group(['domain' => 'admin.world.com'], function () use (&$result) {
|
||||
TestRouter::get('/test', function ($subdomain = null) use (&$result) {
|
||||
$result = true;
|
||||
});
|
||||
});
|
||||
|
||||
TestRouter::debug('/test', 'get');
|
||||
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
public function testFixedNotAllowedDomain()
|
||||
{
|
||||
$result = false;
|
||||
TestRouter::request()->setHost('other.world.com');
|
||||
|
||||
TestRouter::group(['domain' => 'admin.world.com'], function () use (&$result) {
|
||||
TestRouter::get('/', function ($subdomain = null) use (&$result) {
|
||||
$result = true;
|
||||
});
|
||||
});
|
||||
|
||||
try {
|
||||
TestRouter::debug('/', 'get');
|
||||
} catch(\Exception $e) {
|
||||
|
||||
}
|
||||
|
||||
$this->assertFalse($result);
|
||||
}
|
||||
|
||||
public function testDomainAllowedRoute()
|
||||
{
|
||||
$result = false;
|
||||
TestRouter::request()->setHost('hello.world.com');
|
||||
|
||||
TestRouter::group(['domain' => '{subdomain}.world.com'], function () use(&$result) {
|
||||
TestRouter::get('/test', function ($subdomain = null) use(&$result) {
|
||||
TestRouter::group(['domain' => '{subdomain}.world.com'], function () use (&$result) {
|
||||
TestRouter::get('/test', function ($subdomain = null) use (&$result) {
|
||||
$result = ($subdomain === 'hello');
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
TestRouter::debug('/test', 'get');
|
||||
|
||||
$this->assertTrue($result);
|
||||
@@ -113,8 +167,8 @@ class RouterRouteTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
$result = false;
|
||||
|
||||
TestRouter::group(['domain' => '{subdomain}.world.com'], function () use(&$result) {
|
||||
TestRouter::get('/test', function ($subdomain = null) use(&$result) {
|
||||
TestRouter::group(['domain' => '{subdomain}.world.com'], function () use (&$result) {
|
||||
TestRouter::get('/test', function ($subdomain = null) use (&$result) {
|
||||
$result = ($subdomain === 'hello');
|
||||
});
|
||||
});
|
||||
@@ -127,17 +181,33 @@ class RouterRouteTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
public function testRegEx()
|
||||
{
|
||||
TestRouter::get('/my/{path}', 'DummyController@method1')->where(['path' => '[a-zA-Z\-]+']);
|
||||
TestRouter::get('/my/{path}', 'DummyController@method1')->where(['path' => '[a-zA-Z-]+']);
|
||||
TestRouter::debug('/my/custom-path', 'get');
|
||||
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
public function testParameterDefaultValue() {
|
||||
public function testParametersWithDashes()
|
||||
{
|
||||
|
||||
$defaultVariable = null;
|
||||
|
||||
TestRouter::get('/my/{path?}', function($path = 'working') use(&$defaultVariable) {
|
||||
TestRouter::get('/my/{path}', function ($path = 'working') use (&$defaultVariable) {
|
||||
$defaultVariable = $path;
|
||||
});
|
||||
|
||||
TestRouter::debug('/my/hello-motto-man');
|
||||
|
||||
$this->assertEquals('hello-motto-man', $defaultVariable);
|
||||
|
||||
}
|
||||
|
||||
public function testParameterDefaultValue()
|
||||
{
|
||||
|
||||
$defaultVariable = null;
|
||||
|
||||
TestRouter::get('/my/{path?}', function ($path = 'working') use (&$defaultVariable) {
|
||||
$defaultVariable = $path;
|
||||
});
|
||||
|
||||
@@ -149,7 +219,7 @@ class RouterRouteTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
public function testDefaultParameterRegex()
|
||||
{
|
||||
TestRouter::get('/my/{path}', 'DummyController@param', ['defaultParameterRegex' => '[\w\-]+']);
|
||||
TestRouter::get('/my/{path}', 'DummyController@param', ['defaultParameterRegex' => '[\w-]+']);
|
||||
$output = TestRouter::debugOutput('/my/custom-regex', 'get');
|
||||
|
||||
$this->assertEquals('custom-regex', $output);
|
||||
@@ -157,7 +227,7 @@ class RouterRouteTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
public function testDefaultParameterRegexGroup()
|
||||
{
|
||||
TestRouter::group(['defaultParameterRegex' => '[\w\-]+'], function() {
|
||||
TestRouter::group(['defaultParameterRegex' => '[\w-]+'], function () {
|
||||
TestRouter::get('/my/{path}', 'DummyController@param');
|
||||
});
|
||||
|
||||
@@ -166,4 +236,36 @@ class RouterRouteTest extends \PHPUnit\Framework\TestCase
|
||||
$this->assertEquals('custom-regex', $output);
|
||||
}
|
||||
|
||||
public function testClassHint()
|
||||
{
|
||||
TestRouter::get('/my/test/url', ['DummyController', 'method1']);
|
||||
TestRouter::all('/my/test/url', ['DummyController', 'method1']);
|
||||
TestRouter::match(['put', 'get', 'post'], '/my/test/url', ['DummyController', 'method1']);
|
||||
|
||||
TestRouter::debug('/my/test/url', 'get');
|
||||
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
public function testDefaultNameSpaceOverload()
|
||||
{
|
||||
TestRouter::setDefaultNamespace('DefaultNamespace\\Controllers');
|
||||
TestRouter::get('/test', [\MyNamespace\NSController::class, 'method']);
|
||||
|
||||
$result = TestRouter::debugOutput('/test');
|
||||
|
||||
$this->assertTrue( (bool)$result);
|
||||
}
|
||||
|
||||
public function testSameRoutes()
|
||||
{
|
||||
TestRouter::get('/recipe', 'DummyController@method1')->name('add');
|
||||
TestRouter::post('/recipe', 'DummyController@method2')->name('edit');
|
||||
|
||||
TestRouter::debugNoReset('/recipe', 'post');
|
||||
TestRouter::debug('/recipe', 'get');
|
||||
|
||||
$this->assertTrue(true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -11,7 +11,7 @@ class RouterUrlTest extends \PHPUnit\Framework\TestCase
|
||||
{
|
||||
TestRouter::get('/', 'DummyController@method1');
|
||||
TestRouter::get('/page/{id?}', 'DummyController@method1');
|
||||
TestRouter::get('/test-output', function() {
|
||||
TestRouter::get('/test-output', function () {
|
||||
return 'return value';
|
||||
});
|
||||
|
||||
@@ -30,8 +30,8 @@ class RouterUrlTest extends \PHPUnit\Framework\TestCase
|
||||
public function testUnicodeCharacters()
|
||||
{
|
||||
// Test spanish characters
|
||||
TestRouter::get('/cursos/listado/{listado?}/{category?}', 'DummyController@method1', ['defaultParameterRegex' => '[\w\p{L}\s-]+']);
|
||||
TestRouter::get('/test/{param}', 'DummyController@method1', ['defaultParameterRegex' => '[\w\p{L}\s-\í]+']);
|
||||
TestRouter::get('/cursos/listado/{listado?}/{category?}', 'DummyController@method1', ['defaultParameterRegex' => '[\w\p{L}\s\-]+']);
|
||||
TestRouter::get('/test/{param}', 'DummyController@method1', ['defaultParameterRegex' => '[\w\p{L}\s\-\í]+']);
|
||||
TestRouter::debugNoReset('/cursos/listado/especialidad/cirugía local', 'get');
|
||||
|
||||
$this->assertEquals('/cursos/listado/{listado?}/{category?}/', TestRouter::router()->getRequest()->getLoadedRoute()->getUrl());
|
||||
@@ -78,10 +78,11 @@ class RouterUrlTest extends \PHPUnit\Framework\TestCase
|
||||
public function testSimilarUrls()
|
||||
{
|
||||
// Match normal route on alias
|
||||
TestRouter::resource('/url11', 'DummyController@method1');
|
||||
TestRouter::resource('/url1', 'DummyController@method1', ['as' => 'match']);
|
||||
TestRouter::get('/url11', 'DummyController@method1');
|
||||
TestRouter::get('/url22', 'DummyController@method2');
|
||||
TestRouter::get('/url33', 'DummyController@method2')->name('match');
|
||||
|
||||
TestRouter::debugNoReset('/url1', 'get');
|
||||
TestRouter::debugNoReset('/url33', 'get');
|
||||
|
||||
$this->assertEquals(TestRouter::getUrl('match'), TestRouter::getUrl());
|
||||
|
||||
@@ -170,4 +171,197 @@ class RouterUrlTest extends \PHPUnit\Framework\TestCase
|
||||
|
||||
}
|
||||
|
||||
public function testCustomRegex()
|
||||
{
|
||||
TestRouter::request()->setHost('google.com');
|
||||
|
||||
TestRouter::get('/admin/', function () {
|
||||
return 'match';
|
||||
})->setMatch('/^\/admin\/?(.*)/i');
|
||||
|
||||
$output = TestRouter::debugOutput('/admin/asd/bec/123', 'get');
|
||||
$this->assertEquals('match', $output);
|
||||
|
||||
TestRouter::router()->reset();
|
||||
}
|
||||
|
||||
public function testCustomRegexWithParameter()
|
||||
{
|
||||
TestRouter::request()->setHost('google.com');
|
||||
|
||||
$results = '';
|
||||
|
||||
TestRouter::get('/tester/{param}', function ($param = null) use($results) {
|
||||
return $results = $param;
|
||||
})->setMatch('/(.*)/i');
|
||||
|
||||
$output = TestRouter::debugOutput('/tester/abepik/ko');
|
||||
$this->assertEquals('/tester/abepik/ko/', $output);
|
||||
}
|
||||
|
||||
public function testRenderMultipleRoutesDisabled()
|
||||
{
|
||||
TestRouter::router()->setRenderMultipleRoutes(false);
|
||||
|
||||
$result = false;
|
||||
|
||||
TestRouter::get('/', function () use (&$result) {
|
||||
$result = true;
|
||||
});
|
||||
|
||||
TestRouter::get('/', function () use (&$result) {
|
||||
$result = false;
|
||||
});
|
||||
|
||||
TestRouter::debug('/');
|
||||
|
||||
$this->assertTrue($result);
|
||||
}
|
||||
|
||||
public function testRenderMultipleRoutesEnabled()
|
||||
{
|
||||
TestRouter::router()->setRenderMultipleRoutes(true);
|
||||
|
||||
$result = [];
|
||||
|
||||
TestRouter::get('/', function () use (&$result) {
|
||||
$result[] = 'route1';
|
||||
});
|
||||
|
||||
TestRouter::get('/', function () use (&$result) {
|
||||
$result[] = 'route2';
|
||||
});
|
||||
|
||||
TestRouter::debug('/');
|
||||
|
||||
$this->assertCount(2, $result);
|
||||
}
|
||||
|
||||
public function testDefaultNamespace()
|
||||
{
|
||||
TestRouter::setDefaultNamespace('\\Default\\Namespace');
|
||||
|
||||
TestRouter::get('/', 'DummyController@method1', ['as' => 'home']);
|
||||
|
||||
TestRouter::group([
|
||||
'namespace' => 'Appended\Namespace',
|
||||
'prefix' => '/horses',
|
||||
], function () {
|
||||
|
||||
TestRouter::get('/', 'DummyController@method1');
|
||||
|
||||
TestRouter::group([
|
||||
'namespace' => '\\New\\Namespace',
|
||||
'prefix' => '/race',
|
||||
], function () {
|
||||
|
||||
TestRouter::get('/', 'DummyController@method1');
|
||||
|
||||
});
|
||||
});
|
||||
|
||||
// Test appended namespace
|
||||
|
||||
$class = null;
|
||||
|
||||
try {
|
||||
TestRouter::debugNoReset('/horses/');
|
||||
} catch (\Pecee\SimpleRouter\Exceptions\ClassNotFoundHttpException $e) {
|
||||
$class = $e->getClass();
|
||||
}
|
||||
|
||||
$this->assertEquals('\\Default\\Namespace\\Appended\Namespace\\DummyController', $class);
|
||||
|
||||
// Test overwritten namespace
|
||||
|
||||
$class = null;
|
||||
|
||||
try {
|
||||
TestRouter::debugNoReset('/horses/race');
|
||||
} catch (\Pecee\SimpleRouter\Exceptions\ClassNotFoundHttpException $e) {
|
||||
$class = $e->getClass();
|
||||
}
|
||||
|
||||
$this->assertEquals('\\New\\Namespace\\DummyController', $class);
|
||||
|
||||
TestRouter::router()->reset();
|
||||
}
|
||||
|
||||
public function testGroupPrefix() {
|
||||
|
||||
$result = false;
|
||||
|
||||
TestRouter::group(['prefix' => '/lang/{lang}'], function () use(&$result) {
|
||||
|
||||
TestRouter::get('/test', function() use(&$result) {
|
||||
$result = true;
|
||||
});
|
||||
});
|
||||
|
||||
TestRouter::debug('/lang/da/test');
|
||||
|
||||
$this->assertTrue($result);
|
||||
|
||||
// Test group prefix sub-route
|
||||
|
||||
$result = null;
|
||||
$expectedResult = 28;
|
||||
|
||||
TestRouter::group(['prefix' => '/lang/{lang}'], function () use(&$result) {
|
||||
|
||||
TestRouter::get('/horse/{horseType}', function($horseType) use(&$result) {
|
||||
$result = false;
|
||||
});
|
||||
|
||||
TestRouter::get('/user/{userId}', function($userId) use(&$result) {
|
||||
$result = $userId;
|
||||
});
|
||||
});
|
||||
|
||||
TestRouter::debug("/lang/da/user/$expectedResult");
|
||||
|
||||
$this->assertEquals($expectedResult, $result);
|
||||
|
||||
}
|
||||
|
||||
public function testPassParameter() {
|
||||
|
||||
$result = false;
|
||||
$expectedLanguage = 'da';
|
||||
|
||||
TestRouter::group(['prefix' => '/lang/{lang}'], function ($language) use(&$result) {
|
||||
|
||||
TestRouter::get('/test', function($language) use(&$result) {
|
||||
$result = $language;
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
TestRouter::debug("/lang/$expectedLanguage/test");
|
||||
|
||||
$this->assertEquals($expectedLanguage, $result);
|
||||
|
||||
}
|
||||
|
||||
public function testPassParameterDeep() {
|
||||
|
||||
$result = false;
|
||||
$expectedLanguage = 'da';
|
||||
|
||||
TestRouter::group(['prefix' => '/lang/{lang}'], function ($language) use(&$result) {
|
||||
|
||||
TestRouter::group(['prefix' => '/admin'], function($language) use(&$result) {
|
||||
TestRouter::get('/test', function($language) use(&$result) {
|
||||
$result = $language;
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
TestRouter::debug("/lang/$expectedLanguage/admin/test");
|
||||
|
||||
$this->assertEquals($expectedLanguage, $result);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+16
-8
@@ -3,7 +3,12 @@
|
||||
class TestRouter extends \Pecee\SimpleRouter\SimpleRouter
|
||||
{
|
||||
|
||||
public static function debugNoReset($testUrl, $testMethod = 'get')
|
||||
public function __construct()
|
||||
{
|
||||
static::request()->setHost('testhost.com');
|
||||
}
|
||||
|
||||
public static function debugNoReset(string $testUrl, string $testMethod = 'get'): void
|
||||
{
|
||||
$request = static::request();
|
||||
|
||||
@@ -13,28 +18,31 @@ class TestRouter extends \Pecee\SimpleRouter\SimpleRouter
|
||||
static::start();
|
||||
}
|
||||
|
||||
public static function debug($testUrl, $testMethod = 'get')
|
||||
public static function debug(string $testUrl, string $testMethod = 'get', bool $reset = true): void
|
||||
{
|
||||
try {
|
||||
static::debugNoReset($testUrl, $testMethod);
|
||||
} catch(\Exception $e) {
|
||||
} catch (\Exception $e) {
|
||||
static::$defaultNamespace = null;
|
||||
static::router()->reset();
|
||||
throw $e;
|
||||
}
|
||||
|
||||
static::router()->reset();
|
||||
if ($reset === true) {
|
||||
static::$defaultNamespace = null;
|
||||
static::router()->reset();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static function debugOutput($testUrl, $testMethod = 'get')
|
||||
public static function debugOutput(string $testUrl, string $testMethod = 'get', bool $reset = true): string
|
||||
{
|
||||
$response = null;
|
||||
|
||||
// Route request
|
||||
ob_start();
|
||||
static::debug($testUrl, $testMethod);
|
||||
$response = ob_get_contents();
|
||||
ob_end_clean();
|
||||
static::debug($testUrl, $testMethod, $reset);
|
||||
$response = ob_get_clean();
|
||||
|
||||
// Return response
|
||||
return $response;
|
||||
|
||||
Reference in New Issue
Block a user