Skip to content

Instantly share code, notes, and snippets.

@paulpwo
Created April 7, 2016 18:02
Show Gist options
  • Save paulpwo/2f82d89e6d6710c166878498e4665a6e to your computer and use it in GitHub Desktop.
Save paulpwo/2f82d89e6d6710c166878498e4665a6e to your computer and use it in GitHub Desktop.
Slim Framework 3 Skeleton Application with blade templates
This gist exceeds the recommended number of files (~10). To access all files, please clone this gist.
/vendor/
.idea/
/logs/*
!/logs/README.md
<?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$/vendor/pimple/pimple/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/vendor/psr/log" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/vendor/nikic/fast-route/test" isTestSource="true" packagePrefix="FastRoute" />
<sourceFolder url="file://$MODULE_DIR$/vendor/nikic/fast-route/src" isTestSource="false" packagePrefix="FastRoute" />
<sourceFolder url="file://$MODULE_DIR$/vendor/container-interop/container-interop/src" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/vendor/slim/slim" isTestSource="false" />
<sourceFolder url="file://$MODULE_DIR$/vendor/monolog/monolog/tests" isTestSource="true" />
<sourceFolder url="file://$MODULE_DIR$/vendor/monolog/monolog/src" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
<OptionsSetting value="true" id="Add" />
<OptionsSetting value="true" id="Remove" />
<OptionsSetting value="true" id="Checkout" />
<OptionsSetting value="true" id="Update" />
<OptionsSetting value="true" id="Status" />
<OptionsSetting value="true" id="Edit" />
<ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" />
</component>
<component name="ProjectPlainTextFileTypeManager">
<file url="file://$USER_HOME$/htdocs/slim3-skeleton-blade/templates/1c2da57eb3424377b40d341d8f8eef1840c6f636.php" />
</component>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="234160e1-f49c-48be-9733-96abab26589b" name="Default" comment="" />
<ignored path="app-manager2.iws" />
<ignored path=".idea/workspace.xml" />
<ignored path=".idea/dataSources.local.xml" />
<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="ChangesViewManager" flattened_view="true" show_ignored="false" />
<component name="CreatePatchCommitExecutor">
<option name="PATCH_PATH" value="" />
</component>
<component name="ExecutionTargetManager" SELECTED_TARGET="default_target" />
<component name="FavoritesManager">
<favorites_list name="app-manager2" />
</component>
<component name="FileEditorManager">
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
<file leaf-file-name="index.php" pinned="false" current-in-tab="false">
<entry file="file://$USER_HOME$/htdocs/slim3-skeleton-blade/public/index.php">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="-9.807693">
<caret line="20" column="42" selection-start-line="20" selection-start-column="42" selection-end-line="20" selection-end-column="42" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="composer.json" pinned="false" current-in-tab="false">
<entry file="file://$USER_HOME$/htdocs/slim3-skeleton-blade/composer.json">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="-6.5384617">
<caret line="10" column="26" selection-start-line="10" selection-start-column="26" selection-end-line="10" selection-end-column="26" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name=".gitignore" pinned="false" current-in-tab="true">
<entry file="file://$USER_HOME$/htdocs/slim3-skeleton-blade/.gitignore">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.08121019">
<caret line="3" column="16" selection-start-line="3" selection-start-column="16" selection-end-line="3" selection-end-column="16" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="index.blade.php" pinned="false" current-in-tab="false">
<entry file="file://$USER_HOME$/htdocs/slim3-skeleton-blade/templates/index.blade.php">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="-2.6153846">
<caret line="4" column="12" selection-start-line="4" selection-start-column="12" selection-end-line="4" selection-end-column="12" />
<folding />
</state>
</provider>
</entry>
</file>
<file leaf-file-name="routes.php" pinned="false" current-in-tab="false">
<entry file="file://$USER_HOME$/htdocs/slim3-skeleton-blade/src/routes.php">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="-6.5384617">
<caret line="10" column="90" selection-start-line="10" selection-start-column="90" selection-end-line="10" selection-end-column="90" />
<folding />
</state>
</provider>
</entry>
</file>
</leaf>
</component>
<component name="IdeDocumentHistory">
<option name="CHANGED_PATHS">
<list>
<option value="$USER_HOME$/htdocs/app-manager2/index.php" />
<option value="$USER_HOME$/htdocs/app-manager2/src/settings.php" />
<option value="$USER_HOME$/htdocs/app-manager2/src/routes.php" />
<option value="$USER_HOME$/htdocs/app-manager2/templates/index.blade.php" />
<option value="$USER_HOME$/htdocs/app-manager2/vendor/hiropeke/slim-blade-view/src/Blade.php" />
<option value="$USER_HOME$/htdocs/app-manager2/public/index.php" />
<option value="$USER_HOME$/htdocs/app-manager2/composer.json" />
<option value="$USER_HOME$/htdocs/app-manager2/.gitignore" />
<option value="$USER_HOME$/htdocs/app-manager2/README.md" />
</list>
</option>
</component>
<component name="JsBuildToolGruntFileManager" detection-done="true" />
<component name="JsBuildToolPackageJson" detection-done="true" />
<component name="JsGulpfileManager">
<detection-done>true</detection-done>
</component>
<component name="PhpWorkspaceProjectConfiguration" backward_compatibility_performed="true" />
<component name="ProjectFrameBounds">
<option name="x" value="34" />
<option name="y" value="23" />
<option name="width" value="1327" />
<option name="height" value="725" />
</component>
<component name="ProjectLevelVcsManager" settingsEditedManually="false">
<OptionsSetting value="true" id="Add" />
<OptionsSetting value="true" id="Remove" />
<OptionsSetting value="true" id="Checkout" />
<OptionsSetting value="true" id="Update" />
<OptionsSetting value="true" id="Status" />
<OptionsSetting value="true" id="Edit" />
<ConfirmationsSetting value="0" id="Add" />
<ConfirmationsSetting value="0" id="Remove" />
</component>
<component name="ProjectView">
<navigator currentView="ProjectPane" proportions="" version="1">
<flattenPackages />
<showMembers />
<showModules />
<showLibraryContents />
<hideEmptyPackages />
<abbreviatePackageNames />
<autoscrollToSource />
<autoscrollFromSource />
<sortByType />
<manualOrder />
<foldersAlwaysOnTop value="true" />
</navigator>
<panes>
<pane id="Scope" />
<pane id="ProjectPane">
<subPane>
<PATH>
<PATH_ELEMENT>
<option name="myItemId" value="app-manager2" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="slim3-skeleton-blade" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
</PATH>
<PATH>
<PATH_ELEMENT>
<option name="myItemId" value="app-manager2" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="slim3-skeleton-blade" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="vendor" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
</PATH>
<PATH>
<PATH_ELEMENT>
<option name="myItemId" value="app-manager2" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="slim3-skeleton-blade" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="templates" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
</PATH>
<PATH>
<PATH_ELEMENT>
<option name="myItemId" value="app-manager2" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.ProjectViewProjectNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="slim3-skeleton-blade" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
<PATH_ELEMENT>
<option name="myItemId" value="logs" />
<option name="myItemType" value="com.intellij.ide.projectView.impl.nodes.PsiDirectoryNode" />
</PATH_ELEMENT>
</PATH>
</subPane>
</pane>
<pane id="Scratches" />
</panes>
</component>
<component name="PropertiesComponent">
<property name="last_opened_file_path" value="$USER_HOME$/htdocs/app-manager2" />
<property name="WebServerToolWindowFactoryState" value="false" />
<property name="js-jscs-nodeInterpreter" value="/usr/local/bin/node" />
</component>
<component name="RunManager">
<configuration default="true" type="JavascriptDebugType" factoryName="JavaScript Debug">
<method />
</configuration>
<configuration default="true" type="PHPUnitRunConfigurationType" factoryName="PHPUnit">
<TestRunner />
<method />
</configuration>
<configuration default="true" type="PhpBehatConfigurationType" factoryName="Behat">
<BehatRunner />
<method />
</configuration>
<configuration default="true" type="PhpLocalRunConfigurationType" factoryName="PHP Console">
<method />
</configuration>
<configuration default="true" type="js.build_tools.gulp" factoryName="Gulp.js">
<node-options />
<gulpfile />
<tasks />
<arguments />
<envs />
<method />
</configuration>
<configuration default="true" type="js.build_tools.npm" factoryName="npm">
<command value="run-script" />
<scripts />
<envs />
<method />
</configuration>
</component>
<component name="ShelveChangesManager" show_recycled="false" />
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="234160e1-f49c-48be-9733-96abab26589b" name="Default" comment="" />
<created>1460042437656</created>
<option name="number" value="Default" />
<updated>1460042437656</updated>
</task>
<servers />
</component>
<component name="ToolWindowManager">
<frame x="34" y="23" width="1327" height="725" extended-state="0" />
<editor active="true" />
<layout>
<window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.24943481" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" />
<window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" />
<window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" />
<window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
<window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" />
<window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" />
<window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" />
<window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" />
<window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" />
<window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" />
<window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" />
<window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" />
<window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" />
</layout>
</component>
<component name="UnknownFeatures">
<option featureType="com.intellij.fileTypeFactory" implementationName="*.gitignore" />
</component>
<component name="VcsContentAnnotationSettings">
<option name="myLimit" value="2678400000" />
</component>
<component name="XDebuggerManager">
<breakpoint-manager />
<watches-manager />
</component>
<component name="editorHistoryManager">
<entry file="file://$USER_HOME$/htdocs/slim3-skeleton-blade/vendor/hiropeke/slim-blade-view/README.md">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/htdocs/slim3-skeleton-blade/vendor/hiropeke/slim-blade-view/LICENSE">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/htdocs/slim3-skeleton-blade/vendor/hiropeke/slim-blade-view/phpunit.xml.dist">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/htdocs/slim3-skeleton-blade/vendor/hiropeke/slim-blade-view/tests/BladeTest.php">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="-1.2142857">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/htdocs/slim3-skeleton-blade/vendor/hiropeke/slim-blade-view/tests/templates/example.blade.php">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/htdocs/slim3-skeleton-blade/vendor/philo/laravel-blade/readme.md">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="-0.640599">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/htdocs/slim3-skeleton-blade/vendor/illuminate/view/composer.json">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/htdocs/slim3-skeleton-blade/vendor/illuminate/view/View.php">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="-10.295681">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/htdocs/slim3-skeleton-blade/vendor/hiropeke/slim-blade-view/src/Blade.php">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.91528237">
<caret line="170" column="0" selection-start-line="170" selection-start-column="0" selection-end-line="170" selection-end-column="0" />
<folding>
<element signature="e#30#63#0#PHP" expanded="false" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/htdocs/slim3-skeleton-blade/vendor/philo/laravel-blade/src/Blade.php">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="-0.14119601">
<caret line="34" column="25" selection-start-line="34" selection-start-column="25" selection-end-line="34" selection-end-column="25" />
<folding>
<element signature="e#30#65#0#PHP" expanded="false" />
</folding>
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/htdocs/slim3-skeleton-blade/src/routes.php">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="-6.5384617">
<caret line="10" column="90" selection-start-line="10" selection-start-column="90" selection-end-line="10" selection-end-column="90" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/htdocs/slim3-skeleton-blade/templates/index.blade.php">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="-2.6153846">
<caret line="4" column="12" selection-start-line="4" selection-start-column="12" selection-end-line="4" selection-end-column="12" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/htdocs/slim3-skeleton-blade/src/settings.php">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.19767442">
<caret line="7" column="31" selection-start-line="7" selection-start-column="31" selection-end-line="7" selection-end-column="56" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/htdocs/slim3-skeleton-blade/cache/1c2da57eb3424377b40d341d8f8eef1840c6f636.php">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/htdocs/slim3-skeleton-blade/public/index.php">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="-9.807693">
<caret line="20" column="42" selection-start-line="20" selection-start-column="42" selection-end-line="20" selection-end-column="42" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/htdocs/slim3-skeleton-blade/logs/README.md">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/htdocs/slim3-skeleton-blade/logs/app.log">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.0">
<caret line="0" column="0" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/htdocs/slim3-skeleton-blade/composer.json">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="-6.5384617">
<caret line="10" column="26" selection-start-line="10" selection-start-column="26" selection-end-line="10" selection-end-column="26" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/htdocs/slim3-skeleton-blade/README.md">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.028286189">
<caret line="1" column="0" selection-start-line="1" selection-start-column="0" selection-end-line="1" selection-end-column="0" />
<folding />
</state>
</provider>
</entry>
<entry file="file://$USER_HOME$/htdocs/slim3-skeleton-blade/.gitignore">
<provider selected="true" editor-type-id="text-editor">
<state vertical-scroll-proportion="0.08121019">
<caret line="3" column="16" selection-start-line="3" selection-start-column="16" selection-end-line="3" selection-end-column="16" />
<folding />
</state>
</provider>
</entry>
</component>
</project>
<!DOCTYPE html>
<html lang="en">
<body>
hola
<?php echo e($variable); ?>
</body>
</html>
{
"name": "slim/slim-skeleton-blade",
"description": "skeleton SlimFramework 3 with slim/slim-skeleton and hiropeke/slim-blade-view prepared for function blade templates",
"keywords": ["microframework","rest","router", "psr7", "blade", "SlimFramewok"],
"homepage": "",
"license": "MIT",
"authors": [
{
"name": "Paul Osinga",
"email": "paulpwo@gmail.com",
"homepage": "#"
}
],
"require": {
"php": ">=5.5.0",
"slim/slim": "^3.1",
"slim/php-view": "^2.0",
"monolog/monolog": "^1.17",
"hiropeke/slim-blade-view": "^0.1.1"
}
}
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
"This file is @generated automatically"
],
"hash": "f2fd5258e62bb794a32f32bb8f230ced",
"content-hash": "c582aed7b8d9c7fde3815f5043759de0",
"packages": [
{
"name": "container-interop/container-interop",
"version": "1.1.0",
"source": {
"type": "git",
"url": "https://github.com/container-interop/container-interop.git",
"reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/container-interop/container-interop/zipball/fc08354828f8fd3245f77a66b9e23a6bca48297e",
"reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e",
"shasum": ""
},
"type": "library",
"autoload": {
"psr-4": {
"Interop\\Container\\": "src/Interop/Container/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "Promoting the interoperability of container objects (DIC, SL, etc.)",
"time": "2014-12-30 15:22:37"
},
{
"name": "doctrine/inflector",
"version": "v1.1.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/inflector.git",
"reference": "90b2128806bfde671b6952ab8bea493942c1fdae"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/inflector/zipball/90b2128806bfde671b6952ab8bea493942c1fdae",
"reference": "90b2128806bfde671b6952ab8bea493942c1fdae",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": "4.*"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}
},
"autoload": {
"psr-0": {
"Doctrine\\Common\\Inflector\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Common String Manipulations with regard to casing and singular/plural rules.",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"inflection",
"pluralize",
"singularize",
"string"
],
"time": "2015-11-06 14:35:42"
},
{
"name": "hiropeke/slim-blade-view",
"version": "0.1.1",
"source": {
"type": "git",
"url": "https://github.com/hiropeke/Slim-Blade-View.git",
"reference": "9cdea69285acbf712463b38a9bb0b5ce23c4c98c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/hiropeke/Slim-Blade-View/zipball/9cdea69285acbf712463b38a9bb0b5ce23c4c98c",
"reference": "9cdea69285acbf712463b38a9bb0b5ce23c4c98c",
"shasum": ""
},
"require": {
"illuminate/view": "5.*",
"philo/laravel-blade": "3.*",
"psr/http-message": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^5.0",
"slim/slim": "^3.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Slim\\Views\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Hiroaki Matsuura",
"email": "hiropeke.jp@gmail.com"
}
],
"description": "Slim Framework 3 view helper built on the Blade component",
"keywords": [
"blade",
"framework",
"renderer",
"slim",
"template",
"view"
],
"time": "2016-03-11 02:32:00"
},
{
"name": "illuminate/container",
"version": "v5.2.28",
"source": {
"type": "git",
"url": "https://github.com/illuminate/container.git",
"reference": "1e156f8017490f5583ab161030bf839c77c95e54"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/container/zipball/1e156f8017490f5583ab161030bf839c77c95e54",
"reference": "1e156f8017490f5583ab161030bf839c77c95e54",
"shasum": ""
},
"require": {
"illuminate/contracts": "5.2.*",
"php": ">=5.5.9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.2-dev"
}
},
"autoload": {
"psr-4": {
"Illuminate\\Container\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylorotwell@gmail.com"
}
],
"description": "The Illuminate Container package.",
"homepage": "http://laravel.com",
"time": "2016-03-16 17:19:17"
},
{
"name": "illuminate/contracts",
"version": "v5.2.28",
"source": {
"type": "git",
"url": "https://github.com/illuminate/contracts.git",
"reference": "411b851962c211078ade7664a6976e77a78cd2a5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/contracts/zipball/411b851962c211078ade7664a6976e77a78cd2a5",
"reference": "411b851962c211078ade7664a6976e77a78cd2a5",
"shasum": ""
},
"require": {
"php": ">=5.5.9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.2-dev"
}
},
"autoload": {
"psr-4": {
"Illuminate\\Contracts\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylorotwell@gmail.com"
}
],
"description": "The Illuminate Contracts package.",
"homepage": "http://laravel.com",
"time": "2016-03-07 20:37:17"
},
{
"name": "illuminate/events",
"version": "v5.2.28",
"source": {
"type": "git",
"url": "https://github.com/illuminate/events.git",
"reference": "5a5e5d72bf3a2d01d8b15e89440026a60bc4a81b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/events/zipball/5a5e5d72bf3a2d01d8b15e89440026a60bc4a81b",
"reference": "5a5e5d72bf3a2d01d8b15e89440026a60bc4a81b",
"shasum": ""
},
"require": {
"illuminate/container": "5.2.*",
"illuminate/contracts": "5.2.*",
"illuminate/support": "5.2.*",
"php": ">=5.5.9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.2-dev"
}
},
"autoload": {
"psr-4": {
"Illuminate\\Events\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylorotwell@gmail.com"
}
],
"description": "The Illuminate Events package.",
"homepage": "http://laravel.com",
"time": "2016-01-01 01:00:19"
},
{
"name": "illuminate/filesystem",
"version": "v5.2.28",
"source": {
"type": "git",
"url": "https://github.com/illuminate/filesystem.git",
"reference": "e197f38660beab95743d9d5565d0f11d956288ea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/filesystem/zipball/e197f38660beab95743d9d5565d0f11d956288ea",
"reference": "e197f38660beab95743d9d5565d0f11d956288ea",
"shasum": ""
},
"require": {
"illuminate/contracts": "5.2.*",
"illuminate/support": "5.2.*",
"php": ">=5.5.9",
"symfony/finder": "2.8.*|3.0.*"
},
"suggest": {
"league/flysystem": "Required to use the Flysystem local and FTP drivers (~1.0).",
"league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (~1.0).",
"league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (~1.0)."
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.2-dev"
}
},
"autoload": {
"psr-4": {
"Illuminate\\Filesystem\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylorotwell@gmail.com"
}
],
"description": "The Illuminate Filesystem package.",
"homepage": "http://laravel.com",
"time": "2016-03-21 14:55:26"
},
{
"name": "illuminate/support",
"version": "v5.2.28",
"source": {
"type": "git",
"url": "https://github.com/illuminate/support.git",
"reference": "e4aa03c5f26db752e838354a7d71b85e6138f4ec"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/support/zipball/e4aa03c5f26db752e838354a7d71b85e6138f4ec",
"reference": "e4aa03c5f26db752e838354a7d71b85e6138f4ec",
"shasum": ""
},
"require": {
"doctrine/inflector": "~1.0",
"ext-mbstring": "*",
"illuminate/contracts": "5.2.*",
"paragonie/random_compat": "~1.4",
"php": ">=5.5.9"
},
"suggest": {
"illuminate/filesystem": "Required to use the composer class (5.2.*).",
"jeremeamia/superclosure": "Required to be able to serialize closures (~2.2).",
"symfony/polyfill-php56": "Required to use the hash_equals function on PHP 5.5 (~1.0).",
"symfony/process": "Required to use the composer class (2.8.*|3.0.*).",
"symfony/var-dumper": "Improves the dd function (2.8.*|3.0.*)."
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.2-dev"
}
},
"autoload": {
"psr-4": {
"Illuminate\\Support\\": ""
},
"files": [
"helpers.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylorotwell@gmail.com"
}
],
"description": "The Illuminate Support package.",
"homepage": "http://laravel.com",
"time": "2016-03-30 18:18:45"
},
{
"name": "illuminate/view",
"version": "v5.2.28",
"source": {
"type": "git",
"url": "https://github.com/illuminate/view.git",
"reference": "a0e77662f06eaae851469ebf132868c9024a259d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/view/zipball/a0e77662f06eaae851469ebf132868c9024a259d",
"reference": "a0e77662f06eaae851469ebf132868c9024a259d",
"shasum": ""
},
"require": {
"illuminate/container": "5.2.*",
"illuminate/contracts": "5.2.*",
"illuminate/events": "5.2.*",
"illuminate/filesystem": "5.2.*",
"illuminate/support": "5.2.*",
"php": ">=5.5.9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.2-dev"
}
},
"autoload": {
"psr-4": {
"Illuminate\\View\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylorotwell@gmail.com"
}
],
"description": "The Illuminate View package.",
"homepage": "http://laravel.com",
"time": "2016-03-28 15:19:10"
},
{
"name": "monolog/monolog",
"version": "1.17.2",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/monolog.git",
"reference": "bee7f0dc9c3e0b69a6039697533dca1e845c8c24"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/bee7f0dc9c3e0b69a6039697533dca1e845c8c24",
"reference": "bee7f0dc9c3e0b69a6039697533dca1e845c8c24",
"shasum": ""
},
"require": {
"php": ">=5.3.0",
"psr/log": "~1.0"
},
"provide": {
"psr/log-implementation": "1.0.0"
},
"require-dev": {
"aws/aws-sdk-php": "^2.4.9",
"doctrine/couchdb": "~1.0@dev",
"graylog2/gelf-php": "~1.0",
"jakub-onderka/php-parallel-lint": "0.9",
"php-console/php-console": "^3.1.3",
"phpunit/phpunit": "~4.5",
"phpunit/phpunit-mock-objects": "2.3.0",
"raven/raven": "^0.13",
"ruflin/elastica": ">=0.90 <3.0",
"swiftmailer/swiftmailer": "~5.3",
"videlalvaro/php-amqplib": "~2.4"
},
"suggest": {
"aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
"doctrine/couchdb": "Allow sending log messages to a CouchDB server",
"ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
"ext-mongo": "Allow sending log messages to a MongoDB server",
"graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
"php-console/php-console": "Allow sending log messages to Google Chrome",
"raven/raven": "Allow sending log messages to a Sentry server",
"rollbar/rollbar": "Allow sending log messages to Rollbar",
"ruflin/elastica": "Allow sending log messages to an Elastic Search server",
"videlalvaro/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.16.x-dev"
}
},
"autoload": {
"psr-4": {
"Monolog\\": "src/Monolog"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
}
],
"description": "Sends your logs to files, sockets, inboxes, databases and various web services",
"homepage": "http://github.com/Seldaek/monolog",
"keywords": [
"log",
"logging",
"psr-3"
],
"time": "2015-10-14 12:51:02"
},
{
"name": "nikic/fast-route",
"version": "v0.6.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/FastRoute.git",
"reference": "31fa86924556b80735f98b294a7ffdfb26789f22"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/FastRoute/zipball/31fa86924556b80735f98b294a7ffdfb26789f22",
"reference": "31fa86924556b80735f98b294a7ffdfb26789f22",
"shasum": ""
},
"require": {
"php": ">=5.4.0"
},
"type": "library",
"autoload": {
"psr-4": {
"FastRoute\\": "src/"
},
"files": [
"src/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Nikita Popov",
"email": "nikic@php.net"
}
],
"description": "Fast request router for PHP",
"keywords": [
"router",
"routing"
],
"time": "2015-06-18 19:15:47"
},
{
"name": "paragonie/random_compat",
"version": "v1.4.1",
"source": {
"type": "git",
"url": "https://github.com/paragonie/random_compat.git",
"reference": "c7e26a21ba357863de030f0b9e701c7d04593774"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/c7e26a21ba357863de030f0b9e701c7d04593774",
"reference": "c7e26a21ba357863de030f0b9e701c7d04593774",
"shasum": ""
},
"require": {
"php": ">=5.2.0"
},
"require-dev": {
"phpunit/phpunit": "4.*|5.*"
},
"suggest": {
"ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
},
"type": "library",
"autoload": {
"files": [
"lib/random.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Paragon Initiative Enterprises",
"email": "security@paragonie.com",
"homepage": "https://paragonie.com"
}
],
"description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
"keywords": [
"csprng",
"pseudorandom",
"random"
],
"time": "2016-03-18 20:34:03"
},
{
"name": "philo/laravel-blade",
"version": "v3.1",
"source": {
"type": "git",
"url": "https://github.com/PhiloNL/Laravel-Blade.git",
"reference": "3f0ce2ee198604c53c25188110e6d7b5e887527a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PhiloNL/Laravel-Blade/zipball/3f0ce2ee198604c53c25188110e6d7b5e887527a",
"reference": "3f0ce2ee198604c53c25188110e6d7b5e887527a",
"shasum": ""
},
"require": {
"illuminate/events": "~5",
"illuminate/view": "~5"
},
"type": "library",
"autoload": {
"psr-4": {
"Philo\\Blade\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Philo Hermans",
"email": "me@philohermans.com"
}
],
"description": "Use the simple and yet powerful Laravel Blade templating engine as a standalone component.",
"keywords": [
"blade",
"laravel"
],
"time": "2015-12-04 09:42:42"
},
{
"name": "pimple/pimple",
"version": "v3.0.2",
"source": {
"type": "git",
"url": "https://github.com/silexphp/Pimple.git",
"reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/silexphp/Pimple/zipball/a30f7d6e57565a2e1a316e1baf2a483f788b258a",
"reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0.x-dev"
}
},
"autoload": {
"psr-0": {
"Pimple": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "Pimple, a simple Dependency Injection Container",
"homepage": "http://pimple.sensiolabs.org",
"keywords": [
"container",
"dependency injection"
],
"time": "2015-09-11 15:10:35"
},
{
"name": "psr/http-message",
"version": "1.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
"reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
"keywords": [
"http",
"http-message",
"psr",
"psr-7",
"request",
"response"
],
"time": "2015-05-04 20:22:00"
},
{
"name": "psr/log",
"version": "1.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "fe0936ee26643249e916849d48e3a51d5f5e278b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b",
"reference": "fe0936ee26643249e916849d48e3a51d5f5e278b",
"shasum": ""
},
"type": "library",
"autoload": {
"psr-0": {
"Psr\\Log\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"keywords": [
"log",
"psr",
"psr-3"
],
"time": "2012-12-21 11:40:51"
},
{
"name": "slim/php-view",
"version": "2.0.6",
"source": {
"type": "git",
"url": "https://github.com/slimphp/PHP-View.git",
"reference": "a4dcd7e64b56b0c1875a8cd48daf065e6066c7f9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/slimphp/PHP-View/zipball/a4dcd7e64b56b0c1875a8cd48daf065e6066c7f9",
"reference": "a4dcd7e64b56b0c1875a8cd48daf065e6066c7f9",
"shasum": ""
},
"require": {
"psr/http-message": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0",
"slim/slim": "^3.0"
},
"type": "library",
"autoload": {
"psr-4": {
"Slim\\Views\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Glenn Eggleton",
"email": "geggleto@gmail.com"
}
],
"description": "Render PHP view scripts into a PSR-7 Response object.",
"keywords": [
"framework",
"php",
"phtml",
"renderer",
"slim",
"template",
"view"
],
"time": "2015-12-08 13:06:39"
},
{
"name": "slim/slim",
"version": "3.1.0",
"source": {
"type": "git",
"url": "https://github.com/slimphp/Slim.git",
"reference": "03b44a4b41896ba42c78bbd5fa172cd79e650496"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/slimphp/Slim/zipball/03b44a4b41896ba42c78bbd5fa172cd79e650496",
"reference": "03b44a4b41896ba42c78bbd5fa172cd79e650496",
"shasum": ""
},
"require": {
"container-interop/container-interop": "^1.1",
"nikic/fast-route": "^0.6",
"php": ">=5.5.0",
"pimple/pimple": "^3.0",
"psr/http-message": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0",
"squizlabs/php_codesniffer": "^2.5"
},
"type": "library",
"autoload": {
"psr-4": {
"Slim\\": "Slim"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Rob Allen",
"email": "rob@akrabat.com",
"homepage": "http://akrabat.com"
},
{
"name": "Josh Lockhart",
"email": "hello@joshlockhart.com",
"homepage": "https://joshlockhart.com"
},
{
"name": "Gabriel Manricks",
"email": "gmanricks@me.com",
"homepage": "http://gabrielmanricks.com"
},
{
"name": "Andrew Smith",
"email": "a.smith@silentworks.co.uk",
"homepage": "http://silentworks.co.uk"
}
],
"description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs",
"homepage": "http://slimframework.com",
"keywords": [
"api",
"framework",
"micro",
"router"
],
"time": "2016-01-08 15:37:50"
},
{
"name": "symfony/finder",
"version": "v3.0.4",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "c54e407b35bc098916704e9fd090da21da4c4f52"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/c54e407b35bc098916704e9fd090da21da4c4f52",
"reference": "c54e407b35bc098916704e9fd090da21da4c4f52",
"shasum": ""
},
"require": {
"php": ">=5.5.9"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
}
},
"autoload": {
"psr-4": {
"Symfony\\Component\\Finder\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Finder Component",
"homepage": "https://symfony.com",
"time": "2016-03-10 11:13:05"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": {
"php": ">=5.5.0"
},
"platform-dev": []
}

How to Contribute

Pull Requests

  1. Fork the Slim Skeleton repository
  2. Create a new branch for each feature or improvement
  3. Send a pull request from each feature branch to the 3.x branch

It is very important to separate new features or improvements into separate feature branches, and to send a pull request for each branch. This allows us to review and pull in new features or improvements individually.

Style Guide

All pull requests must adhere to the PSR-2 standard.

[2016-04-07 12:03:32] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"e9e1f8e"}
[2016-04-07 12:26:31] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"4a51d31"}
[2016-04-07 12:26:35] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"6163bac"}
[2016-04-07 12:27:02] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"758a073"}
[2016-04-07 12:29:18] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"13f6f1a"}
[2016-04-07 12:33:32] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"13d9049"}
[2016-04-07 12:34:51] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"dc565e8"}
[2016-04-07 12:36:17] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"dbdc08d"}
[2016-04-07 12:37:57] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"8a66b0e"}
[2016-04-07 12:38:57] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"1e108ec"}
[2016-04-07 12:39:28] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"003e598"}
[2016-04-07 12:40:48] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"e3d3835"}
[2016-04-07 12:44:02] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"d7f2e57"}
[2016-04-07 12:44:27] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"4957159"}
[2016-04-07 12:44:48] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"d14ad4b"}
[2016-04-07 12:44:51] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"7132798"}
[2016-04-07 12:44:57] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"a2ba9d7"}
[2016-04-07 12:47:10] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"c33513c"}
[2016-04-07 12:48:43] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"b27b338"}
[2016-04-07 12:49:52] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"5227b4c"}
[2016-04-07 12:50:18] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"08b0f2b"}
[2016-04-07 12:51:43] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"5dbfd93"}
[2016-04-07 12:52:05] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"36e42ad"}
[2016-04-07 12:55:14] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"1cf6977"}
[2016-04-07 12:55:56] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"9b3bbcc"}
[2016-04-07 12:56:36] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"2c4a371"}
[2016-04-07 12:56:38] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"8b0caef"}
[2016-04-07 12:57:10] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"e250aba"}
[2016-04-07 12:57:24] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"93c6b17"}
[2016-04-07 12:57:37] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"03e70b8"}
[2016-04-07 12:57:39] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"46d729e"}
[2016-04-07 12:57:46] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"5637efe"}
[2016-04-07 13:01:48] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"c2ae340"}
[2016-04-07 13:02:41] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"aedf164"}
[2016-04-07 13:02:49] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"7187a4a"}
[2016-04-07 13:03:25] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"ef4eb04"}
[2016-04-07 13:03:27] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"46a991a"}
[2016-04-07 13:04:15] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"4cbace1"}
[2016-04-07 13:06:20] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"f78e9af"}
[2016-04-07 13:06:48] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"5754985"}
[2016-04-07 13:06:54] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"9ce28cb"}
[2016-04-07 13:09:12] slim-app.INFO: Slim-Skeleton '/' route [] {"uid":"abb3ee2"}

Your Slim Framework application's log files will be written to this directory.

RewriteEngine On
# Some hosts may require you to use the `RewriteBase` directive.
# If you need to use the `RewriteBase` directive, it should be the
# absolute physical path to the directory that contains this htaccess file.
#
# RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^ index.php [QSA,L]
<?php
if (PHP_SAPI == 'cli-server') {
// To help the built-in PHP dev server, check if the request was actually for
// something which should probably be served as a static file
$file = __DIR__ . $_SERVER['REQUEST_URI'];
if (is_file($file)) {
return false;
}
}
require __DIR__ . '/../vendor/autoload.php';
session_start();
// Instantiate the app
$settings = require __DIR__ . '/../src/settings.php';
$app = new \Slim\App($settings);
// Get container
$container = $app->getContainer();
// Register component on container for blade
$container['view'] = function ($container) {
return new \Slim\Views\Blade( __DIR__ . '/../templates/',__DIR__ . '/../cache/');
};
// Set up dependencies
require __DIR__ . '/../src/dependencies.php';
// Register middleware
require __DIR__ . '/../src/middleware.php';
// Register routes
require __DIR__ . '/../src/routes.php';
// Run app
$app->run();

Slim Framework 3 Skeleton Application with blade templates

<?php
// DIC configuration
$container = $app->getContainer();
// view renderer
$container['renderer'] = function ($c) {
$settings = $c->get('settings')['renderer'];
return new Slim\Views\PhpRenderer($settings['template_path']);
};
// monolog
$container['logger'] = function ($c) {
$settings = $c->get('settings')['logger'];
$logger = new Monolog\Logger($settings['name']);
$logger->pushProcessor(new Monolog\Processor\UidProcessor());
$logger->pushHandler(new Monolog\Handler\StreamHandler($settings['path'], Monolog\Logger::DEBUG));
return $logger;
};
<?php
// Application middleware
// e.g: $app->add(new \Slim\Csrf\Guard);
<?php
// Routes
$app->get('/[{name}]', function ($request, $response, $args) {
// Sample log message
$this->logger->info("Slim-Skeleton '/' route");
// Render index view
// return $this->renderer->render($response, 'index.phtml', $args);
return $this->view->render($response,'index', Array('variable' => 'HOLA MUNDO BLADE'));
});
<?php
return [
'settings' => [
'displayErrorDetails' => true, // set to false in production
// Renderer settings
'renderer' => [
'template_path' => __DIR__ . '/../templates/',
],
// Monolog settings
'logger' => [
'name' => 'slim-app',
'path' => __DIR__ . '/../logs/app.log',
],
],
];
<!DOCTYPE html>
<html lang="en">
<body>
hola
{{ $variable }}
</body>
</html>
<html>
<head>
<meta charset="utf-8"/>
<title>Slim 3</title>
<link href='//fonts.googleapis.com/css?family=Lato:300' rel='stylesheet' type='text/css'>
<style>
body {
margin: 50px 0 0 0;
padding: 0;
width: 100%;
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
text-align: center;
color: #aaa;
font-size: 18px;
}
h1 {
color: #719e40;
letter-spacing: -3px;
font-family: 'Lato', sans-serif;
font-size: 100px;
font-weight: 200;
margin-bottom: 0;
}
</style>
</head>
<body>
<h1>Slim</h1>
<div>a microframework for PHP</div>
<?php if (isset($name)) : ?>
<h2>Hello <?= htmlspecialchars($name); ?>!</h2>
<?php else: ?>
<p>Try <a href="/SlimFramework">/SlimFramework</a>
<?php endif; ?>
</body>
</html>
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer' . '/autoload_real.php';
return ComposerAutoloaderInit18c991973baf7db5c413bc07273de8f4::getLoader();
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
);
<?php
// autoload_files.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'5255c38a0faeba867671b61dfda6d864' => $vendorDir . '/paragonie/random_compat/lib/random.php',
'72579e7bd17821bb1321b87411366eae' => $vendorDir . '/illuminate/support/helpers.php',
'253c157292f75eb38082b5acb06f3f01' => $vendorDir . '/nikic/fast-route/src/functions.php',
);
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Psr\\Log\\' => array($vendorDir . '/psr/log'),
'Pimple' => array($vendorDir . '/pimple/pimple/src'),
'Doctrine\\Common\\Inflector\\' => array($vendorDir . '/doctrine/inflector/lib'),
);
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Symfony\\Component\\Finder\\' => array($vendorDir . '/symfony/finder'),
'Slim\\Views\\' => array($vendorDir . '/slim/php-view/src', $vendorDir . '/hiropeke/slim-blade-view/src'),
'Slim\\' => array($vendorDir . '/slim/slim/Slim'),
'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src'),
'Philo\\Blade\\' => array($vendorDir . '/philo/laravel-blade/src'),
'Monolog\\' => array($vendorDir . '/monolog/monolog/src/Monolog'),
'Interop\\Container\\' => array($vendorDir . '/container-interop/container-interop/src/Interop/Container'),
'Illuminate\\View\\' => array($vendorDir . '/illuminate/view'),
'Illuminate\\Support\\' => array($vendorDir . '/illuminate/support'),
'Illuminate\\Filesystem\\' => array($vendorDir . '/illuminate/filesystem'),
'Illuminate\\Events\\' => array($vendorDir . '/illuminate/events'),
'Illuminate\\Contracts\\' => array($vendorDir . '/illuminate/contracts'),
'Illuminate\\Container\\' => array($vendorDir . '/illuminate/container'),
'FastRoute\\' => array($vendorDir . '/nikic/fast-route/src'),
);
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInit18c991973baf7db5c413bc07273de8f4
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInit18c991973baf7db5c413bc07273de8f4', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInit18c991973baf7db5c413bc07273de8f4', 'loadClassLoader'));
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
$loader->register(true);
$includeFiles = require __DIR__ . '/autoload_files.php';
foreach ($includeFiles as $fileIdentifier => $file) {
composerRequire18c991973baf7db5c413bc07273de8f4($fileIdentifier, $file);
}
return $loader;
}
}
function composerRequire18c991973baf7db5c413bc07273de8f4($fileIdentifier, $file)
{
if (empty($GLOBALS['__composer_autoload_files'][$fileIdentifier])) {
require $file;
$GLOBALS['__composer_autoload_files'][$fileIdentifier] = true;
}
}
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see http://www.php-fig.org/psr/psr-0/
* @see http://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
// PSR-4
private $prefixLengthsPsr4 = array();
private $prefixDirsPsr4 = array();
private $fallbackDirsPsr4 = array();
// PSR-0
private $prefixesPsr0 = array();
private $fallbackDirsPsr0 = array();
private $useIncludePath = false;
private $classMap = array();
private $classMapAuthoritative = false;
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', $this->prefixesPsr0);
}
return array();
}
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array $classMap Class to filename map
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*/
public function add($prefix, $paths, $prepend = false)
{
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
);
}
return;
}
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 base directories
*/
public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr0 = (array) $paths;
} else {
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
}
}
/**
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*/
public function setPsr4($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
}
/**
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*/
public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes.
*
* @return bool
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Turns off searching the prefix and fallback directories for classes
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
$this->classMapAuthoritative = $classMapAuthoritative;
}
/**
* Should class lookup fail if not found in the current class map?
*
* @return bool
*/
public function isClassMapAuthoritative()
{
return $this->classMapAuthoritative;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}
/**
* Unregisters this instance as an autoloader.
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return bool|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
return true;
}
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// work around for PHP 5.3.0 - 5.3.2 https://bugs.php.net/50731
if ('\\' == $class[0]) {
$class = substr($class, 1);
}
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative) {
return false;
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if ($file === null && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if ($file === null) {
// Remember that this class does not exist.
return $this->classMap[$class] = false;
}
return $file;
}
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) {
if (0 === strpos($class, $prefix)) {
foreach ($this->prefixDirsPsr4[$prefix] as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) {
return $file;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
// PSR-0 lookup
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
}
if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
// PSR-0 include paths.
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*/
function includeFile($file)
{
include $file;
}
[
{
"name": "psr/log",
"version": "1.0.0",
"version_normalized": "1.0.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "fe0936ee26643249e916849d48e3a51d5f5e278b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/fe0936ee26643249e916849d48e3a51d5f5e278b",
"reference": "fe0936ee26643249e916849d48e3a51d5f5e278b",
"shasum": ""
},
"time": "2012-12-21 11:40:51",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"Psr\\Log\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"keywords": [
"log",
"psr",
"psr-3"
]
},
{
"name": "monolog/monolog",
"version": "1.17.2",
"version_normalized": "1.17.2.0",
"source": {
"type": "git",
"url": "https://github.com/Seldaek/monolog.git",
"reference": "bee7f0dc9c3e0b69a6039697533dca1e845c8c24"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Seldaek/monolog/zipball/bee7f0dc9c3e0b69a6039697533dca1e845c8c24",
"reference": "bee7f0dc9c3e0b69a6039697533dca1e845c8c24",
"shasum": ""
},
"require": {
"php": ">=5.3.0",
"psr/log": "~1.0"
},
"provide": {
"psr/log-implementation": "1.0.0"
},
"require-dev": {
"aws/aws-sdk-php": "^2.4.9",
"doctrine/couchdb": "~1.0@dev",
"graylog2/gelf-php": "~1.0",
"jakub-onderka/php-parallel-lint": "0.9",
"php-console/php-console": "^3.1.3",
"phpunit/phpunit": "~4.5",
"phpunit/phpunit-mock-objects": "2.3.0",
"raven/raven": "^0.13",
"ruflin/elastica": ">=0.90 <3.0",
"swiftmailer/swiftmailer": "~5.3",
"videlalvaro/php-amqplib": "~2.4"
},
"suggest": {
"aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
"doctrine/couchdb": "Allow sending log messages to a CouchDB server",
"ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
"ext-mongo": "Allow sending log messages to a MongoDB server",
"graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
"php-console/php-console": "Allow sending log messages to Google Chrome",
"raven/raven": "Allow sending log messages to a Sentry server",
"rollbar/rollbar": "Allow sending log messages to Rollbar",
"ruflin/elastica": "Allow sending log messages to an Elastic Search server",
"videlalvaro/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib"
},
"time": "2015-10-14 12:51:02",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.16.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Monolog\\": "src/Monolog"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
}
],
"description": "Sends your logs to files, sockets, inboxes, databases and various web services",
"homepage": "http://github.com/Seldaek/monolog",
"keywords": [
"log",
"logging",
"psr-3"
]
},
{
"name": "psr/http-message",
"version": "1.0",
"version_normalized": "1.0.0.0",
"source": {
"type": "git",
"url": "https://github.com/php-fig/http-message.git",
"reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/http-message/zipball/85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
"reference": "85d63699f0dbedb190bbd4b0d2b9dc707ea4c298",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"time": "2015-05-04 20:22:00",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.0.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Psr\\Http\\Message\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "http://www.php-fig.org/"
}
],
"description": "Common interface for HTTP messages",
"keywords": [
"http",
"http-message",
"psr",
"psr-7",
"request",
"response"
]
},
{
"name": "slim/php-view",
"version": "2.0.6",
"version_normalized": "2.0.6.0",
"source": {
"type": "git",
"url": "https://github.com/slimphp/PHP-View.git",
"reference": "a4dcd7e64b56b0c1875a8cd48daf065e6066c7f9"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/slimphp/PHP-View/zipball/a4dcd7e64b56b0c1875a8cd48daf065e6066c7f9",
"reference": "a4dcd7e64b56b0c1875a8cd48daf065e6066c7f9",
"shasum": ""
},
"require": {
"psr/http-message": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0",
"slim/slim": "^3.0"
},
"time": "2015-12-08 13:06:39",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Slim\\Views\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Glenn Eggleton",
"email": "geggleto@gmail.com"
}
],
"description": "Render PHP view scripts into a PSR-7 Response object.",
"keywords": [
"framework",
"php",
"phtml",
"renderer",
"slim",
"template",
"view"
]
},
{
"name": "pimple/pimple",
"version": "v3.0.2",
"version_normalized": "3.0.2.0",
"source": {
"type": "git",
"url": "https://github.com/silexphp/Pimple.git",
"reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/silexphp/Pimple/zipball/a30f7d6e57565a2e1a316e1baf2a483f788b258a",
"reference": "a30f7d6e57565a2e1a316e1baf2a483f788b258a",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"time": "2015-09-11 15:10:35",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-0": {
"Pimple": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
}
],
"description": "Pimple, a simple Dependency Injection Container",
"homepage": "http://pimple.sensiolabs.org",
"keywords": [
"container",
"dependency injection"
]
},
{
"name": "nikic/fast-route",
"version": "v0.6.0",
"version_normalized": "0.6.0.0",
"source": {
"type": "git",
"url": "https://github.com/nikic/FastRoute.git",
"reference": "31fa86924556b80735f98b294a7ffdfb26789f22"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/nikic/FastRoute/zipball/31fa86924556b80735f98b294a7ffdfb26789f22",
"reference": "31fa86924556b80735f98b294a7ffdfb26789f22",
"shasum": ""
},
"require": {
"php": ">=5.4.0"
},
"time": "2015-06-18 19:15:47",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"FastRoute\\": "src/"
},
"files": [
"src/functions.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"BSD-3-Clause"
],
"authors": [
{
"name": "Nikita Popov",
"email": "nikic@php.net"
}
],
"description": "Fast request router for PHP",
"keywords": [
"router",
"routing"
]
},
{
"name": "container-interop/container-interop",
"version": "1.1.0",
"version_normalized": "1.1.0.0",
"source": {
"type": "git",
"url": "https://github.com/container-interop/container-interop.git",
"reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/container-interop/container-interop/zipball/fc08354828f8fd3245f77a66b9e23a6bca48297e",
"reference": "fc08354828f8fd3245f77a66b9e23a6bca48297e",
"shasum": ""
},
"time": "2014-12-30 15:22:37",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Interop\\Container\\": "src/Interop/Container/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "Promoting the interoperability of container objects (DIC, SL, etc.)"
},
{
"name": "slim/slim",
"version": "3.1.0",
"version_normalized": "3.1.0.0",
"source": {
"type": "git",
"url": "https://github.com/slimphp/Slim.git",
"reference": "03b44a4b41896ba42c78bbd5fa172cd79e650496"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/slimphp/Slim/zipball/03b44a4b41896ba42c78bbd5fa172cd79e650496",
"reference": "03b44a4b41896ba42c78bbd5fa172cd79e650496",
"shasum": ""
},
"require": {
"container-interop/container-interop": "^1.1",
"nikic/fast-route": "^0.6",
"php": ">=5.5.0",
"pimple/pimple": "^3.0",
"psr/http-message": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^4.0",
"squizlabs/php_codesniffer": "^2.5"
},
"time": "2016-01-08 15:37:50",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Slim\\": "Slim"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Rob Allen",
"email": "rob@akrabat.com",
"homepage": "http://akrabat.com"
},
{
"name": "Josh Lockhart",
"email": "hello@joshlockhart.com",
"homepage": "https://joshlockhart.com"
},
{
"name": "Gabriel Manricks",
"email": "gmanricks@me.com",
"homepage": "http://gabrielmanricks.com"
},
{
"name": "Andrew Smith",
"email": "a.smith@silentworks.co.uk",
"homepage": "http://silentworks.co.uk"
}
],
"description": "Slim is a PHP micro framework that helps you quickly write simple yet powerful web applications and APIs",
"homepage": "http://slimframework.com",
"keywords": [
"api",
"framework",
"micro",
"router"
]
},
{
"name": "doctrine/inflector",
"version": "v1.1.0",
"version_normalized": "1.1.0.0",
"source": {
"type": "git",
"url": "https://github.com/doctrine/inflector.git",
"reference": "90b2128806bfde671b6952ab8bea493942c1fdae"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/doctrine/inflector/zipball/90b2128806bfde671b6952ab8bea493942c1fdae",
"reference": "90b2128806bfde671b6952ab8bea493942c1fdae",
"shasum": ""
},
"require": {
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": "4.*"
},
"time": "2015-11-06 14:35:42",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-0": {
"Doctrine\\Common\\Inflector\\": "lib/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Roman Borschel",
"email": "roman@code-factory.org"
},
{
"name": "Benjamin Eberlei",
"email": "kontakt@beberlei.de"
},
{
"name": "Guilherme Blanco",
"email": "guilhermeblanco@gmail.com"
},
{
"name": "Jonathan Wage",
"email": "jonwage@gmail.com"
},
{
"name": "Johannes Schmitt",
"email": "schmittjoh@gmail.com"
}
],
"description": "Common String Manipulations with regard to casing and singular/plural rules.",
"homepage": "http://www.doctrine-project.org",
"keywords": [
"inflection",
"pluralize",
"singularize",
"string"
]
},
{
"name": "illuminate/contracts",
"version": "v5.2.28",
"version_normalized": "5.2.28.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/contracts.git",
"reference": "411b851962c211078ade7664a6976e77a78cd2a5"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/contracts/zipball/411b851962c211078ade7664a6976e77a78cd2a5",
"reference": "411b851962c211078ade7664a6976e77a78cd2a5",
"shasum": ""
},
"require": {
"php": ">=5.5.9"
},
"time": "2016-03-07 20:37:17",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.2-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Illuminate\\Contracts\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylorotwell@gmail.com"
}
],
"description": "The Illuminate Contracts package.",
"homepage": "http://laravel.com"
},
{
"name": "paragonie/random_compat",
"version": "v1.4.1",
"version_normalized": "1.4.1.0",
"source": {
"type": "git",
"url": "https://github.com/paragonie/random_compat.git",
"reference": "c7e26a21ba357863de030f0b9e701c7d04593774"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/paragonie/random_compat/zipball/c7e26a21ba357863de030f0b9e701c7d04593774",
"reference": "c7e26a21ba357863de030f0b9e701c7d04593774",
"shasum": ""
},
"require": {
"php": ">=5.2.0"
},
"require-dev": {
"phpunit/phpunit": "4.*|5.*"
},
"suggest": {
"ext-libsodium": "Provides a modern crypto API that can be used to generate random bytes."
},
"time": "2016-03-18 20:34:03",
"type": "library",
"installation-source": "dist",
"autoload": {
"files": [
"lib/random.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Paragon Initiative Enterprises",
"email": "security@paragonie.com",
"homepage": "https://paragonie.com"
}
],
"description": "PHP 5.x polyfill for random_bytes() and random_int() from PHP 7",
"keywords": [
"csprng",
"pseudorandom",
"random"
]
},
{
"name": "illuminate/support",
"version": "v5.2.28",
"version_normalized": "5.2.28.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/support.git",
"reference": "e4aa03c5f26db752e838354a7d71b85e6138f4ec"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/support/zipball/e4aa03c5f26db752e838354a7d71b85e6138f4ec",
"reference": "e4aa03c5f26db752e838354a7d71b85e6138f4ec",
"shasum": ""
},
"require": {
"doctrine/inflector": "~1.0",
"ext-mbstring": "*",
"illuminate/contracts": "5.2.*",
"paragonie/random_compat": "~1.4",
"php": ">=5.5.9"
},
"suggest": {
"illuminate/filesystem": "Required to use the composer class (5.2.*).",
"jeremeamia/superclosure": "Required to be able to serialize closures (~2.2).",
"symfony/polyfill-php56": "Required to use the hash_equals function on PHP 5.5 (~1.0).",
"symfony/process": "Required to use the composer class (2.8.*|3.0.*).",
"symfony/var-dumper": "Improves the dd function (2.8.*|3.0.*)."
},
"time": "2016-03-30 18:18:45",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.2-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Illuminate\\Support\\": ""
},
"files": [
"helpers.php"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylorotwell@gmail.com"
}
],
"description": "The Illuminate Support package.",
"homepage": "http://laravel.com"
},
{
"name": "illuminate/container",
"version": "v5.2.28",
"version_normalized": "5.2.28.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/container.git",
"reference": "1e156f8017490f5583ab161030bf839c77c95e54"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/container/zipball/1e156f8017490f5583ab161030bf839c77c95e54",
"reference": "1e156f8017490f5583ab161030bf839c77c95e54",
"shasum": ""
},
"require": {
"illuminate/contracts": "5.2.*",
"php": ">=5.5.9"
},
"time": "2016-03-16 17:19:17",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.2-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Illuminate\\Container\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylorotwell@gmail.com"
}
],
"description": "The Illuminate Container package.",
"homepage": "http://laravel.com"
},
{
"name": "illuminate/events",
"version": "v5.2.28",
"version_normalized": "5.2.28.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/events.git",
"reference": "5a5e5d72bf3a2d01d8b15e89440026a60bc4a81b"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/events/zipball/5a5e5d72bf3a2d01d8b15e89440026a60bc4a81b",
"reference": "5a5e5d72bf3a2d01d8b15e89440026a60bc4a81b",
"shasum": ""
},
"require": {
"illuminate/container": "5.2.*",
"illuminate/contracts": "5.2.*",
"illuminate/support": "5.2.*",
"php": ">=5.5.9"
},
"time": "2016-01-01 01:00:19",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.2-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Illuminate\\Events\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylorotwell@gmail.com"
}
],
"description": "The Illuminate Events package.",
"homepage": "http://laravel.com"
},
{
"name": "symfony/finder",
"version": "v3.0.4",
"version_normalized": "3.0.4.0",
"source": {
"type": "git",
"url": "https://github.com/symfony/finder.git",
"reference": "c54e407b35bc098916704e9fd090da21da4c4f52"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/c54e407b35bc098916704e9fd090da21da4c4f52",
"reference": "c54e407b35bc098916704e9fd090da21da4c4f52",
"shasum": ""
},
"require": {
"php": ">=5.5.9"
},
"time": "2016-03-10 11:13:05",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "3.0-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Symfony\\Component\\Finder\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Finder Component",
"homepage": "https://symfony.com"
},
{
"name": "illuminate/filesystem",
"version": "v5.2.28",
"version_normalized": "5.2.28.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/filesystem.git",
"reference": "e197f38660beab95743d9d5565d0f11d956288ea"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/filesystem/zipball/e197f38660beab95743d9d5565d0f11d956288ea",
"reference": "e197f38660beab95743d9d5565d0f11d956288ea",
"shasum": ""
},
"require": {
"illuminate/contracts": "5.2.*",
"illuminate/support": "5.2.*",
"php": ">=5.5.9",
"symfony/finder": "2.8.*|3.0.*"
},
"suggest": {
"league/flysystem": "Required to use the Flysystem local and FTP drivers (~1.0).",
"league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (~1.0).",
"league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (~1.0)."
},
"time": "2016-03-21 14:55:26",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.2-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Illuminate\\Filesystem\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylorotwell@gmail.com"
}
],
"description": "The Illuminate Filesystem package.",
"homepage": "http://laravel.com"
},
{
"name": "illuminate/view",
"version": "v5.2.28",
"version_normalized": "5.2.28.0",
"source": {
"type": "git",
"url": "https://github.com/illuminate/view.git",
"reference": "a0e77662f06eaae851469ebf132868c9024a259d"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/illuminate/view/zipball/a0e77662f06eaae851469ebf132868c9024a259d",
"reference": "a0e77662f06eaae851469ebf132868c9024a259d",
"shasum": ""
},
"require": {
"illuminate/container": "5.2.*",
"illuminate/contracts": "5.2.*",
"illuminate/events": "5.2.*",
"illuminate/filesystem": "5.2.*",
"illuminate/support": "5.2.*",
"php": ">=5.5.9"
},
"time": "2016-03-28 15:19:10",
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "5.2-dev"
}
},
"installation-source": "dist",
"autoload": {
"psr-4": {
"Illuminate\\View\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Taylor Otwell",
"email": "taylorotwell@gmail.com"
}
],
"description": "The Illuminate View package.",
"homepage": "http://laravel.com"
},
{
"name": "philo/laravel-blade",
"version": "v3.1",
"version_normalized": "3.1.0.0",
"source": {
"type": "git",
"url": "https://github.com/PhiloNL/Laravel-Blade.git",
"reference": "3f0ce2ee198604c53c25188110e6d7b5e887527a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/PhiloNL/Laravel-Blade/zipball/3f0ce2ee198604c53c25188110e6d7b5e887527a",
"reference": "3f0ce2ee198604c53c25188110e6d7b5e887527a",
"shasum": ""
},
"require": {
"illuminate/events": "~5",
"illuminate/view": "~5"
},
"time": "2015-12-04 09:42:42",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Philo\\Blade\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Philo Hermans",
"email": "me@philohermans.com"
}
],
"description": "Use the simple and yet powerful Laravel Blade templating engine as a standalone component.",
"keywords": [
"blade",
"laravel"
]
},
{
"name": "hiropeke/slim-blade-view",
"version": "0.1.1",
"version_normalized": "0.1.1.0",
"source": {
"type": "git",
"url": "https://github.com/hiropeke/Slim-Blade-View.git",
"reference": "9cdea69285acbf712463b38a9bb0b5ce23c4c98c"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/hiropeke/Slim-Blade-View/zipball/9cdea69285acbf712463b38a9bb0b5ce23c4c98c",
"reference": "9cdea69285acbf712463b38a9bb0b5ce23c4c98c",
"shasum": ""
},
"require": {
"illuminate/view": "5.*",
"philo/laravel-blade": "3.*",
"psr/http-message": "^1.0"
},
"require-dev": {
"phpunit/phpunit": "^5.0",
"slim/slim": "^3.0"
},
"time": "2016-03-11 02:32:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-4": {
"Slim\\Views\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Hiroaki Matsuura",
"email": "hiropeke.jp@gmail.com"
}
],
"description": "Slim Framework 3 view helper built on the Blade component",
"keywords": [
"blade",
"framework",
"renderer",
"slim",
"template",
"view"
]
}
]
Copyright (c) 2016 Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
{
"name": "container-interop/container-interop",
"type": "library",
"description": "Promoting the interoperability of container objects (DIC, SL, etc.)",
"license": "MIT",
"autoload": {
"psr-4": {
"Interop\\Container\\": "src/Interop/Container/"
}
}
}

ContainerInterface Meta Document

Introduction

This document describes the process and discussions that lead to the ContainerInterface. Its goal is to explain the reasons behind each decision.

Goal

The goal set by ContainerInterface is to standardize how frameworks and libraries make use of a container to obtain objects and parameters.

By standardizing such a behavior, frameworks and libraries using the ContainerInterface could work with any compatible container. That would allow end users to choose their own container based on their own preferences.

It is important to distinguish the two usages of a container:

  • configuring entries
  • fetching entries

Most of the time, those two sides are not used by the same party. While it is often end users who tend to configure entries, it is generally the framework that fetch entries to build the application.

This is why this interface focuses only on how entries can be fetched from a container.

Interface name

The interface name has been thoroughly discussed and was decided by a vote.

The list of options considered with their respective votes are:

  • ContainerInterface: +8
  • ProviderInterface: +2
  • LocatorInterface: 0
  • ReadableContainerInterface: -5
  • ServiceLocatorInterface: -6
  • ObjectFactory: -6
  • ObjectStore: -8
  • ConsumerInterface: -9

Full results of the vote

The complete discussion can be read in the issue #1.

Interface methods

The choice of which methods the interface would contain was made after a statistical analysis of existing containers. The results of this analysis are available in this document.

The summary of the analysis showed that:

  • all containers offer a method to get an entry by its id
  • a large majority name such method get()
  • for all containers, the get() method has 1 mandatory parameter of type string
  • some containers have an optional additional argument for get(), but it doesn't same the same purpose between containers
  • a large majority of the containers offer a method to test if it can return an entry by its id
  • a majority name such method has()
  • for all containers offering has(), the method has exactly 1 parameter of type string
  • a large majority of the containers throw an exception rather than returning null when an entry is not found in get()
  • a large majority of the containers don't implement ArrayAccess

The question of whether to include methods to define entries has been discussed in issue #1. It has been judged that such methods do not belong in the interface described here because it is out of its scope (see the "Goal" section).

As a result, the ContainerInterface contains two methods:

  • get(), returning anything, with one mandatory string parameter. Should throw an exception if the entry is not found.
  • has(), returning a boolean, with one mandatory string parameter.

Number of parameters in get() method

While ContainerInterface only defines one mandatory parameter in get(), it is not incompatible with existing containers that have additional optional parameters. PHP allows an implementation to offer more parameters as long as they are optional, because the implementation does satisfy the interface.

This issue has been discussed in issue #6.

Type of the $id parameter

The type of the $id parameter in get() and has() has been discussed in issue #6. While string is used in all the containers that were analyzed, it was suggested that allowing anything (such as objects) could allow containers to offer a more advanced query API.

An example given was to use the container as an object builder. The $id parameter would then be an object that would describe how to create an instance.

The conclusion of the discussion was that this was beyond the scope of getting entries from a container without knowing how the container provided them, and it was more fit for a factory.

Contributors

Are listed here all people that contributed in the discussions or votes, by alphabetical order:

Relevant links

Container interface

This document describes a common interface for dependency injection containers.

The goal set by ContainerInterface is to standardize how frameworks and libraries make use of a container to obtain objects and parameters (called entries in the rest of this document).

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.

The word implementor in this document is to be interpreted as someone implementing the ContainerInterface in a depency injection-related library or framework. Users of dependency injections containers (DIC) are refered to as user.

  1. Specification

1.1 Basics

  • The Interop\Container\ContainerInterface exposes two methods : get and has.

  • get takes one mandatory parameter: an entry identifier. It MUST be a string. A call to get can return anything (a mixed value), or throws an exception if the identifier is not known to the container. Two successive calls to get with the same identifier SHOULD return the same value. However, depending on the implementor design and/or user configuration, different values might be returned, so user SHOULD NOT rely on getting the same value on 2 successive calls. While ContainerInterface only defines one mandatory parameter in get(), implementations MAY accept additional optional parameters.

  • has takes one unique parameter: an entry identifier. It MUST return true if an entry identifier is known to the container and false if it is not.

1.2 Exceptions

Exceptions directly thrown by the container MUST implement the Interop\Container\Exception\ContainerException.

A call to the get method with a non-existing id should throw a Interop\Container\Exception\NotFoundException.

1.3 Additional features

This section describes additional features that MAY be added to a container. Containers are not required to implement these features to respect the ContainerInterface.

1.3.1 Delegate lookup feature

The goal of the delegate lookup feature is to allow several containers to share entries. Containers implementing this feature can perform dependency lookups in other containers.

Containers implementing this feature will offer a greater lever of interoperability with other containers. Implementation of this feature is therefore RECOMMENDED.

A container implementing this feature:

  • MUST implement the ContainerInterface
  • MUST provide a way to register a delegate container (using a constructor parameter, or a setter, or any possible way). The delegate container MUST implement the ContainerInterface.

When a container is configured to use a delegate container for dependencies:

  • Calls to the get method should only return an entry if the entry is part of the container. If the entry is not part of the container, an exception should be thrown (as requested by the ContainerInterface).
  • Calls to the has method should only return true if the entry is part of the container. If the entry is not part of the container, false should be returned.
  • If the fetched entry has dependencies, instead of performing the dependency lookup in the container, the lookup is performed on the delegate container.

Important! By default, the lookup SHOULD be performed on the delegate container only, not on the container itself.

It is however allowed for containers to provide exception cases for special entries, and a way to lookup into the same container (or another container) instead of the delegate container.

  1. Package

The interfaces and classes described as well as relevant exception are provided as part of the container-interop/container-interop package.

  1. Interop\Container\ContainerInterface

<?php
namespace Interop\Container;

use Interop\Container\Exception\ContainerException;
use Interop\Container\Exception\NotFoundException;

/**
 * Describes the interface of a container that exposes methods to read its entries.
 */
interface ContainerInterface
{
    /**
     * Finds an entry of the container by its identifier and returns it.
     *
     * @param string $id Identifier of the entry to look for.
     *
     * @throws NotFoundException  No entry was found for this identifier.
     * @throws ContainerException Error while retrieving the entry.
     *
     * @return mixed Entry.
     */
    public function get($id);

    /**
     * Returns true if the container can return an entry for the given identifier.
     * Returns false otherwise.
     *
     * @param string $id Identifier of the entry to look for.
     *
     * @return boolean
     */
    public function has($id);
}
  1. Interop\Container\Exception\ContainerException

<?php
namespace Interop\Container\Exception;

/**
 * Base interface representing a generic exception in a container.
 */
interface ContainerException
{
}
  1. Interop\Container\Exception\NotFoundException

<?php
namespace Interop\Container\Exception;

/**
 * No entry was found in the container.
 */
interface NotFoundException extends ContainerException
{
}

Delegate lookup feature Meta Document

  1. Summary

This document describes the delegate lookup feature. Containers are not required to implement this feature to respect the ContainerInterface. However, containers implementing this feature will offer a greater lever of interoperability with other containers, allowing multiple containers to share entries in the same application. Implementation of this feature is therefore recommanded.

  1. Why Bother?

The ContainerInterface (meta doc) standardizes how frameworks and libraries make use of a container to obtain objects and parameters.

By standardizing such a behavior, frameworks and libraries relying on the ContainerInterface could work with any compatible container. That would allow end users to choose their own container based on their own preferences.

The ContainerInterface is also enough if we want to have several containers side-by-side in the same application. For instance, this is what the CompositeContainer class of Acclimate is designed for:

Side by side containers

However, an instance in container 1 cannot reference an instance in container 2.

It would be better if an instance of container 1 could reference an instance in container 2, and the opposite should be true.

Interoperating containers

In the sample above, entry 1 in container 1 is referencing entry 3 in container 2.

  1. Scope

3.1 Goals

The goal of the delegate lookup feature is to allow several containers to share entries.

  1. Approaches

4.1 Chosen Approach

Containers implementing this feature can perform dependency lookups in other containers.

A container implementing this feature:

  • must implement the ContainerInterface
  • must provide a way to register a delegate container (using a constructor parameter, or a setter, or any possible way). The delegate container must implement the ContainerInterface.

When a delegate container is configured on a container:

  • Calls to the get method should only return an entry if the entry is part of the container. If the entry is not part of the container, an exception should be thrown (as required in the ContainerInterface).
  • Calls to the has method should only return true if the entry is part of the container. If the entry is not part of the container, false should be returned.
  • Finally, the important part: if the entry we are fetching has dependencies, instead of perfoming the dependency lookup in the container, the lookup is performed on the delegate container.

Important! By default, the lookup should be performed on the delegate container only, not on the container itself.

It is however allowed for containers to provide exception cases for special entries, and a way to lookup into the same container (or another container) instead of the delegate container.

4.2 Typical usage

The delegate container will usually be a composite container. A composite container is a container that contains several other containers. When performing a lookup on a composite container, the inner containers are queried until one container returns an entry. An inner container implementing the delegate lookup feature will return entries it contains, but if these entries have dependencies, the dependencies lookup calls will be performed on the composite container, giving a chance to all containers to answer.

Interestingly enough, the order in which containers are added in the composite container matters. Indeed, the first containers to be added in the composite container can "override" the entries of containers with lower priority.

Containers priority

In the example above, "container 2" contains a controller "myController" and the controller is referencing an "entityManager" entry. "Container 1" contains also an entry named "entityManager". Without the delegate lookup feature, when requesting the "myController" instance to container 2, it would take in charge the instanciation of both entries.

However, using the delegate lookup feature, here is what happens when we ask the composite controller for the "myController" instance:

  • The composite controller asks container 1 if if contains the "myController" instance. The answer is no.
  • The composite controller asks container 2 if if contains the "myController" instance. The answer is yes.
  • The composite controller performs a get call on container 2 for the "myController" instance.
  • Container 2 sees that "myController" has a dependency on "entityManager".
  • Container 2 delegates the lookup of "entityManager" to the composite controller.
  • The composite controller asks container 1 if if contains the "entityManager" instance. The answer is yes.
  • The composite controller performs a get call on container 1 for the "entityManager" instance.

In the end, we get a controller instanciated by container 2 that references an entityManager instanciated by container 1.

4.3 Alternative: the fallback strategy

The first proposed approach we tried was to perform all the lookups in the "local" container, and if a lookup fails in the container, to use the delegate container. In this scenario, the delegate container is used in "fallback" mode.

This strategy has been described in @moufmouf blog post: http://mouf-php.com/container-interop-whats-next (solution 1). It was also discussed here and here.

Problems with this strategy:

  • Heavy problem regarding infinite loops
  • Unable to overload a container entry with the delegate container entry

4.4 Alternative: force implementing an interface

The first proposed approach was to develop a ParentAwareContainerInterface interface. It was proposed here: container-interop/container-interop#8

The interface would have had the behaviour of the delegate lookup feature but would have forced the addition of a setParentContainter method:

interface ParentAwareContainerInterface extends ReadableContainerInterface {
    /**
     * Sets the parent container associated to that container. This container will call
     * the parent container to fetch dependencies.
     *
     * @param ContainerInterface $container
     */
    public function setParentContainer(ContainerInterface $container);
}

The interface idea was first questioned by @Ocramius here. @Ocramius expressed the idea that an interface should not contain setters, otherwise, it is forcing implementation details on the class implementing the interface. Then @mnapoli made a proposal for a "convention" here, this idea was further discussed until all participants in the discussion agreed to remove the interface idea and replace it with a "standard" feature.

Pros:

If we had had an interface, we could have delegated the registration of the delegate/composite container to the the delegate/composite container itself. For instance:

$containerA = new ContainerA();
$containerB = new ContainerB();

$compositeContainer = new CompositeContainer([$containerA, $containerB]);

// The call to 'setParentContainer' is delegated to the CompositeContainer
// It is not the responsibility of the user anymore.
class CompositeContainer {
	...
	
	public function __construct($containers) {
		foreach ($containers as $container) {
			if ($container instanceof ParentAwareContainerInterface) {
				$container->setParentContainer($this);
			}
		}
		...
	}
}

Cons:

Cons have been extensively discussed here. Basically, forcing a setter into an interface is a bad idea. Setters are similar to constructor arguments, and it's a bad idea to standardize a constructor: how the delegate container is configured into a container is an implementation detail. This outweights the benefits of the interface.

4.4 Alternative: no exception case for delegate lookups

Originally, the proposed wording for delegate lookup calls was:

Important! The lookup MUST be performed on the delegate container only, not on the container itself.

This was later replaced by:

Important! By default, the lookup SHOULD be performed on the delegate container only, not on the container itself.

It is however allowed for containers to provide exception cases for special entries, and a way to lookup into the same container (or another container) instead of the delegate container.

Exception cases have been allowed to avoid breaking dependencies with some services that must be provided by the container (on @njasm proposal). This was proposed here: container-interop/container-interop#20 (comment)

4.5 Alternative: having one of the containers act as the composite container

In real-life scenarios, we usually have a big framework (Symfony 2, Zend Framework 2, etc...) and we want to add another DI container to this container. Most of the time, the "big" framework will be responsible for creating the controller's instances, using it's own DI container. Until container-interop is fully adopted, the "big" framework will not be aware of the existence of a composite container that it should use instead of its own container.

For this real-life use cases, @mnapoli and @moufmouf proposed to extend the "big" framework's DI container to make it act as a composite container.

This has been discussed here and here.

This was implemented in Symfony 2 using:

This was implemented in Silex using:

Having a container act as the composite container is not part of the delegate lookup standard because it is simply a temporary design pattern used to make existing frameworks that do not support yet ContainerInterop play nice with other DI containers.

  1. Implementations

The following projects already implement the delegate lookup feature:

  1. People

Are listed here all people that contributed in the discussions, by alphabetical order:

  1. Relevant Links

Note: Order descending chronologically.

Delegate lookup feature

This document describes a standard for dependency injection containers.

The goal set by the delegate lookup feature is to allow several containers to share entries. Containers implementing this feature can perform dependency lookups in other containers.

Containers implementing this feature will offer a greater lever of interoperability with other containers. Implementation of this feature is therefore RECOMMENDED.

The key words "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", "MAY", and "OPTIONAL" in this document are to be interpreted as described in RFC 2119.

The word implementor in this document is to be interpreted as someone implementing the delegate lookup feature in a dependency injection-related library or framework. Users of dependency injections containers (DIC) are refered to as user.

  1. Vocabulary

In a dependency injection container, the container is used to fetch entries. Entries can have dependencies on other entries. Usually, these other entries are fetched by the container.

The delegate lookup feature is the ability for a container to fetch dependencies in another container. In the rest of the document, the word "container" will reference the container implemented by the implementor. The word "delegate container" will reference the container we are fetching the dependencies from.

  1. Specification

A container implementing the delegate lookup feature:

  • MUST implement the ContainerInterface
  • MUST provide a way to register a delegate container (using a constructor parameter, or a setter, or any possible way). The delegate container MUST implement the ContainerInterface.

When a container is configured to use a delegate container for dependencies:

  • Calls to the get method should only return an entry if the entry is part of the container. If the entry is not part of the container, an exception should be thrown (as requested by the ContainerInterface).
  • Calls to the has method should only return true if the entry is part of the container. If the entry is not part of the container, false should be returned.
  • If the fetched entry has dependencies, instead of performing the dependency lookup in the container, the lookup is performed on the delegate container.

Important: By default, the dependency lookups SHOULD be performed on the delegate container only, not on the container itself.

It is however allowed for containers to provide exception cases for special entries, and a way to lookup into the same container (or another container) instead of the delegate container.

  1. Package / Interface

This feature is not tied to any code, interface or package.

�PNG

IHDR[$)��esBIT|d� pHYs���+ IDATx���w|TU�?�ϝ>�Lz'��Ђ4)��R��*.�볮eWWl���誫���]W�ߊ���"�� %���L2}���r3Hrg&���5���)�i�~�9�{�$� """�.�R:"""�P�d����� 1�""""�BL�������-"""�.�d����� 1�""""�BL�������-"""�.�d����� 1�""""�BL�������F����GCi)�K�!��bc��I��u�ʼ<ly�Ex��s�6<) ��d�c��Ñ2|Ⲳ �x�JDg�d�����
�'P�{7�� gC���|ɔ��������M���] �Vۮ�s66�8g7<N�yś2|�X�"4z�yݟ�z&[DNn߆���v�4��V] �! ��j��0DE!"9)#F���sr2R���J�V:D"�"L���5�JU���ZU�����:z4F��H�L"“��=����z�Η)&�C�V9!JK�PZ��ݻd�N�@!H����,$fgs��(D0�"�v�8�(ۿ����+(@e^.++Q��C{��������#I�@���$D$��Sll��ۯ?�X�b�z�jO�V]�{���*�'&u(�)8x�g�{M� �f�o[��H:�C���� S\�%�D� &[D�&�ł��P��g��ۇ���3�K���d�Y���L���5b$�z���l�)&���"iH6ԝX�7��k��vݶ��Q�|�eez��dOJ���U�zZ��c!��%������G����'7�x�5Tp��uЅ�wbT�������� ��KQ1�O䟳�m�7a�-���"
��"�6�ffB���َdK��!qH6��ɈHIA��!0��A� ������0x�����(۷e���l�>X++e=a��Ne=Q�b�E�C��ߏ�!C:t��!�8�c���Ŝ��;���Ȍt�ef��!�()�G e�����R��߇���Q_\���}:T#�X�7��"T"� #�(�ł�۶���?���-����/�Dxbb���O>FcEAbv6���0b�L�n�^��~y%2g̀�hR:$���Q�VU5%W۶����~u@S~y%�h qb���m�h: k�, ���0'%)Q��d�(�՜�G��?���5�<c0m�8\��?X��6-�~�����:_y�.�nƚ-� �Xph��8�|9��k�}L���N����(X�����q:�����/�tu#�lKI v.}y�W��p������g�$��6qp��������/��z5�
ۜZ�=]D݃�Q���ŧ���s_% ��Ӧ#}�x���Ӎ�Q��]�-v��ԝ<�fҥ7�qѯ������N�@�D���Q���w7����u�N��q��g�d����g ��+�4��7��� Jԉ�l�#k�`��!,!����AW�&&X�W�����is ���t��mhM�*���0�"
2��\�~Ӧ���Λ��ā_`���a�>]P?��1�H<c���0�"R���
��X�à�V]�����8��
d͞����@�.�MDL��S��'l~q �׋k�|�,�B��Nnߎ��,����(�p�-�nV��'�|�u��ӷ-�z��2E����K3F��B{������
?>�w����丬,�n�(�lu1�Ӊ=}����a"Ҩ� x�N� �n������-�.tr�VlZ�����=i���V� �͑]��#G� �99Y�P�������
�{��^������s�B�u1�)�ت����;��0���ӷ��!4&[D���ʯ���%�����Mo6c�bȼyL�((y�N�z�O8�u �ǃ��d�}��OLT:4���d���8,l|�Y�^�foր9�c������@tD�#wշ��'��}��231��Mt<�&�$�y��m#ъ���կ�?L}�1�(�e͜���_��t�oe^V�����(p1�"�$�F�°__�XBg�m 1�ͷ�<l�֡�1�����ĉ~ ׷z��:##
LF$�Dn���|�~��#H6L鐈�����wy �7l����mO33��I�#"��(�0�"�d���Л��p}9
qn�+�{�w����mϚ9 �x���N�0"Q' ���N�z�^�O<���lH-ή�]�-}�<.���&[DDt� ���s�� K�6/yUG����"ꉘl�1DD`��Ų:-�Á��1�":kU��!��� L��>�zM� l���p�aMP�����YXJJ��[����M�P�ހY����b��-�3���Ŋ��D]a!~�%���e�C"
x��ѽ{��K�h�ǎ�%`D= �~ jCen.���]~��z�i��2E����Cف���{0������Ck0(���l�r�Dk���1���d3�Q۬UU0DGs�u"0�"��9�����/���0��;�� "�� :�)��������Q��=F�r+-"":/�{pX,Xy�"ԝ<)��D���.� ��9,|�ǻPu�l���2�""� �aD��<N'���1�<(۞5{.��>��#DDD�{�Ѷ��
Nl�$ۖ~�%��2�""�N�� �X�W~�=~ ۖ����O<�ѨPTDDj8��H�o��rx4���ɸf�0FG+Q�P�'j� ��'�B�-�
w������j�W����0h��a���=9���[8�c;�220�����dR:,�.�d�z���"�z�O:^�K��!
y�' ���n��b�m��C�iӠ�����lQ�'�^@� q�n���Gqt�Zx=@l���{�(�q��z<I�b�EԍF\�z��zՑ#�߰^�[�����-""�Vq���=q"Tj�oۮwނ��P0*���d����][�[�ٻE!��u���Ld͜U�������-
IL���H�o�:��w��[��l�"L��Ț9 j�ַ�����q:����1٢���(� ��
�Z$[�{rPy�0�^��Qu.&[����*>��F��I�P�� �23�q饲3�~�1k�(�0٢�Ts"�>��b�]w�ۇDce��aQ�.�)��:�i#+*���s1٢����W��4�_�w/ -
q�(pd\z)���n����-�nQ�`�E!�h�O8���m��ٜ>D8$I��9W�
�sW���jU0*���d�BΖ�^D�%?㲲���P. ":�̙3���^��3q����!2R鰈:�X��rd�T:$K�.���P�x\A�4z=�=�W����/+�'
vL�(��~���ޓ&�ר����:"q��C �<ܧ���㏨<|X֫5�w��W���Ž��C+��]�=i� P(""�&L�($T������~�Z�$)�-
{?��� D�jQ `�EA�ZU�#kV˶]|��٫EDD�����w���㲲�{�d#""":��5���׫5t���HDD�{$
j֪*�ff���bc�y� #"""��D˪b� $<���wk���0��~�tHDԉl��8���pY��h��P�tJ�D�!L�(d� q�($ت���/�Ⱥu�8�0���?�><\�Ј:�{%
�J�D�(����Q�������ZY��=9�z<J�F�!�3Q@R�tHw T����_�<.��Qu�-""
X}1*��w=�&x�n#"�8&[DD��� �12�7I����C�t�lQ����H�d<�)�1�""��ơD
vL���(�q(���-""
hJ�`�d����)�1٢��s��xo�<l~q �w�R:"�&m %V8�[9�(�1٢�rd�jԝ<�=~�/��V~�tHD� �J,ܹ�C��lQа���:�8��uUj5z_:Qᨈ��$I��]/ڹ�C��lQ�8��z����#a��P("�n�'�z�����^����GB��z�Ç�СC��Ɂ{��Emm-�1
b�:lH�x|5;tz�5�����^�4H*l�hQ�V����<x0bcc����`̘1���]�\]�l�ٳ˗/�G}�C�1����̨еhT�ً*�C����[ ��B�F�\�<ܧP'���ǬY�p�UWa���0�L���]�l9���X�d ���`���{ �$I�$ U�٫tXD�͚���W�������GAFFT� �������^{ }���}�݇�Ǐ3ѢN1��)�ͽZy��#""%0Ѣ�W__��_Ç���ߏ'N�{ӌtZ��~�z�����~;JJJ�dQ�)�~��N�H�������� /��ѣG�^��r~���l���k�2e
{��K�% �����2�""��QQQ���7�|3N�<��\炓�E����og�E]fp�|��j�� �Q7���0�|:t�CÊ�l���bΜ9x��hQ�)Bd�)e۶m�1c�l�w;'�=�d��뿰jժ�;Q�eF�eיl�����p�u�aϞ=���:�dkѢE���o!�`�u)�$!��$s��1���$�@aa!n��V�����N��,Y�:d�E]-+"��ZDDp������>�����޶C�֪U�p�}�1ɢncq����uN'�B$"��!��g�}�_|ug����3�;���%%%�$Q{�H���N�u.��!Q�P�g6�����b��d��� ���=zt��ͷ�g��W_Eiii�G�^!P�p0�""�d�O��� ��^) �.�Bt>�x�3'��[�p8���Os����F���PP�:��� 5D�A����
;v쀫�N�v%[��""�@��V4�x/I���;�_�vBॗ^BUU������d��c ��?� �����D�m͚5ػw��d��L�֯_�^-""
HG,xZ$[��L�H9B�]� ���L�V�Z�^-""
H �px<��T �Ha6l��j�m;g���vY@DDD�����0�H1۶mCAA�l�Y��۶mk�4�DDDJi]���I!BlذA���VNN���(��hh��m�e�),''Gv��� ㉈(Нhճ��d�I�V0"��*++e�5g��'�4�3������Pn����8t:����t�l6�߿���g�����n� �²e��t:��yu:� ���t��v8p���!�k����o�yyyX�|9�v��!)�����fC��p�N-\�b2��΅���)��I���w��p�S�I�.����n��� ���ߏ{�f�R�ኟ�<�֮] ��{�G�y�ϟ�x%%%ذa��������°h�"�s�=����}N����C=�իW�͇L�͛�����AEE�l�ң���7�w�Z��f3��s�DRD�z�8�HJH5�|G��$���zLL ��}L�6 ^�˗/��ݻ���0y�dL�0��ƌӣw|mٴi6oތ�;w�b�����z�X��G���ٳ�}�� �u����;#�.� �b�
�ڵ Z��&M������o��K/E^^�=WG��z,_�cǎ�W\��[�^PR�e�lڴ {��A]]]'F|�mV�PbZ���+z0)�ʮ�5��]Ҥ�D�Av�x��ᔢR���O`ʔ)(..�5�\�]�v����zMƎ��ᄏ͵�z�-[�`ƌ K�T*L&�Z-t:�S=��K�Ra��Ř6m���p��bǎp�ݾ�i��Ѹ뮻�p8.��:��h�F��^�������[�bΜ9â⨥AV$�;#���/��ֿdz&[=��K�H5�d��l���_t�E���k .�%Z����֭[�m۶6; ������r�ر���~��j����Daa!�����'B��`˖-����D\r�%�x<ظq#jjjd����п�<y�&� �ǏGLL ��ߏ��w����Q�F!&&�17�߿?� I��w�^����_�V#++ UUU(//��f����h4B�R!-- ���p8(,,��KKKèQ�`2���������v�СX�`$I�]w��K�Z~N۷oǍ7�x��i�ȑ���AEEv�����6N���Gqq1�������#""9998z����_��d�Z�Fjj*233a���^kTT� �^�z�f�aǎ(**�W�V#33555(++;��ZKMMŨQ����<�ٳǯ���9JJJP[[�A�a���8t�<��z�Ӊ*��*I�Q�F�^�"���c!�#΢w��/�t���!��?�\,^;Z�<v�Ȍ0+��c� ��.6l� ����}���X��o
��.<��b��œO>)���d��1c�����>�����EMM�p�������*n��V&���? ����[ee��={�P�T�Ǫ���?�����Dii����G,[�L$&&��ҥK��f���������GEE�>���5����ln��.��2QSS#���+!T*�x�7��f^�Wx�^����9s�P���������_<999b��Ѳ���#����F�i�&ߡ��?����Z�~��駟��O�>]TVV����;��{o_x��}$I�����Z�m��9s��F#z��%�}�]���({,��-^|�E������EEE�X�r�����mk����D�XK�,���~�?..N���ۢ��Q�����#ƍ'{��M�&���Ē%K�O<!jkk�������o߾��F'&ċiI�"�l:IR���g_Zb��K�]�5B�lO�p��h4�f��r�����7����u���H��?��%rrr�w�!���*��M�����#���� ����̙3��b�����r�+V�� �?�P8a�X���/�v�x뭷�… ŷ�~+�N��������Ǫ��EEE��r�u�։� ��zH��� ��#^}�UY�!֭['�N�سg����;�UW]%/^���g�F��w������j���?�XL�0A\|����G���/ hN"�����~ҤI����(,,.�K������G�-IIIB�$.֬Y#�N���O����Ÿq��s�='E^^��߿��s��믅��O>��0�L���"""|ϱg�q��w����J���UUU����{N�>]v�e�����9�]�V�y���g��E�\.q�7
�V+��'�GyD�<yR�\.�t�R��c��E����!I����;EUU�x��wů�k�_�B�s�=���T�\.q� 7��9���*�j�*+���w�}'��.��ϊ��z�r��M7�$�����o��F8��g��3f�q�Ɖg�yFX,q��1p�@!�J`����B�t:��͛Œ%K��/�,��J�.J���0��%�/�z�xi�(_������4�w��-�n���o~��q9���;�V�Ul۶M$''��K�$�O�.���Dmm�:t��o�ɖ���=��/a0�Lb�ڵ��t
��!~����v�111b�޽��p�z���-��#�x� Y�����EMM������پ���.����E�^�d1O�6M��Ԉ��Z1l�0!I�0�LbӦM���V >\�"��]hN����[Yϊ�d7n bҤI~���7�,���ŧ�~*���}�5�x�嗅�f�����t�l6��۷���&� .���bǎ"==��$Ib�ԩ���R��֊�#G��֜l5���=x�$�zז-[��Zׯ_/,��:u��h4��|�HJJ����]w�%,�x��}��CUU�X�z�_���xēO>)�]{��ECC�X�l�콼��EMM�����e���F��⋢��Q<������d�����{O��� I�d�7/���KK\>�J����LDNq|˂����v�G��b�ܹ�j�x��e�S�9�ر&� cǎ�F#/�ܸq#^z�%߂�V��7�Ļヒ>��WKS[[��;wh��Q��?�͛7�瞓�D�e�>|aaa4hT*�,�^z�W[��ƍ�s�NY��V�F��'O��� ���h4�7o4 �z�-�Y�n�_�5.��R h4_���jm��k�Z\y����x��QZZ껟�6m�Ν;a41f�h�Z��7oތ%K��bB`ݺu�Z�HKK��hl�뭨�@ii�_���Ç�t:��=9�����}q}���~qi4\}���j�x�wdg5��^�F IDAT�n|��7��l?~��k9v�/^���J�:xo�k%�I���%�&�Z��z}��V1���lFZZ:�u:����1q�D 0j�ZV$m�Z�
ī����z���(۱ !PWW! ��Yn���~�e�ِ����#G"==*��/���|���v;^z�%�=�=����j���K�ꫯ�p8��^�Ixx8��Ҡ�hp�w`޼y�ם���ш��h�Zx<_��Mr�f3RSS�t:�����ۇI�&!++ �FV0���T__�� �^���GJJ
Ə����#,, ���0�P���>��f���UWW��#�+<<�����tX�p!���*��8,, �����t�����Guu5�,�s`�E�����zu�f��P[[ !���ڵ��j�0 p�ݰ��~;$!���!�@XX�O���y�椭�7H��B�����(�)�+V�ꫯ��ŋ1~�xL�8Ǐǝwމ�k��%0��ܣ�R�0t�Pdff�ݦ��?��#�v;�n�/���̄Z�>�4�����;�sj�Yt�󈌌����w\��0 B��tB���� ����K�$��j_�mvv6����w���B�_����JD�aD
(�{�%�r:�صk�^/�L�����s���v�v�g� ���TUU)r�|tt4��sp��p�\P��g�j��y�����I�&a̘1���O������{�>��9�����0p�@dff�.YYYx������Ӊݻw��vc���o�s8�γ�昘H���ϩ#ɑ$IX�x1���zlڴ �G���`@XXfϞ����e\^���_��4hP���>*�%��c�EàR!V��]wy�3�(������p80n�8L�0��C (--�^�Gvv���M&F�I���O?�w�O{DEE� EFF"++ B=z� ())9k�#G��J��%5- !����n�+W���lƨQ��n�����������h4����=G[�濭X�6� cǎń ���-?�!C���D��5���IXtt4�L��ǃ���/سg�nw��B5���q�$�gz����lQ�H2eG�e����-[�n�:H���K���.�%*�
�������1x�`�\.|���x<X�hRRRd�w��";;���ضm[�&[�G��O<���߶ �w��(,,ā|=_~�%�n7��^���K�8 ,�СC}1��n�t:dff�ދ�C�6��;.� V�Z��z�����raŊ�x<�����w�N'K��mۆu�����c֬Y��K�R�ꫯƖ-[0l�0��n|��Wp:���{���*{�k��]tN�8�{����r�f�A��"%%E�Z��/I����t:̝;�C�����/�����w���=m�����D䏿
1zy�Kac` !6��������˗c�СX�r%:�@�Vcܸq���Gyy�����7�ĵ�^�#F`ӦM�裏PYY�1c���Yy��eg�u!n���?_�5RSSq��WC���駟FYY���⭷�‚ 0j�(lذ�1*++q�����/<��C���SSS�a����bŊ�������1w�\���`�ΝgMP\.v�؁�'⩧�������������ᅬ `„ X�~=��}���#""�\r fΜ�[n�˗/�%y�-Bzz:F��+V����8p�T*ƌ���DTTT��p����w�����1z�h�_��|� ���1j�(\~��$ �<�JJJ.����k}�'0l�0DEE�W^��?��͛7����׿��W_}N��_=Ǝ�wdg�裏0�|L�4 �}�>��;v 7nfΜ�� ���?�RTD��l�(�˒�d��^���xLm]bbbēO>��yF�����믋��,�|C�����ߖͮ��z�O?�$f̘�7�����E}}�X�b�lN%�i�)��*�}�Y�D������ ��.n��v�ė��l�^��7�x����Ԉ;�C��z�ט��,�z�-ٌ�^�W�ڵK6�;a4���?/�������۷��c��挚6m����_~��� ������N�Sx�^a�X�%�\�o\\���?��7����˖-������)::Z,^��7�z���7�� ��g���$�.]*�A����ݻw�fxo��S�NUUU⫯���Y@ 0@����ݻw��Wk~�5k����{�'Nj�Z$$$���{O�����뮻N9rD|��W�Ib�)S����
���_���jk[˸���ENN�l����xɒ%�9�Z��_|�0`����2e�(//_�����S�7� /�xiIg9L�ӧ�����g�N��#�`@��0h$ ��V�tbQpgj�ILLD\\, �����x����$ ����ӧ�j5
�Zl���&�$I�����b�vT��0�;��`�̙��O�y�f,X��������űc��:5Cs̽{��F�9k̒$A�ףO�>0�L(,,DEE��m����#-- QQQ(((�[�Q�$�t:���������BAA\.�{�Z~N���hllDQQ����ۇ���O�>�h4(**Bee�?'�� ����� ��ね���Z�֖��$I���EZZ���QXX�ǃ��0�\.��j+� �K�ӡw�ވ��Duu���=G ��jaR�Q`e �Z�f�lQ@�N]�Ӈt�Z'[�\�2�$Ế��?"aj5j�N<���
��K=W���P� -":!��lF�F�J�x��v�K��l�<m�z�R������f��H1<�(�mذ�_~9JJJ8!%�('�a��T�^/�95�<� 0�"
aV�6lP: �nWnw��d��=[�~���(��l���J��/�N�]�lQ�)�Z�mq�M����I!L���(丅@���J�$ �FطEJ`�EDD!��a��m�M��"��#"��Tb���4��=�HL���($7Ze=[ia&�TD݉S?��bt:ܖ� �˅R� �v~,+W:,"
r��lB�D�̵H ��"���u�e2b@d&%&bxt��!Q��;��z} �Q�F�F�pT�1�"����(T��$���T:$"
�V��nK�$���q�Gݎ�9R\�^/�^�d��:I�M^��`d�<u?�l���Z�װ��P("
5v�8VoA�Պ�]鐨b�E�kݳ�d��:���
l���� ������d��k5���0"u/ F$Rk�Hq:��A�.�B�u>&[�(�$��bqX����{�{&[���Vvf���V0""���d���ɮ�^���B �-RT�3Y�EDD���)*B��x""
mL�HQL���(�1�"E1�""�P�d��l9�lQh �� �Y�f�`0`��HJJ�"��k��Zpભ�?�gB�pT��ƍ��x�a�����x<J��m�~�[Q�p���k�#v�t�u�sߑ�[On?Z��8�:}��A~~~7��9&O��k���f�B�޽�88�<���J��+����b�ڵ��/�|�r444(R�c���
Ob�n��b��&, ��9�f�ҡ�=��h�ezR��̙3��SOa���l ��XYY��y��� p:�~4��M���] KI�o'x݇#�woe�B��hK��*$j�Ǝ�u���o���#�Pu���D<�������ܹs��gUۏ�A�$�{��ӻ��c���������>�����u��a���J�B�#������?��O? ]�տ���Y��ӡj�l5��5�/�b���舠N�^~�e���+0��$�G�D
h���w�}���O�tH�����LK��:��}]�Ix{h�v�������fK��aٲe�5kV��}�5�w����hw�������.�#�&���P�$ J�Dj� ���`ԩ��{B`�޽�3g����1��c��sŕ�E{>���T��Ǟ�7�� �%�r��A_ ���/c�…gm(k�x绣�v��v��u�Q����� J��Z��oO� 6`�ܹ�����ύ�G�el��%�^��m� Q�2�^���#�B��舠N����?��W^9cC�t{�����r�I8�^"$
}�2cq���H�3A���P��K���;���P ¶����T&�{Z�ͷm�ԇ�0D(U���GGm�5f�|�������k�x����'�&� � ��� Ш��?���;�����0�� ��eD�B:���>n!j�3X��͂��8A;��+�������Å������Pu�Ã�����p{�{�$I��?���H������1<�+Sc$/��[��*h��+���7�`�#��Z;����
",]������x�;��h�"��z";��5s� �ӻ>����RN0��!h����͆����� RӾ�3Fn_�Ppry�_�����J�$ ��{/����� �j�h��h�=�/�$X���`h?:CP$[3f��������;�Ea���#� ����[��P�:<xue.�.����`��~�;ŎN�~PK��$���0k%�-�r��Y�"ٺ��k�<*�ipb�OE
EEB�l�����$������bۡ
�� I�p��+��j�f��-�c��) 5 ����E�5w��6�/]��ӳ���)�M�8�`(�|� ��(v:t(����_l?�%��,�WK�A�(5 ����|�8y��6��w���v�B���3h�6�u�>\�H�3�(o��� L���Ť��$a���8|�p�������R�:� S�hXM1J�D���3|�ָq��ؗ_ã� �w�O���>�vڙWwgM�6�ۇ�~P[����#���,ej�3��%�����L���ܾ�pe7GB�I핟��бg+T<Yo�eBBT��=�c�AmR�q�ټIQ��~t���<))����u�n��:��uϖΤP$��*�l~�pMs�tw����H�Gg
�d�w��mn/��������+wwi�l���s��E���ӻ�Ȕ�Qp ���3|�gZ^����͑Pg2�je�9�Zj�h����Jl?��O���)�k����r�g@��&�a���ʼn�T��
�j��g˫�ʮ'D�1mD
���P��H�
}�̨����.8>���r{!ŗAa�qf��~�K��:����H�2���"�����o?:S�'[�ϠU�W2p��4�*�N�P���,]��}��g���ٲ��O�Nļ 騨s`o~ ,���9^��[fe!>R��+������x+O=N(��,�Q�µ��`�Ž�U�?�u{J���<4ڹHv(`�d� j<8(�dD�+��+p��:�
C�Dc`j�g^6�ym;j�q�D��������؅�g��[>��hճu�d�����:8�X�!�D�kq��LL����aNwy3٢�*�ǹK�11;s.NE�ʼn-��Q����>��7ӆ%����;��̓���d+�Hn�,�3�Peq����x�F����1 5W�I���~s�$A�UA-IЪ�]
�q� �:�����:<���OU� j���#�m�7;�PU��o��U:,"?��~�K���V���C�z��� �bkn�=3F$cbv"Vl-@��5����V���C �Ҋ���h�C9TX�C��ۼ�I��^0�5�kt!��6��ZzřPQ���A����(�5*-i�;mިS!>����<>ʀF��@E�]������l��%�ݥ�2KR�L���Po=]��fl�Q�kU8VҀ�s���G�d3����8^ڀ�ǽj H�3���s�ś����VʓD ?�U�ǟː_ր)ÒؙE)�ڏ�p�./r �P��?�x���
�p�P�6�W��cʰDuj��L�B�� 2v@�j�#��������2+�i��E���+�l� |�!������C����B���q��~0jՐ$ ��-'��ch�����b���Ch\� ����;�����fn�����C���ڿ� �d Z��=�_ �� {����O���n�1xp~6V�,BY� ���&]�ض�u�d�h�Q�6gF��FբF��/�8����;��}c����vg�^�_�K�V�BE���u-�F�o�=��ςH)��~4�}y|���~� l?�Ep�y�
�l � Ɉ�$I؛_��FL:��E�����F|��5 Nd���/Ǧ�K3�R��wƎ$IPI�O�٨��c5�r��q&���_�KG^��4�-�zw1����}q*"���]��z.
*�j�& I����ذ� ;r+�p��0�11M�Z���Hl>xz���Z�>5o�6,�)��5�z�)q&���_�MÑ�zl:P�;"6hUx`�E��-�*��O�p�<�4;�F���k�ⱷw����c�s\:$�f��Hq=�jU����Pk?,V�$���ɽqŘT.�?��c��������->�_���b��`���G��0�% ��64؂s-@�c�$�Z"�4�$�����I��2uX
��D �����XN�pw�Vb߉<r�E�}q*�唢�Z��m6j�я��l� �ZU6��\�����P%�^�}���+�ǘ�8uaX��y����Z��~.CM���🅀:>���#��aۡ
��=ө�f�o8�O7���Tfsx0�El�S1O���^fl=T��V����C�Uc�$���;�d�k�Y����������p Q���c߉Z�$ 7L틑�cΫ�8��ĕ�]x Kq)��퇫k?Lz5�\� �J�J���3)�c~RSj�V�.u���* RK�%�㡒$��Z�w�t�D-�-0����w�uX��lQМcUp{���h��h�:�K�P$ '+m���N����8Y�/��-�s�.�h�M��Jj:*� amN���+�v^����(��@��;���(-
z!�~8Y����~XOM�,�ʒ�O 6\�h�qŘT�3��ʆ����蓄Q��g+H�Q�NӾFŨW#.B�ۃ�J�_���(o���H� �J�l�?���F���d�Z��f�5�0(=
IQ�j�5A%IP�:6UB[�5��ͨS#.R�
�|t/L�N��'&\�J�٤�Z%�j5Jjlh���~�5�f5�-Ⱆ�#N�ڏ�b0w|�xme.jz�Ħ���V�p��h85�]��0H�<g��Q��Ө��
Y�hK�S �Q���l��$u��&�������$�Uҩ�O/Ԫ�_��el�G��$�w��6އ�:��ע�e,DA��G��(�t[]�IEڏ��f��Ъ%��2
j�=�K���V�py��X�?Ō�zGcŖ8�q���+���t�3�.4M&j��:4c�$�Ck)�tYL�Nž�5xk���l:{gX�<��x��w:6�h:k�������hq}���m�2�m�����?y�z���H�7��Ca���uǰ��2�^A
n��
"[������i�缽��AM� :�
�� =7��e �Wb鴣����5.� �Njw�;���FtO�cszPU�Z%!!J�{���P��ß��� ���q��k�;ڏ�hZ0q|�� ��^$�E���d+�(����5PI�*C{������o��h���+ �� �
�/�39; � a(��#���#��r{./�j �zy\��6P�("ը��Uu�bk���C��+ǥ�l���ը�
a�B�^�6C�/�B�^]�+p���#֬ßd#1ڈ�6`��N/�8�D\�׾>�?��p�����G�dE#NV6B-I���0-j�p��5��pivz'��ߏƆ�h����+��xcM�����
��a@j$n���R̈
�aŖV�p�d-& I��W���'S�� ���K�-����I������b���uv�4����b����ؑ[���֨�y{#�T�nJ�*0 5�;^)����~%u'�ms�an�DSM[cQ$q��+ۏ��EZ\8 ��Fcp=�{�����Y�|�l��:~�'����#S�oBzB���`]N)>ݔ�*K�Y,�����tY&����K24�-i������㵲�R����u{�~}�^��M��� Vl9������y�3`wy���Bx��[����UctV^1p�Ăg>ݏ?�΂�Uu�bhOl�h� IDATV�5:<x�=�͔~�:, &���z�;r+e3@�S��i��^�ƄA H�3Ɋt#�t?(�Ú��py8�)����ư�TJP����� �{z* QY�7���#���i�@s��_%�)��g���F���S�5I�3������������Ǐ###��l����)Q`�N���٤���Ee���Co���
��F�$ ��Xl�3�Y��j8]�6���:����d�#�z�����au�n $f���[ݨ��C������\g��c�QKH�1¨S���Fe��6޳�=G[��l���qg�p��'���:DEE����K�\(�mc�qz{���<�
joS�\I���?�Jx5:h ��5�5�cf�5r�&C���k�Zc�qZw��ezŞ� %N�S��BMù���fonyv6-��l�3� ��:��#�[ݨ�6ȶ��ht��ydž�����3ަ=�����E�\zb�a��!��'xT�����xL�*�W��[*!��+)Ża��A�!�+���Fx5g���~��D��b�E�����V���4��.����l'"��2��O]}�+r�w�up��`3F�nf��t*�J)�����\7�ş�+�� <�����j�15�[� ϩ#L"��f��Jx��zS}�����v�+��T�@�v!�"Fk�/��4(O�bu�-R�$$!�a�ED]�*6ӗTIB ����WR��������H.΁�q���ʄA���e�r��-�VF[���u�[u����` K�%K��b�����>�1B�t>�G���Z���P���`E��ثE���f��Ay�HD]ϥǾ��p��@�ll�$����}ː;h
��G�9��7BբW�!<�Q龄���سE��`��]��*N%"�*��I88�jx4M��Kh��J?� ���4��TH,� ���_q�Hx�:���P�d��Q�s����$�"q0
2.�W}z����|�=�=Tn'b���h��Ɨ� ��m]~{�[5Oجua*QW*�fNED}b�� y=���'���ت#����^#�҇)3?�l����oDDԉ�J����C�)�W0�^d� ed��%I�+�V�. �-�V��Ft�g���2�q0�WpiM��v4n;$���jՙ�a�Jm�a���D�L~6�KcT("��j�3�;`���]�����1�0�:�-�V�V=[n-�-"R�$���f��\٩ Ce�`N�@���u+�U��-"R�P�q��T�Fg���Ap�L
FF���u+�U޳�⺈D�0�ր�C����;,J���":_L��[�����D��(2.]�c��1,�:��I��S�j=��Ps����}��U��ϽS�{��c���16��B%��%���Iv ��v I�%��&c �6�p�En�eɖՋUF�hf�=�?f4֨Y�5s�^�����i_1�s�9��s��J��"�Ӝ6eW��H��j���A�R�(�>9�$b�Z�t��g�(z�9���{�R�ʢ� ��[���
�^�J�������(�4��2jWB\�ׯ!]R����X97+��a��4n�n%���p^�t:���a��!��ZRװj^.�vC�����Y���+X�������n""+������EFWDg��EE�z���̋a���*�H��Ä�d�j�X|���Ե��p`�""�)%��C׼F�B�@�=[��2=�-""��@�5H�gh94:t� ��!=�9q�<�H HR�����ֆk���h8�{i-{�5��A*:�kQH^Tdb��""���t�����aD�c�""�� ��xr�){-��fưEDd������#ó�qΖ��g^�kA�ž-��{i [ю{���9#""?��h�=�L����V��g��}Έ����8��sFD4v1lE+�qf)�猈h�b؊R���z����İm�Ǚeq�3"�����835�sFDD�1lE)�qf=��9c�"KQU$N����w��������UmH�9 ��h?T����S?E%����=�,��>g�\d i ���<�(�zl}.��w/�-'F��B q�Tx�����0��.e�|L��>�SS D`���8�g7���?���E����h�=�,����U U�Pԭ_����C�-4w7��-#~Θ��}�h��S|�Ɉ|n��;����W�:|�y��z﷐2{�.��kׄ��&��hƞ-k�>gdQ=C�ݍ h+=8*�B���[��|vJ�~�QR�:*�Q��_1�#i�T� �Nj�h����("�.X����q���!s�r�]r)쉉hݿe�?�����nFƢŀݎ�E�����׋��= ��C�Zq��?e�>���CƹKкw/:���0q"J��55!�]|��H�2~�$�'��O��/�#5�<K���e[�1lQD���"e�l�z�'���BӖͰ''#u�|�z�a|�Ѓ�������で��� ������<�L���{�yyp�����=ь�iW"s�RT�}9�����\x!<����]îW8Ȼ�R!���'@�/Xz牯���׺��`Vo(��c�""�Q��|����t�/�wM5��Р�B�۱���UU(
�~�^d��IӦ�y�T����o��'�D��;p�'C���f�3=;�0\��(��:d.Y���߂��V)3g����������wH�7)3g�������`OKE� E�ͦ�0>'�s�����۪�.gLᢦDD4*�II���Gl����|��1!����]G��mbs��ZB���O������؈%{WP��¢�;"k�2�>��o?e`J�?�W\�܋.FLv6��Ù�5.n�'��9S2x-t��g���FE�����ա��O����Ӻ� ���p ���������k�mX��E���d)\�JaOKCҌ�hۿ��S>��Ñ?>�E��oF�ŗ"�hJ~�(���CF+���,����DD4zz�����=��W5�Y�K����nh@�9��&$ u�l��P�����aH wM J��-:�W"q�T$L�tF���Ş-""� �˅�͟!�+�<u2��_gZ��>�9W�� wC�
a����2p��l��9b�����VG�������64{���(��> RJ���#��>��W_��3qb�.xZ[�~�p�g�;lKNF\A!�χ��F�O�'c�g����>g��@��y�47�Uv��r�,)y�K�<h��y�=���#z.��ޖ�̚�� /��4��쁻�攏�8v��r$Ϙ H���6�r1R[R�?��p�Ԡ��Oய�#=��]���,ԭ��u��F�a����>g=�g�Ɣ��1y�h�|�=� �M4���m����iӑ<}F�mZg'�nEw}����յ��H�����?��\.T�Y��߸��������#p���<���xP�~&O����F�*=���ko�񿽊�뾈�_�z����v�r�{e���|���E�Xe�3%6o�9+W��� =[�.�G4�ZKJ����C��~t� �|��~k]�����[n���U���o�1���r �<���� u�[67$]G՛o��7aON�=) ���Ɔ�/fJ�ðE�Xe���iӑ:g.J����a�����$����, v\vw�\�k���UR�ᓏG�����ޖ��$ ���h���Į��z�=�^/b�X"��3+�s梳�8:�3�"^�H���>g�� m�������>g��d8�������2�>g�K�CGyy�}Φ#s�Ґ�����7�>g��9Dc�#5�e�q��W,�)�{�hPV�猈ƞ�����GLw�4Y{�hPV�猈�(� EسE���>gDDDFc� �
���a��Z�>gΌ�Q�猈�(��(""��Q���-���9%.Y˖Aq8�HIT���Ȼ�*H�M۷�[����h�1lQ?V�� �
�1�;!�����y��p�m]�PðEDDaưE�Xb�3��R||� ��=���‰a�m���\u����I�_~���/�ӧ��a���3+�s�q�3�Q T�����-�z=��ծ������0lQ��>gD#$j�ڑ��x��
�Q<�S_qM���b2-�S?/3�:�vU���Ẅ����,�R����׶❏��_S�g�
�����w����8�HDd���@(*��������oB�y uݿ�]O�boq��F
U��ڡڝP���8!�� �̌a���
� �@QmPmH]������ X Z�EBQ!T;�� Eu@QlB��2;�-""����������=&p�
]�BJR�^A��+z��{�@Q�Pl�v'�����q8Ѽ���,@�PE�b���^.t��F�ɰ%����-Vlv�R���.�p������BE��M@(6(�)u��g �0b��/nP�(*�j�#*
{�,�a�ĸ�F���d! ��
���)Q5����[O�Vυ=��F�Űeb�v��B�~��}R�'{�(����=�� ��F���� I��k4 �`" Y�ð��%p� ��>'jp1�1\Y�V������3�":=[o6�d$��YN�ӆ�u>��$���O��-�?��Y���S�+��{�����0T;vq&oT�V�yO���Dw\< r ����x���`WGvj_:# �_7�qv8�*�z�$L-H
S�c{��T�m7~�����3o��v�z9Q*�fN`�B�#�3�[oѨ�=.5d2}Vj,�Z\�W6��m��;.� �״>�]����8x�-,5�E [�h�m7��P��vC��<mG�^[o(�����D�u.d����|���p� ��!-���.�=��j�.��h�m7,�[oQd��� &��nSBz��d2�xe�L���.3`��T�[�c�V��ƭ7�(R�k]���*\��0xL8of��\9�c�z�$8�=���?�?³�(c؊V�vü��EЋʱlf6R�/rB|��x�C>f��4,��ٯW��۫p��#�5�5 [ш�nX�� ��p��ʦ����!�'�&⒳����nS�X�6�˃?�c�V80lE+n�a �z��"��͕�`n��\�g8��)�>�_֕�۫���1�a+�q� K`�"�p��{�0����!�ZHy����օvՆ�8b�2n�aN WDA%'��@M��w�߼���&aİeV<�Q����~KA�ʺ]58R�ֺ�:��HDDd'\�a��'�sR|�1lY�+�����V�z�
4�w�����a����B<>����Sޯ�օw�WE�"b�"""���-w�����z.�) [DDD4���?��8��j�6^�HDD��� F���o~V�+�\����x�C�[�W�3lQ�����膴��#X63 ) �`�y�c�;����+\���ﱊa�������(%%V����yy�5>��h��/.�/.��)�h�燛�ʦ��1�C�E�@В��U�rqߵ��Lfָ4���]�� ��� 8A����K��%u W-.2�":W.*t�ԃ=�c �E�R���0!7��Z&c��� u����A [DDu����]�]
�] �l��^-�a����IϤx��Aj>Cˡѡk^H]��a,�y""�.RR��:t}���/D�(��^Z �n�w\������w�M�g�E����9��jd`���������\c��l9R�
Zc�=e�""��81�1xb����8F�3�E'�lY�Ę~/�����ˆa����(������ˆa����(������ˆa����(������ˆa����(��5Qo����S�:�}6L�uu���Ԕ t�SS�8y
��N���h��%� [DDD��-8 3� ��}Ö˅��� oˉ�=�H�2��&t76�b�ã��b֏~��� =|���QQ�:�*�-""�^��B(
�֯C�����ɚ��֖?gLN�>�S4|�)>�d�{�r/����B����cG�Űef&�Ʀ6tDQ�'�t76���਴�B���[������l\}-7�nGڼ�{m�c�2�^P9�����(��
WB@��g ]D��u�Jd-_�CO��˖#�KaOLD��}({�9t��t32-�v�/Z�н^~�Y�B֊ �u��({�Y]w2�]�ֽ{�YU���Q�ۧன y��oFҔ)8��'�=�<x�B`� _��*8��%�p�/�A0l����(%%V����yy�5> <]�GIE3>?܄W6��."3���E��٘��O����-�aONF����������kk���ok+DA!��OK t����?OnR��Č�=�ؼ<��C�l�hF�+��d)*׾|][J
r.���Fh�!kL�9 �K�C���U[3�})|��"���aռ\�w�,�,�5. �ƥ�aW�zC94�;A�2��@\��������னTU(v;v<p?���E��oދ� i�T4oق�7^C���X�ēh�|<�$����B@�lp��c����!�3#��\��%KQ��[л��*e�,8�P��ߠ�݃�/�NL��VtUW��&E��2�^AK��Z\dtEt��\T�>H�{+�(�ؓ������?q��PccB�#��3������� ��� ���(���AKJ@Jt76�D��"�����Z� �χ��ۇl;r.X���q(�����rA��1 {��B�ԡk>L�M6�:C�1v�j`�,��E��7_G�K�CM��"����Ӻ� ���p ���������k�mX��E���d)\�JaOKCҌ�hۿ��A�ϑ���뿄�m[qb�.���0 [&!���u���Rh��R�R� $�V�^��=���3�p�m�~t74 ��E8�v Rg͆=>u?
��H������@���?q�Á�+����0����N�>��h�3)��k�?V�k^H�����yQ>� ��?C�W"y�4d.;�����=d����%K�=g�*tM����7�����)�a� ��)u���akõ_�`Q4\罴�����5HE ��Odq�O��j|��?���>F��W���k�0a"��m���u��[�"���:������"��s����U^���°e�'p�jː�yxRJ^YJ��g�A��!yD��@���A���si�� e�l�^x1����d��X����Q��ˑ<c& %�?�9������i ���c�2�B��a-R��:H�\DQ����kH�6��g�ܦuv�q�Vt��Aj��s��n�,<���?�>� kVc�7�Ƥ���:v?��u��>O��<Ԯ_�ɓ&���m�JO�w����Mj��I [f8)K�o����(����`� �~��g���P�ګ�ֺj-كM��ԯ��n����1b22�mm����yzs��A�:�l>nĤā������A����‹a�Lسe-|?���0?��������kr ��!��r %>���'��A�\܇��(�9���:w:�����1�ˡ���-""�(�HME{�aԮ�Z��{!Rtb�"""�b��cϣ�pځ�q���(�1h��Q1l��Q1l��Qq�:5UE��)P�N�>����:�^Zj�+e�@Ҍ�/�(h/-E{�A��""" cآSJ[pf��AE��-� [�ޖ#{R!�8e*<MM�nl�j�2w��s/i����D���_�����:�ht,�U�K��� �a�NI�*���n�:Լ��k3l�� okˈ�3&'s�)>��z2"=c�+.@ws3ʞ��#�+,��;��Թ�Pp�p���l�1"�(��F�@4, [tJ=C�ݍ h+=8*�H!�s ��u������4���G�1����"u�T��v��`���N���� V"k�rz�w�\�y�\
{b"Z��C��ϡ�x%������h1`�#}�b,((�����s��u��V\����GٳϢ��q���݋�)%�� IDAT�*$L����>wMM�k�x3��L��_? ����:\��u75B�4��o>E!P�Ԏ��D�jN��� ��U5�9�H�9�� ������C��H�7�z��d���ok+�����OK �����<�L���{�K�CGy9���f$O���%KC^ז��� /�-.�{d���deC(
��u��ODQ ��- ���2�� ��{�55��h6��O>�_hٳEÖ�|����Eŋ/�]S 04��P�v�x�~tUU���߼Y+.@Ҵ�h޲Uo����[���'���x�ɐ�RB� ��t����p>pfd��됹d)��~ z�?X�̜Gb�^��Ȇm6d�Z�� ���h��r�4�߿��1v\�l�%{������o� ���_��\��s�]֨ؼ����Fh��8�h�bآa�'%!./2��� 56&�>��?<�Z��hھ �+.@lNް_K��?������؈%{�~�9�+,��� ��,���i��}+�^�)�f���]h޽˒�(����E��#�����ϟy����嬧-��?����c��*�#>Ć-%� k��e��@���@Q�9b�:�`�qB(j�^c � [�����ա��O@�RB�xB�i]]�RBq8��ZR��Y]���6�GƢ��Z��C����!i�t���wC���?a�dL���𶵢���C���c�(̄࿈FQmPmH]�#B��5@"���>u�5/�:��z0�K,�bs[���PT(��怢:�(��EQcs�����#��� �g�-�m�~t74 ��E8�v Rg͆=>u?
��:���|�x����}��OtUW�v=D4�z�N��B�v����M*t� )u�l��۳5��a8�/8��Š.m�I�V�gK �l)6T���EQ�s���p"�����B��ϐwŕH�: ��΃���{v+:��0���������Z�@�D4�(*�� �r9���0���0�Ċ�P�����3 �R`W�yz#�����T;����]���n���>���?�o8��>F��W���k�0a"��m���������c��?�#- ~�h޵�󴈢Uϼ� lB�A�5H�==[��?émUHt�@~MQQ�3���f�$���
E�Pm�a�v!+�hؒg�A��!m��ف����'��ޖ�̚�� /��4��쁻�攏�8v��r$Ϙ H���6@�N���j�Ի�A\a!:�#i�L$M��Y��6l@W���DB@H )��S�*j hIO��CV����`�O�]M���Kʂj��Q&�pu�nk�蔼�m����iӑ<}F�mZg'�nEw}��)��W{�YR���@�\.T�Y��߸��������#p���<���xP�~&O����F�*=�� l*)�B a�d$L���>]uu [D�"���{�W��{���^-�w��~��� ���E� ��P�5�!
�� L�4�"�0l�)���`� �~�@�wt� �|��~k]�����[n���U���o�1���r �<���� u�[67�ݍ��;��'���!���f��m\I�%�v/��������� ��¯4�CV�-�a���`�ew��5��q��Y�
� �|<�ͣ��̩ωZ��<� E��Hu���:Ak������t�Y�H�;�U��q����L|2Ϩ?�wk0Xi� �������hp [d:��T��F��u�l/D""�e���|��Ր=�ȯ�&�`�"�i?�{}���D4�8�Z�YJ���*�AW������\7�̏A��L(��v(�z�\��hOʅTx:�2��DDDҚZ������=��΂4�j�4||����"�9c�3&!��y��QU��j7�,
3�-""����ᩗ]E�����ˆa����(������ˆs�,d�˯] ��t�i ["Tk�ODDd%��MDDDF [f#j���������]EÖY����] ��M�*����YÖ)�O�"�~��V���^�n���=x�ō���;��EdI��U��ؓ=�q��I������z$��?��߿ ���u@JȞ��M��K�GR�*���ꌇ=� ��\���Ed5K�CR{ <�Bm�\�O8��d��"0l���P��6�6��A�u@�N,��#����愢:�(6�@v0YMF�A�w6R����>�Ѣs�m4{����h'D�é(*�j�j� ܤB׼�R���W�b��."��)PT;��� �f�����xl���#�f'�� �Y��́7&���1�a�PT(6;��r@�}�aD� [҂a+�ݎ��D��8-"�D`X����K��{���AD" qv� ����U�/���;V�7 ! 
l6�ؠ��ԁ��-��Èq�MXv�5|6�hK�2����/pP�(*�j�#*
��YL�-P4o�KTkR>ړ� ��ĘŰeB@H )��K�*j h&�[0d��h*����ҽk�u�hI.0����ӻ�s�CϿ��� ͇��]P��W /:�j7�*2ÖY�n��
6!%y�Wˢ2Z*�<]X��O�|�Mh̜btY�E.v�48h`ED4�r�w������L@c�tH�۩�e [f�3%{��$,�j@J��௩�>,��'�}=� �2���Ed]�Uۡ�''���΁�khMd<�-3�s��e�UO�;�O����{^��ۅc�W�H1\YZRk۪!�<v�p'�ÖeX�D�v�<tȭ�iނ�ہCS/�x]DD}� �����̩p�$CZ�}���Ւ[� y���1s�����h`6w;���C�51�:tN�'0lQ�K>Q������W�o����E�F�>""ȭ� ��e�KGS�N�' [ń�Cr�ѐcG�-��sO�ʪۋ[����:�hl�����'�� ΂�\-
`آ���V�VMWl*�bS�J��gK���ؔ����\���>��ED��T�Xwk0hi� 59s�1lQ�E��GC&ǟH���+> [��_�9pLHl�¹��1�͑.��ƨ��|T�?��TH5���I��K4r [�R��C~nK� ����mg '�&����f,����"���:pd�*l\���O8:~9{�(�E��>W"�����s�c���Д9�_�ʩ��"�������sё� pD� �b:O��k� �=�Iy�W�9�c���?+$pu�g��P"��8tH`?'E�Ԧ���Z-)�C?@�s=N��Gzc)�3��5�(�u�
�E������ZSN�� �9b!�@u�Y�)8��EDDd4�-�J�� !?7���ew�#�n2��!��f^��ŋ�7
��EDDQ�s�(*yc����LD[�����혶�Ud4���Dx""�j�٢�t`���pv�pd�˨ks�`��w��R��`�t��3�X""�!0lQT��$�dލ�!�>W����КR��J��<̬ۇ�…TJDD44#RԒ�ukR�=3����=�(���h��Ȕ�g�����J$"
���혾�$�VAJ^�C��aD2�΄,t�g"�������P���yF�FDVtt�kQp|+��'�t�%hKʇ�b�4�l�i��� ���]�߸b����� ���:��Hi.��8x"�S���Vm���.�Y�*7�&�0)��
U�۝��ip�$�� �a�L�3!����EL݇��#��DD��V���2��c���BWVEf��E�V�;7��@�J$�0ȯ�E?٫�J�F[r���(��J����� %fs(��F��ݎ���Pz�-�χ�^-&�-2���␡D�ۅĖc��DD֒[�v�;��Ǚ�ƌI��jped [dz}���)���Pxl3�� ��+^�=�к�\���3'� %f���� ����28�Z�m���P�= R�2�4|�k!�kI��3^g"�������D4
��l��kb|u�tǥr��-��M˾��Yl�hķ�"��B�\�&ot��Z42 [d �3����b��~E;9W�!s*ړ����b������ۑY��� �͝ �s��40l��w��θ 4dO�rtZщ���8^��)Eȯ܊���*X�^-:m��!""�C
���B�%�l�*h�8���Ȥ����#<��FWA&�9[DDDDaİEDDDF [DDDDaİE���Z�)�߂�y�.����(N�'K*,߄�ʭ�輻�Dkr���]�A��"K��GB{ ��!�Dv�~�K""�1�a�,�6��=�2kK`�tZ�M [dI-)E�M� ���>d�w����Hy�;�&�-�&!P�{r���S�۸z�(*���X���X��?QT� 6���Ȃ�Ȳj
�� ���C�D"�v7�.�v6a�7q�'�c�QǰE�Ց����,%р��Cѱ-������+�ѥ��0l��U���r��0�"�"yU���l#<�T,��4�L����A�V�7����7���n3���¦�S��@l?
�m����a�.k|�XCk��o?NGԇ-�{��G�+!3rǥ�5�0$pe�q(1ܒ����� &�� �: ����pl�R�
��6Z���)��V]]݀�S���̪&﬐nn�v�j ��lP����e}}=d�/�g�A�)>�j�^���pǦB
����%�ڏ��a��ѣ�J��p%dVu93�Sl�ޭԖcHh�2�&+K�w`��U}}=t]�h-l?h i�eHj=!O�=/\�^�(M��h���USS3����I�������� !��?7��+�L�2@cYWW�o�l?h 9U�B�j5dNE[J���Dˋ��c4E�_Vii���OH�p%df�y B��wAռ��ce��f�6@kYRRM�"Z ��+���u����ժ�[�^�(M��h�����o��v�K�9�����hPUd6 93��B��cѐ=`�u6�Y�e��r�����|����U\�����J�Fc�H��e�hk?FSԇ���Flݺ��qE�zq��i�e/���_�G<��3���3�,˹��B$���ܺq�ƈ7�l?����:d�� �ժ��ʫS�A���)�Ö�o��ƀ��;= EY��������PU�>��s3� )Ά�¦�����?DWWW�kb�A��� U��j���`�V���c4�⌳z���l���/��@�0^�B��E�H�����y�x<�b�A~vw;�jvC�O��T�_��ZQ!Zۏ�b��u��q<����6� _Y51�Qo�ge�҅��J�����Ö-[ �����@�v�������Պ��~�!���r��񨨨�`9�KII������������t������1��#�f%�;��Dz��ó]t֯_ohc���R���Da�����i [3C�q�z�+S�l@KK {�os������ͫ�rH�(�����w����Dǀ��k֬�g�}fxC���B��G�� И�^-���� ����Ӊ���/���|c�>%G[��w���ܓ鈢Y�C�uˊq�YH��O��3�c�\s�5���4��~�~E3���w�2U����4���;8��l05]��ѰaO-VT����D4Zl
p��\�0�N8lꀟ���J\y�())��-6�~����H�:l�ĉ�����h�7
�K��j�u��7�pM��wD�R"�K��ajA
LJ���HKt�aW!���(����n��u�r]�D�c��c$L��X�`��`ʔ)�6���t�4 M���juSZ;�#U.�)��I�Ӯ@�*`S�s�������[n��~��j��
?��#a���� //O?�4���!̾�^ 't65�}�i�&]J�P��ƾ��݋�o�������ol?������p ;lM�>�HQ�C���x��G?·��m��Č��$���3���]���H.,—��W� ��5k��{�����L3ǂ�Qt0c�1�^�!+++�Ŝ )%\.~�ӟb޼yx�����M4�Φ&�������B�z�|� �6]��|�駸���} Ǐ7UC����Xfn?N%###��!�ָq��Y˨q��8t����oa���x��p��Q6�4���t�/\��^��w�ws
���x��p������/Ǻu����n��ol?��UW��/JY��Lfff�϶���bF�����ضmJJJ`��1g�\q�X�d ���1{�lP���߁��>
�#~��H?��ʢGee%�;�Ç��w��?����n��n�_-ԃ�u�8r���](8gξ�N����f���~ �o�֐s���� ��؋
UUa��a��7�TU�L��]T�<�3� o:тw �*z�]סi�^�e&��
�s�6;s�*
<������V� rs���u�]��k��g���8����i�4 n���R(��%%�2 =�}&%���e���9���iqq�)� ������v�hi�f�a*�n}�a 9g�� /DLLL8�!2ܾ�V�y��9E�9��xE�+ �TO�J~�݅�'N0hQ�-]�4��!�VRR.�첰Dd4���GuM�g!.��5�""��II�������7�W��=�ayyy�3gNȱ!�\z�a+�(Zloj�G׃�[�v;椤\ �Ey9p�`oK �vt�}Zi=��vʰu��Ws(�,�����Ɠ���0�<W��e礧�8>J�^���k�a�`ժU���9vʰ�����+W��(�h���!�[�����V��
���O��1�j�222�t�R��9w�2l !��㏳w�,�xW������[��E�ef ��-���գ���E���׿����~k��2l��3p�m���0�hҷwkNj
�lC��BDIPU\��{�^�� �h�x ��Ƣ�S��_�*R��;���(
~���w�,owK ��!�@���mpUD4�9�H��Bz������^-2�]w݅���w,V�� t�u�]�ZQ��6��.kw�H�˸��h@)v;��̀M����55h��6�2��:�,\s�5HHH��a��(������())��u�F�@�h�q}ҝN|�؈�.7t.�Hu�,�G|�^�6�����",//����QTT4�}�ݳ x��0y��3.�(Zy��+�*Q��MJ^�DeTsRR������u�������SOa��� 1�wDa �����K/!99�;��eq�Q�ri�:P�Ҷ6hR��ˍO٫E���� �V�:�v!���:u]�o���o���.�'""�E,LKE�Oþ�6�SD��'?�}�݇��S�{Za �^/�oߎ�n� �b�""���_��"%11������n� �����;��������r 6m���EDDD�����'�x�]v���������MUU���_�]w��9\DDDdIg�u֮]����zDA 8Þ��\.�n݊��a/YB^^�����n@NNTU�s�Z��χ��v����/~� ���0t��ddd���o��wߍ��\��Ĝ�ި������ظq#�}�]���;���d�"�PhFADD�*##K�,�ʕ+q饗"??���g<M*,a������Fww7<������?���F[[{�Ȕ�dd���\�=Z��--F�CDD�!##&L��f �b�
,Z����p8gԓ�WX���T}��%ڎWA�|H���M�_�-6��҈�(���ՈDcI\Z\uu�5�� ��:�{�5��"���?{;_�+4���R����0�c���V��/����������?���u���o�W�U;v@��H�̉a�h�����[�:��c����"e]������������A����s��.��0l�@|VV�ޭm�?W}��UY˶?>���ǃP)v;��ݰ�b�_�hŰE4B ���zm<�ni��?��W����=�q��y��c�o���'@(<e�9�/�h�bRR0�ƛBz���4�*"��<|��_���<�:af^�%�z �� ��i�q�uH�2%���ulx���9���m��3h>R2~�=�-~ �IDAT�B\j��U�9�-��`��Ź��2��p�����D��f�n�}�Րe�^~9�,�8��舢 ��i*<�LZuap8QJ���?�.�*O4"� ~� x\���B�{�=�s�`��-��%���}P{]!�Q_����'N�'�-�<����!��e߽�iiVE4z���@BV����C�w���JJ ���<�l��~�^Çs�t�9|H°Et�f_�Ed��,�i8���n�BWs36����tt��N������=G�R��ΐ-6˾s?U�31���A���{Fm�x"����O���⥪Á��=��،.��
r����?|� �Fbv6�?�N�������ϻ�&�Ι���!9�A4*tM�I�ht���x���H���UO>���d��"u [DDd]�P�w/bSR�\P�-yȒ����XRB��H��9[DDd,!��EV��Z"""�0b�""""
#�-"""�0b�"� ������Z�V]
E�Q��;�W�~'��Y���>�ZZ�.�(�j�솮iF�Ad8�-�h:t�|�N4���4�VV�����.�K#
��o�����]|���O{����a�(�&MB�9��?K)Q�s'>|�1�n`eD��f�n|�����j���_ǻ� F�Ed�-�B��B��'J��ᅦ�?�-LV�TV�u��+:��R�P������bAc�Q�8��q��~�����tMö�Ł��2�2���TV�w�ڪ�C�/���1}:n�Cc��"(.- �>�8�33��tM�G����z��ʈ�L0hUU���.�����jl����a�(’��p�/�=66xL�z�ȴ\uuX��#h�� Z�n� n�5�o�h,b�"�0!�g��E�����L�UW�w~���5'k��_�¯}��x�#� [DF�K�2p���ViiHК��B,���p��XQ���AF�:�nڄ������ZsK��1����o�3�VH4���2������"�*�I�.��= gB���E�lH(ʠ=\�����⣏ ��h`=��O��3h ��� \3��EK�XQ�������C-��1lE������~���L-]�%��T���҈B�����b�^kfM��r���C ZD���-�h"%�kk�LJ�#�WqQt�lnƻ?|u{�b�7b�w��h [DD4b-���߷��_{L���E5�-""1)%��CQU�K!�z [DDDDa� �D&�r�(:���.�����-"�<�~�=h��œ/߈y_�
A%"�2��"2��/���}{��؈���4^��n4�1�,2�=k��>���R�,�=[D&�r�(^����v����P���Ӎ�{�M�IN6�J�v��+��=��m۠kV��ǘ|��Pm6�K#� �-"��Rb� Ŏ��G�[[CnSm6�gec���a��Wsh���<���߰��=�����㳲p���IWHd [D&��|p��aӓ���>
�p��͆� ���Fѹ�X)E��۶ᓧ�ĉ�rhO�m��D\�迡p��U���1lY�������<�Ά��ۄP�v.^��n�ٳfT%��x%6�������s��4��g����I�EF$E [D�k��(Y��^�k��EEU��lț�3��"�/_nP�i]��س�%�yy <����r{lZ���]�|ɥ���rؙh�1lY��󡣾�W��=k������fÊ”�.���zB�޿� ��6h>_����� �w�M��ʂ��,��`�"�(��E�2l�Y�3�+6- 7�^Gb��R� 'd�Ξ�%�݇�)Sas: ��h�`�"�0)%t�M�����?�|�F@J,��=X�[8ڢ4��o�
Z�E�&>6- �~�^L����!��Ža�h,�Z t�Y�2λ�{�ղ��/�Ƨ�y*x�alZf�̼��$%Cpi��a�"K����A��G���];�������0F���ىշ~���`�r$&�*C"0l�)�rםh*=���1��K�;R��]�B��}H�σ=>�!��@ [D4��Ç���C�x�W2�*��"1'9s� �,<qF�jI�{v�f�N��ۋ �)lΘ�?XJ�W��_u�hH�~z�j6���t�z�r���+Q�������q(<�l�Λ���φ-f���z�U�]��|t���R�z�N�}��Njg�"�
��"�!z�=�{�UT}��ߊ� ! BU Y3f w�\L�� H�Ϗ`��2X����o���^���=��A���`�"�!IM��󡳩 G7mB��P�k��چ|�P(��E�܋�_�'.1��WG>�Wu5���P���!�U_񙙸饗a���P�D48�HDC�
��"173��ӿ�H]G��}�ڹU[��z���z�z�S� F�z�ee�R"}Ҥ��5�B����7O�ؗP�m�@bRS�7g.r��C�e�%2!�-"!����%w�������4�a�O���|�$ڂ���k"�+CH\�1nt��zzo��0.�i�@MlMJ-)��:M��E��*Ch�����df:9�'���c㜿y����uz���/Xx��R>l�y(� U�z:����,l����K aY�Qz��qb}��}�Oe�D��u�|^�<��HĎr������� 7+Y����k W�sgqS���N��H�Q��]�"��,�Q�X���$ɉ Lc�եo|y3M1���qB=�<?�Z� ����,�ss|~�,���6��4h���'���yt�J�6c��R���1��ݶ��j0��ch}�p寱�t4�-����7<��x��.�:ܸZ*�˿1c� Z�������� ��ի�-��VV��B]oY��� �ᤏ2�N�$S
W"��–��9��Vm�B����:�woCU��c ^�Lo���;w~+�E�=�-�o �&�6���FЪU*�f��,.R)(���ʕ���ܮ+T��88�T�}h|<�< ����t���zfأ�D��i��6�p����H)l������–���H)l�����������
"JIEND�B`�
�PNG

IHDRSm�L8sBIT|d� pHYs���+ IDATx���y|��?���^97wHB. !�> �ܠV���z��'�}k=��j�jEjն��� ^�"��#�$$$� �sϙ���.Y6���d7y=�ievv�=�����3���$� """�K"wvDDDD�L��+<r�rrr��� !�����6�QG0`��������� �=��ݷ#��e�}��a�ʕ�������‰���|NLL f͚�뮻�g�FPPP�����)�ՊW^yK�,A^^ ("""�F����ǃ>������|��b��W_�c�=���QDDD䷌F#n��6����GRR�%U�*�6l؀[o��-QDDDԥ������3�������-.�^}�U�}��,�����˚7o���"11�$��=-*�/^�^x��uycƌ���ˑ��Ѣ�~,�L&~�_��/�d!EDDD�Fbb"��}�3Z�G��`1u�UW᫯����u�$!11+V���a�.�B��+�/v�H��"""��D���B�q���˻�MSK�,q��b!EDDDݑ��ٸ��PVV��r^��W_}�?��,������B��O>��/�����&���3e�ZѫW/wX�DDDD�. ��=F�����_���
JJJ:48""""_g�Z��O4y���2�V)"""��I��U�Va�̙��t���)�J5O��K�����c��e*!!��RDDDD I���KL�2�=�� 8`�V)"""� B`ݺu���uϓ�G9'"""� ۸q#����������ﴀ���������QPP����}����NDDDDNBlܸ��o9;;�������Z!;;���2;��Nyy��������
�o���:t(���a6�q��A^�����r�-�����+`��:d�z�C� Arr2, :����.�Ꞝ���o����X�r%,Kg�DD��H�'O8q��h
��_Dee�p8BQ����-f̘!dY��8}m�������:q��1���pٷ,~�aQ^^��9�۷O\u�UB��v�qi��?�ATWW��Ǐ����N��'N�)))I�hy���Sdd$�}�]L�:��b�ʕػw/�z=&M��q��᭷���ѣ��]O�7oƖ-[�k�.��Ը� �Z�
�F���ٳ�cǎ6�EDD୷������V�ž={���0q�Ddeea���?~<rss۴��0 X�r%ƌ�k��۶m�������[�b���طo_�O�'��WXXx��z����'_�dY/����Z�"??_�5Jh4@H�$$Icǎ��N������:N����7���1a„6��ɲ,�.]*�f�(((W\q��ʵ�ѣG�7�|S$''{�s9���@���ߋ��j1y�d�����)'N�:r�Lu�>D�e���X�p!`ѢEسgEwKʶm۰}��&[Vbcc1r�HDDD���;w��d�ZN��!==������Fxx8&L��V��[�z<��G���+�(
6mڄ��J�u��z����ԩS���APP������СCl���ň#y��]���0d�H�����#77׽~�F��}����������P$''#00�,#)) ���Z�(,,����XRRF���� ���";;v��c�A�a���$ �����s�N�z\��ر7�|s���������2�ڵ�븺>���4�>}UUU AVV�F#���q��q����5((����HOO��b�����p 2={���l�Ν;QTT��F�Azz:*++q�̙K��|���1b�������}��y�osm���&� ���ǀ����Ç������IMM��ʎ'_�y�a�X�ƍExxx��%^�ua�X<��X,��O���`��g̘!���ij�>+~��x�ͪ��w�q�=�����q�V^^.fϞ�Ѳ3c� a2��_��q�]w�����C+V�=z�h2�e˖ ����SO=%BBB<�����>._�\���
b��颲�R�^�Z�F!˲X�|�0��BUU����}V�U̜9��r#�}�]�x���ŨQ�<���uuub���"&&�U�����?Q__��O?��0��O�6M�������{��:�/����=�$��^{M���7����[={�o�������X���/�����nڴi���L�]�VDFFz�s�U\\챮%K����0�����o��������_6v�X�c<u�Tq���d���O��$�����{����UN�|ara1ʼnSä�j�7�|#�v���_�*�z}��&���{a��Evv���{�u�]'��׿���J�(�x�gD@@��=3g�555���T��v�j�*�h�"���� ��*jjj�w�}',�x�7ĢE�ė_~)l6�8z��HLL�XWuu�(**v�]�_�^,Z�H����̙3BQ��+�xtF�Q�_�^�l6�o�>q���뮻N<���������@�{�y�Q__/>��C1n�81r�H����w�}��#�*��� ���ĉ�C=$
��n����x����ŋE\\��$I����o��F�l6��G�iӦ��cNJ�{N��Չ��\������֬Y#�V�x��'EPPP�>'����ƾ}��o~�q�u׉�{LTTTEQ�s�=�q��O�.Ξ=���֭['��^��ϊ��a����7�,t:� &L� |�Aq��)a��Ųe��#�<"/^,�$I��{�����_����+��~�;QRR"�v��馛��s�PQQ!���+�1�׷�~+~��_�g�}VTWW ��.n����pHH���/��j�|�1c�;v���?�!jjjıc�D�~�ܗ][aa���lb˖-bɒ%⥗^������ʉ�/L,�8q:o2�b�޽��p�n���}]��^Q__/�o�.�����%IӦMUUU�d2�A��_sS���Gy�]�u�� ��&�V��կ~��A������V�գu�UL)�"�x� ��iӦ���JQYY)233�?�w�}����;v�={��y�ԩ���R�L&1d�!I�
�7o&�I :ԣ�q_W1��_z���M�6���Z1q�D�c{뭷���j�������|�V+^z�%a6����G���Ehh�رc���iiѻh�"Q]]-v���яJ�$1e�Q^^.L&�>|��5W1�:��8I�ܭc+V���� 6���1e��� cbbD\\�W��_��ע��F�����b���_��W1�(�x��'=Z�x�Q[[+V�X�q,o��fQYY)>��S��<�V+^|�EQWW'���?��~W1�(�x�wDLL �nq�t��"��Z���$����E���t�3gt:^|�E�qG\�عs'���0f�h�Z��oڴ K�.u?0����֭���x����{����L&�ڵ ��ϋ,{��nٲ�=��Ǔ̷n݊#G� 88����,�1/]��ݷ��M��k�.��EA}}=1i�$��hk�K�V�y��A���7�� ��p`͚5�Z�?~<��j���!I���[�}�N�k���/��JJJ��B`���صk1z�h�t:��oٲK�,q�&�����Q__���$�x���PRR����ȑ#��l������4�Wuu�;����+.�V��s�B��᭷��+��p��/���lFVV�׾�8q�?�8���!��cw�����u���;���=���HJJ��jENN����fÏ?�� & ##�ƣr}}�W�g�BUU���y�p !PUU! I�������e6������Ç#99�,{���� �l�X�t�R�5
�=��Ν��K�b��հZ�-:V� ARR�Z-��̛7�c����H�t:(�⎹�ELhh(a�ٚ��`�ĉ�۷/�Z�G��>���j��
���UضDBB���������`���#00���m��l�����
��x����D��z,Z��]w��1FTT�z������p��YQD�b����l��d�}��m��N�C@@,������B 88��?��q��5�qe���N��EQ�,���yժU�;w.�qdeea„ 8y�$��^�[�Ϋ@i)W��,�4h��ӽ�)((�?������.*��ӡ�h���kj�}n�ϩ�gњ�#,, �<� n��F@���V�.���=9?.I���hܭ�����ӧ���
�a�w+)�/�5��lسgTU��ɓ|��8�as�YQQQ����N��<""��8��vh4�f[v\1�.�|��w�8q"F���?����x�w0`��K.\��b���s������S߾}��#����6� {������I�Ңm�l� �sdd$$Ij��Ԛ�G�$<������y�f�5
��ٳ���R5�KUU�1���ѿ�&���?�q���Z��Q!V�\ �Պ�c�bܸq�|S[[��� dffz-�#F@�$�޽��[oZ"<<��MXX��� !�?EQP[[���� �<|�pȲ�.ZB ;;7�t֮]���P�1��Eq�����Z�>}Z�)))�m45�^[�j�f3ƌ�q��]tۍ?��z�I��>_�󋬈�L�<����Gž}��p8.{_$�g�:ƒ$]�Q반"jd�֭X�~=$I²e�0}�t�Y�1o�<�ر ��n�g�}EQ�x�b$$$x�o�…���D^^�o�~Y��Q�F�'���ht�[�`RSSQXX�C��[(>��s8����GϞ==ֳ`� 4����^�Gzz�DZh|i�l6_�u�n����:�={��X�n�cժUP���oУG����z�h���X�~=�?��f͚�QPɲ��s�b�֭2dV�^ �͆���wHLL�X��~�3 <����}�Tv�f�:� ���oI�<�G��cΜ9����ژ>��s�l6�s�=^�SW -��ND���CԈ�b�o�[�\�� �ڵk����C�A��`�ر���Aii����믿�� bذaؼy3>�����c��Ѹꪫ��w��]s����~;����f�$&&b�ܹ0 x��q��w��o�� `Ĉظq#>��C���c�ȑ������{$���DlܸG�ŪU�P^^���,̙3���صk� �ݎ�;wb„ xꩧ0t�PDFF�_��������b��7n6l؀w�}yyy0���+0s�L�~��X�r���[�x1���1l�0�Z�
G���C� �2F��=z��� V���⭷�����1j�(lذ}�JKK1b�\}�Ր$ >� �����B�x_�x� 2���x����?b˖-HKKÿ��o���+��l���1f�����|����c�ĉ���o��{��ĉ0�;v,fΜ�E���O?�h4":Ǚ���{���O>��{�K׈ֵ����^}���o'>>^�������*v��-f̘�5�Ҵi�Duu�X�j�ǘB�s̥��z���z � @����E�}���]�L}����Ѱ]ۯ����s�0 ^�/�x� ��UU{����p>o�����[UU�c�1f���IS�N&�I|���^#p��Njo��V�l6������W\q�������_������V�U�X�B���y�q!�q���?��˗����{��'�-[�1���b�޽���ʔ)���B�^��c�&"##C�����{�z�/���7�|#�V�{_'L� 4�������q���?���űc���ի݃��'Oeeeb͚5�q����8�ӧO���l��]]�xɒ%�1���>�Lddd����ɓEii�X�f�������IN�|qr�RSSE^^�ȓ�L�=���AQ�&[.$IBHHz���F���� vf6��X,^�D�$ aaa����,��h꾛 fΜ��>�[�l�� `�Z���UUq�ĉ ]��955Z���1K����^�z!((���(++�Z���r�#)) ���(((�z�$I����ի���PQQ������f[�NQQQ���CQQ��/RS��W�^�j�(**Byyy��Shh(�Vk��EQ`6�/���?3I����$�={���P������^�j*��ĥ�둚����0�={��c|�m��M��"�o�S�����rS�NDDD�,�����ND�9x7��۸q#���js�E"�N�>SDDDD��}�������)"""�6`1EDDD�,�����ڀ�Q��""""jSDDDDm�b����� XL��)"""�6`1EDDD�,�����ڀ�Q��""""jSDDDDm�b����� XL��)"""�6`1EDDD�,�����ڀ�Q��""""jmg�� �Y�f! ����$I���شiE�ƍ����CQ����0�Mw�.Rjj������8ZmҤIX�p!f͚���T&?�vb2��n�:|��gX�r%jkk;;�v��Atyt��ј�S3g��SO=��C�2]fgΜ���?�^x6����i3������GS���3f �z�)\y�L�D,??����z�j8���՘?�:��� qS~���;�����1iҤ���[JNNƧ�~���~z����i��������|�e꥗^¢E��g�<�$�<B�^�7�tL&Sg�sQ�D����GK��e>�^�+V`֬Y�$�I�@^%�p�L-�,�Y�8Yҵ;��E�A����e ���Q}���\��M����㪫���ӧ;0�c� ���r�h �/��Q6��T���ַDZ�H�,]�:,Qg���W��r4r�{Blܸs��AeeeGxq�D��+����b��;���/��l"�9T|��$>�~
6�� u}#ңp�4$DAn��P�e˖��{��j����A���5���S�G��w�}����&a�ɂ�>��&x�d�`�U� ���~!�����k����'�"��o��R�l1�{�n�0�'�#��x��l6�u�������L�%%%4h���;!2O�D��_�ǥ�ɡ����fa���DH�I�}����g����=z`���0 ��9�D���G[�T���ݻ1l�0�Dhs�X��(,��Ȉ(Ƞ�S��@RL�W�ٌ���رc���/���q�|�ejƌ:th�����q&B�NVoU��ڣ�ٽ;m��n봳K�"�����=�L1�p��&��+km�jwQ'EED�.0a{N�gB�$ W_}5�Zm����A��|5��)��̙���e_���e"��|���A��W�^�2�8������|���4i��ý��*�)너��9��u8YR ��Τ�$aڴi~v��A�?|-��(�Ǝ�d���J�U��]�p4qg�ԩS;<2�_���'�����&��8��Nuu�OUy�Y@ll,d�c�
�����^|"길�&�VY:8"j��*3T���1����ȿ�R�h/>QL���69��d��@��Eʫ�h""99���,�?���/���Q49������QK��l��\�{�����A�|%��������� �E�1V���3�(���'l7f��a (8S��9eh��O
�����j ʪ��gq)�@g�>��1��VBZ����9T䞮f�@�����y ����\3& ��~_�;S�e_��@��s�l� �=0o\2ʪ�؟W������L����"&̀�G����aS|<�S����;�2N�Y#{B���,��+��sQgQ:7Hj3S>($@������p��v� 'Jj����+����y��ݫ;`��KZx�Ð���A~i]��w�TrNU�pa�M<b��D��p˴t� ��L�皤YL��`��-2{ઑ�8[c�֜RT��1�W�����!�3;����p�̯���1����c@J8*jlx�}8�(鼿�$2��ftD�k˒�N�F��Ӵ����*<��^�/EB4x���/v��ڊ���찈�0����z���l;\�n�^��w����a�������}���)�+.�B`���p���V#��`�� �"��A-���8ZT �ͻ Y#=c�ڒ IDAT��PVe�٦ @'c@J8 ZNjk�n+�ˈ �N�l�� @��E(��x$�`���C��Ů�ha*��^1H��PUoGu��כ�-9��ŵ8s�[�c���N+�tE�s��&�?!:� �H� BRL0
JkQX�y���ݹ���3�;S��C��E>�����GNar
�<��r����@�^��@�)?�b�njɈ�N##��G�����@-n���y�Q�\�*�bs>>ژ{�f��}"q��L|���& n���: $I��jk>�^��ᄎ�������eBPT�G�ڋ�U�
������Y�ܷ��Vo+��ߝ��ш�C�D�� 2��d%���������}�3�vW�T��˩}�o۶��������������h�F}DJj��C�;s�eP�H�y~&��U�*�I�id��,��k�P�(9�Yxc��D��������v����)"K���pH���yg[�(� �����=��+�×��PYkCߞF�dL~6>� ���I�/�$A�$L���@-����֜2$Fa��D�dl2rO�`�!�;�{Eg�1{d"��Z|����VX�
������(l<p;����ގ^�~R*���#���r�ܳ�\1����5�xgl'+��p��pըD�dL�Uc�2�m�NƟ�F�D#����ݧa�+���F$�O?�G�܃�?�6�쁈P=�V���j�4r��$�u���?z��F�Pb2�����|�)b��0k!I@aY]���5eʐ�%�{�{oj�0w-ǁ�J<�p0f�L����>����?��M��g%�m*~6>Yb�=�U�@� ����7��`��[�����ڰ�<�ʺs���M�% 7M��i�؞S���Y6wk{h�n��Ǜ��hHPf����b�7�<a`,�{�b[N��:�{��S��aL���U�q\#C��~���ˣ�4q9��_0x���d�`��xȲ�����w"R��Ġ�䤑�u̴��u��H�b KVm+�:�9�oB���5�H4z��PAVn=�����p(*b��>-UUo�H�.���
c����QE���g[ ܉��8 �"��霱ɒ�V��u��g�p�(�����pw�KI��|w���=��b���q��D���
3�����EŖ)"�g=zm˒F�A�h�6����z�jW�Kk�?) =��!K���jW���T�0ءN+_�h�Q�z�OG\x�: zFA�$�r�h*6�\���D� ��գzbBf��D�衑%�頑%��ŕf�rpG��?<�j��'s�R�
�յGa��wv%,�|�͡��a����P~Ѵ����ke(����X}C �kZ5ڬ$I�Z>Ƞ���1!3Yj�X�B#��c��:#�$ �q�p4qJ��8�gB ����K��#�GZ|(~{]?�4^Y{�
L-�K��Ŕ�+Njk�����X��֋�塨E � A�k��PSoo����V����4LȌþ��x��c8U��eH�H<p��Vl�%���Mλ��Ox�OW7���Yԕ1�&8tx�H� Ÿ��1P�7ן���x����b�)��p)U�r8�%�]ty�MAe�z�����םσ
 �[\�ngA�$�h085vE�[�CAy:��1�TT۠�%Ć��="��?Z�#�G��ܿ`�����|��Q�ї���)s����'+!K�4�R�=^�d ���w�B|D����e�0w\2ƒu�OʌCrl0N���ha�g\-�P�v��(��3.I��5�:ijeg�r;6џOQ������ �W���hJԕ1����Q�z�yA&zD��X���ïtA���c���kr��/�"1*��8 ���p��IB��0�u0��`s��-���X�������JP[�@ߞF�Ȉ����6�e��G�����[g��OB(ƒ�X����f>e�ā=�k`�S�)C��3��&C�y[���8��i��o� ?���ʂ�-�%�cx�H<�� v�h���20oB*:�&DB���D#~;�?T+��ڝ�^u$�Ks9���'�FRt CzG`@-������MwE�a1�J��x��ݘ���i�����`�ծ`}v >ޜ���] 5f���>�2=Yb0�γ��ŵx��\�x��qV���D�PT�6lU�ٗ��f�U[O!#1 }{1/+��5� �
�7�>�@���Fc�5�'�k������}���{��Z�r^luVO}�7L�)C�`b��ê�
�<Z�1��h؆҂3D�N�q�c��� 6,X������=��{v�C,P�b���!�6t��% =�{x �9h�2��oI���"//�S�8y�$RRR��֘���N��7H ��Ch����j������2zDB�$�W[Qc�7��!Ƞ�ͮ6y6���
4�4vIb� 2hQj���z.HB��� @u����aء�m5�%�@���@��f�M(M� m��}�й���]9/�5ɱ�^���ᨪj��Lڊ��i���?$x�;��9�?�J4|pl��a��*k��x��s���gP�8���lk��K��d�=>�P]�@u}��|K��B1\rlp^�8UV��2-ن�z;��a��������;J�;���)"""�6`1EDDD�,�����ڀ�Q��""""jSDDDDm�b����� XL��)"""�6`1EDDD�,�����ڀ�Q��""""jSDDDDm�����|��uE���P;a1EDԔF�hb^��D-Ԩx�$H���*��b���|B8K%!0eH� M@f�H�'�������s�+6�C,��SDD�5RBU0uh<~;7�E������ �V��NBQ���_ct""�F��P�dlrgGD]��c�!A���%���)"�Ƅ
��@��0�J�e���A���{G~��Q#BU���;;�T��l�b��_c1ED��t@U�ѩ�P� T��z��@��Љ�\�����6_Lm�{mE]���?��`�*
�F ��?vD�Kl�""jD�
*�}X��Bi(��"��XL�9Мܨ4*����W,���k�a�a���=c���XL��-S�A�
�5��""""jSDDDDm�b����� XL��)"""�6`1EDDD�,�����ڀ��5]D�3!5z�]S�.SDD݀��#|�p�͜�S�"()��Cj7 3gc�#�˜��{^ߌN��� mg@DD��$!~�l���!I�s��9���_����n?�ol���]�MH� ���<�˅�Q��`!R�/����__��Hz=�F�D�O�E��S���[�������<����qd�@U/�v�:�)"�.*$�/��΃���?KI�����Q��W�\�Vg�|���� b1EDԁb'OA�ĉ�}���q�d�ϘM@*v����A1��x�$̚휿c;�����j@�/n�q�}i),���N�� 0�틜%/�n�D����Z|�1,gJ�b��L�7��&4�s~��,"�ਭ�ٽ{��ч�6z앓����+�������3Qu��/_s�)g<��ѣ�8[�F���?�nDZ��P�{Խ��˗#y�\D��U��г�@�X��\7�OT�3���xJ�q)��0�,X��1c�3��R\����@�7_�s�&]��I�p��בx�u�{�ơ矅Z_Iۥ���Q
�O@��A�|�a��pv�&%!v�$�#"�}�z�97������������1Y�p꓏��Ն�#~�tX�ʠXֿ̐?T� �?^��I�!y �=Q��[� 09=����añ�/��$�>��bcQ�stF#"�C��`���Qe�����*H��f��d�j�C؝%\`\<�db�������?I��$��EFb�#�"(1 ���Q�u�3���9t�?��O���뢢0�Ga�큒u��ZV���Ñ��;�yo� �(�O@x�����?:�:q�W{[�܍��%��~� l8 ��8,���:�$I�4�Z ���a))�&(Þ|��RR�/a�G��!0DE�z�g��RW���q(Z����]��+W@�X����.,�� ��tѸR\����8��W��4 �W���H��N�,�9K� 8��A�Þ?���B@��q����r2��2pv��^��{va�s/�l�^�,](���ja��¾�DM�Q� B��/oFP�D��8��W����N$/X�#/��.�Z"�������4������k0�� ~�t�|��Bϸy��~щ�W\zŅ�Tg×�.��C#u0 �����݇I�����������{�Z_���?B�롏X��Q��~%&��@��5�ݎ�]���42d���
q�"@����`-+Eٖ�ECٖͰ��#l�@肃���$�^����UE��]���o���$�|�-��E�� �S��� iq?,Mp0"� ��t����)vTl�
�`@pR�G\y��KU���jlt�h��Z�a�QB@��<�9���Η$ ��q�g6|��1c�5��r���D؀��>|��R�r�
d���.4��0T<�������a��@p��Є����wK���b�@Y�o��PU�O�F�kR�x��b�6OH�>І��^u�V7�CY��}B���Pg ���@r�8���ӧ���r�k�VґXL�:�xI ����Qc�"���1h0��!8���e/�j�����"#Q_S���5ZH��4=l�P�sc6]���b�]L{��N $I��ʄ�ݻ :���v*�����:�)""?㨭E���H��'�臘�ਫ�����e��z���"z�D�����f �\�f�."�j�w�Α�uaaP,(��d��Ox8��x��8Gmm�שZ-P��*M8��(>rW�U|B�>�VI�[=����p���Ἤ׉�HD�J7o�$��EX���Ά����B8;n+$�tB3�y�#�_D�Gm-�
�����^˄����T:{]]��T
����%�^]�|<����ky1娩E]a!��гU�@t1l�""�Cu��=yaB�� ����CQ��'H�7C�ʷmE��c�F��!C>0�����];Q�r�����y�����#��
ܫ��͇�ۑ��G��s�E����dB��L�M��p�t�,ŧ�}���q�!���3�?���S�x~�3��@�'{�ٺᰣp�
���0������=q�^��~�a��G_Z�Y���)"�$BU�6�fC�w�ާ���v +౐@��� �G���?`��B�G�p�J�x۷���%�s˭�sۯܭH5�G�����.�d�b<�;jk���H�s��PU����`))>o=�� +vl?ϭ����X.���?�=y��45����y�y�����u�����p����9�3Ir����5GJMMyyy��ɓ'�����<����]� w�Frl0���n���QՁg��?��*T��vK-ֽxs��n�{� ���C5& �ݽv��Æ#�pz�c���{'I�;�S��α��Z^�����&(vS�5M��jn��V��{$��ѰWUy�ujn=�O��$��á 5B����l�ױ�h\�4����1��_�>S�*��{}v�N_�m��-SDD���
�f�K�N�@ٖM��Pjk`�X'r!`�(*.�Xs�p�}3y"yт� �4�n!`������U�#j;��!ClD ���S�+h�cU��}�e����#"Ps,%߮�b6wv8D��)""?T�s?>�(�$���GD�XH�SDDDDm�b����� XL��)"""�6`1EDDD�,�����ڀ�Qp�N"�V�������̶����Q+IMg�@D>��2Q��""j�$���|` ].6���C�v�b���1I$ $l�{����.l��|��%��C�6b1ED���Q�
��~�_l:��)jw;�a���P�],��;�5�,�dH�v���__�'���������J�̢jh�4�4:4�`�B ɮXP�+SDD.�@�$ɐ5Zh�zU���� �r��b!E�!I�H��FIk���C���$�� E����,��$ ������4�����!�
!D�B�����ݒ!kt��zht�ZdY����}���Q $�5��:���JUu8/��\1%XLQ I Ŕ�p Y��E�F�l��d^��c,����$H� ZHZ ����*B\-S/�Q�H�on�!�H��2�,�E�ϱ�""r�$HB@H2$�ْ��5 �TC�sQ���)׍��ox���)"��
*g��]V�ĹV)�6�ntpuJo�ىQ[��"":�뒌h<��;שݰ��ZXL5�: �e>jO]�)"����!u� ��izŅ�@� �z�:[��3n@,�*z��׿>�/w]�h�'�FDD��n����q!�$ �zE���F@�i�����X�Ӂ ������i�H4^���SDDD>lPjĹ��F�'c�Z�~�F�m3�!7t���u �u�"�~XL���gj=�-X81������TD��=.QK��1���������;T����: n��~��Ƅ��1I��0؞S�y��kw�b���ȇ�,��W�u�L��=/�����i0�<�mow�CjG,����|��N�Tk�(�$I�]We4���}"1��W��W��PXVw�b�XL��:��n����;>3G�����ʸqJw�s��Z�^�V���b������~
'Kj<[���w���a��5.�;��jW.o���)"""? ,����|��x��!�?YR�o��\��1SDDD~�@^%��]�e�}~��LXL��W��*�b��+Ɖ��Sw�b���ȏT�ښ�ޜ:����/3SDDD~����^C%4���p��z�c��XL��C�+k�\t��%���?����"""�C�G�\�u���8BG`1EDD䧖}���k�sʰ'���龴����m��ˤ�G��.����s������5c�<Ɣ�9T,�:��B�湈�TS}�D��{"��4JX�����扬Kc>���d� ����;|��g*�.c��\���� �LMB`ʐ8L���^�^��u��yg���Y|�9�`"벘�����y�S/�v���XL5֐���`��x�vn&������� �N�{ߟ��:)A]���"'v@wi�����'c�;;"���jt2d�Bu�`P�|D~���"S� *TŁ��a< $�����!T���������Hw�E,�B@�*T��١���8�g���L��c>"ӝs�)�\'O��@(�N ��5��PU����ǘ��Ou�\��.B�y�WU�O^�^ہA�3��� 𚯪Y @8��ݰ�g��|D>���[���v��俜g�ݳi�+c>"ӝs�)7��L`��@�L4J^��v �G䏺o.b1�X×@t�/�7w��n��|D~�;�"S�� �~g�,�#�+����b����� XL��)"""�6`1EDDD�,�����ڀ�Q��""""jSDDDDm�b��1}� qq�bIBh� fB|�ŵF#� BH��������uE����IC"�UT�Z^��R��Y�1�'��RRr��[*b�pd�w?$���Oc��C��nrYMH(���)�L��ڰ���P��wI�%"�|D� [�����8 y�q���@�<^�{�m��o�ݱ���kr���u:H� {M 1dH��F����88�kY��eO�U1Qw�b���$ �,C�$�dT����u_�^S㹼����&�o�
�jE��i��z�u:�O�KY)� ��%��������Dk C���#z��B����5(��k@U��� v�D��oČ������ E��C8�|̅�)��E|8�/IDAT�c�Z-�ƌ���D�v;�-{ ��r{�d$̘��������<�?��rD� c��8��RX��=bN�� 0�틜��^y�=�Rz��>h0{�D�ɓ� ��!���p�
���������B�Y���G#��Qs�{��+'#v�D{�Dg�w�U9�p|�r�Ox�s�l�d�;�Σ9��=T7Z'�L��ī�A`bT�6S%�P-V���U�7�Wk C����{t�0�g������p�8�J�N��o���k�E�Y�:|��j}}��'D����#�l����( {�)�M���͛���۰U��v�"����3���x���F�����!T�A��aȼ�h�aGM-�UU�� 6� 6� �nw�'>!i�ІI������U���2��돘�q1k��7m�AAP,f��T�g� Y�A� ���,�N�[7�sc�w܉�͇��4N}�1J7������y�C��w/���x�CH���Gr��c�Pd��~��#�˦�~��/�\g��x�CHH8ی����o�Xm���ݻ�)��KY)T���� ���?mʷms~f�J��������q�0���GĎ����HZ-$�j䛘�<1ѥ`�T'H����X|�o�ܗ (Z��>����P��XJ��M� d�{�o1�EE�,#�_#���0����;P��g8�{'F��E�ݻ9K�x$ g�s�(Z�
g�����x-飼�R[���q(Z��ٙ��fBjD�g+�Z,�;$������!&+ �>[GU@��#Q�/���{��>�8��33�Mn@ ��*"�X��%Ԃh��J���m�X���V]���n׭�u{�>>�m�ֺ]�K��.����"�$ ���&s9g��ɐ0Hr�̙����pf����y����3muu�m'�5��>Z��N�<X���F��NE3f��H;�o�y�Z��%��Y7S#b���͛���Ҿ�>�u��՚p�u*�>C�C�ddei����N��G��Ƃ��S T����d˯�唎Ў�con�������y�]���:�~��VG���*{�0�s߽jڽ+���<o� ȣ��#��4�<~���s��j�ոkg|���k�ʓ�+�ر�冤=�~$\�dY:�m� I�#���ڏ����)o�X�-� �P邋e��:�m[� 1�Ҭ�W^V���=;��t��������ʊ홞�e��.!]�_�e)kȐ.{������Z�55���c۶J������M�Ϊ*ɲ�[�';[��|���*�ȶ�փ52�^y �%u�gs���A5�� ���pHG_�,3;[��N�ah��>\�Ep��ȣD���������+.R�С:��d�'��|�E2 C����2۶e�]�ik�m�2�\�m��ō*��J\��w�7t�
gL׉v(p����տ�Ic���FU,��7^�a���)p�N|���q��~��O�(�߯�!C��ц ���8�����uN� O~~l���:%E��W^y����
9"�|*�s��pH��ެ'�/_Q�̬l�����3�G^�?��e��� -�y�y�ޢL���n<�����S���BA5Ħڻc�6��(����HN|���ְ �ꩵ2�l������R���d�ԉ�;U8m�rG�VN�p喍��'W���ۍy�K5��7�
���{�)X_/Y���ztfO����:'��u١`�봃A۶U�+��y?��?ܭ��2喍V���j��u��l�Vٱ�;;X�����a��C%"��������
oЁ����ޞ�!%77���U��rM���Z��5���i7P;֡�/�h�L�Z�H�ee���u�׻}���H�����;�z��Ǣg�͜�!�����;�<rX��w��G�vZ��k�x��4b��u���j��U��jڵK{����q�߳�g�R��`0@�G]�G�+�T�����RS�� �[6Z-�>��Z�lێ��B���t��W^��˖j̲�ʟ8IǶn�O3���w�V��A�/�a�:�ҋ
����^�_^�_ {�t9� {��>_o��:�YR��sTVq�|�
�����niN��pS�ZT����-��=�i\�ېG]�G�+�T��ᐪ�~J3�K���/�Z�5��'3;[E�g�p�4���*ܜ|C�N��E���:[�]*;Q����=ԧ���R�}*�13z��K/&L''>qBG�جQ�/�a۪ݸ^v$���C'N(x옊g���Z��հ .Ը�������5�n�M�հ��k��^��Jǁ�Z�m�XX���� m[���U��jke�C���3�q��y�]:��5��+3+KEӦ�p�4���)��Ч��BuE��(Sipl�V�|�AM���5��o��M:��b��aD7zۖmu��;� �<:]nn����5e�74y�M�e���ߧ@]m������]� /;T�� �2y�ڏ��y��8N ���J����\�_�{�v�R�"a�V�،HK�v?�KM��w4��n�!)�Р�{L�W|�˘{�z�\�[������|�1���˲:o2sr:qB�zRv((3;G�&��ӗ(�D�}�winֱ7�i��҄k�������Un�l?�{�yD�9c�����4���}�4nܸ�K�/���� ��eۖ�pH�`�B�f���k����/}�����!_lj7�ڪ�cG."g��$^G�cy{{�w�Fv�rJJjl�7��z�����л���ϯ���>��wݎ×%Y�Ľ@Ð���>� ��KG�0 ������e�����W���9�b�����v���:��+'k����h�y�����Z��wYg_�3�.��yrr�/�����\y�rez}'�8����� T^�y�����X�=�
���=?�yD�<��#�ܒNu�p��T:ٶBǏ+t�x�w�n#�n���~�0�/��ȅ�m��/' �Ӯ7L�\��\���u�g\G�^�3�3�xH��y�~��H �x܂�� p5��r��A�BR٥#4�9j=X����� tl����
M��my�
�������g�����_??�@��G��Q��T֐!jڻG��+��v�d�������4ja�
Ϛ*�� ��T�b�j+7����k�.@�GnG�BRM;?�{߿o�o��ÇU�fu� �y��<��{ �L�{�e,��d�e;,�s�ᇎ�L8@�p�2�e
���\��.y�t��ɾ�"��dQ�T/O����#�-��P��1 �mס��C�t�4�`�ge�3Ð C� mzko�G�ѫ�Vɲ��b`!��A{Q��#`����{�}��Z[ޯ��W��p8�)�!60�G�d�w .S��Q(h�?V�U���s����-+z�؏P��R�Pl��4ez|�f�ʓ�'_N� ���nE%�Lu0 I� Ô����͒mEd۶LÔmE$;Y�=�>&pÐ!�0=2=>�,��,��W�a�0�h0�#�Y��2%E�˶%Ðizd{|��rb7ydEB�mK�m��Ş RΈ}F�{��7K_�L�O��c3����G��2cH�aJ�G��'Ɏ�fɲ±iu�iu�M|j=�Տ��E���az���=H� �nF%�Lu����2�� �+ӊȶ-�cOP�7�����dS����F��MsP�
�܊,J@��`2l[�a�0���czb�eG��-�A�a����݆�<B& ��(S��,�]o�ö%�'�0b(w[���ߑG�dQe�Tӗa���oH@2�9� ��,�Lu��!1�wā5h�Gp#�(�2�|p�y��໲@?�L8@�p�2�e
����)(SP��L8@�p�2�e
����)(SP��L8@�p�2�e
����)(SP��L8@�p�2�e
����)(SP��L8@�p�2�e
����)(SP��L8@�p�2�e
����)(SP��L8@�p�2�e
����)(SP��L8@�p�2�e
����)(SP��L8@�p�2�e
����.Syٞt@7�#�C8-�p/��Go��L��ˋ�R<=U�ϒ��2�[򣿸�L���%]^������<�LÐat����zٶ�ұ�@fqS~�W�������K�rR<=Q�ϒ�d����^�e�t,��Yܔ��e�СCI�O]��艱��e& ú����Y�@fqS~�W��ݻw']~�ġ) ���?�D�$i�}�vE"�����2��򣿸�L=��s
 �t�\M.+HӨ$�5���e& Í7*�t<��9ܖ��e�ȑ#ڲeK�r�4��±i��\�*��%=xtӦM)C��nˏ��2e۶�{�}jz��K�)�d
�켱�z�ĩ��T[[[��D~�����_\Q�$i���I��S7_6M�v�/ ]1����{����#�( �aT�� ܚ��5e���F�V�Jz�Yc
�w�R<"�]2k��7F>�����_��o���Q�p77�GpM��m[w�}w�S#=��%�ї��it��6��HWWL�?ۓt���?��Z[[�0�(�p/��GpM��������?Lz[���W>3A�p�T���d�}�K34� +i�]�V�7oN�^%��O��S���������{q���z�'t�W&}�CaK۫��u����=X p��,SW^<N��Q~�W���7�|S˗/Wuuu:�����!�/:f�]W�$i�СZ�n��?�����l���^�V��O�-�4������1Z|�h�e+˛|j���Z�_~��o�� ?������-W�)I�4i�֯_����o���lE��GǴm�1�9tB�[R<R ��y5uL��N�s& �Ђle�<2��7)I���Z�b�6l����@� ��� ח)�04w�\=��:묳� DI
G,�#�"�-+��>>ڦƖ�T �HF(�g�4 y<���)o옢��z]}�ժ��t���������/S�d��������k�ҥ� �SY��@r���w���__��״c��B��z��>Y9?z*^��M�f�ܹ3���a������u뭷*''�W���]�V��v�<�1�8��;db~�DG�2KKK�<�ӳm[��������9s�hժU ב��y��t饗�nPMMMF!��W&�Ǚ�����6����w��]��s�a(77W�f��M7ݤ����`
�oUYY��\�ׯWSSS�_��Rb �G2ӧO׎;$Iޑ#G�y8=g۶Z[[�u�Vm߾]>�O�g��ҥK�`����&�^���ց�g�=���z�2�l���� ��L癩�*S,ˊ_z��W_Ֆ-[��E<���yt@�,K�e)�(
��C�!?��5���Ç����7.�Cq.�(�(�{(2 ���Ə��\�h�rrr�7� s�E��6 �dɒ4 s���i�������x��  �t������e˖�U@TTT�����mJRii�.\��Ad���]t�E��͍/3����x�f�N��oԘ1c�\����cƌ���k�20��:u����zwY/S�i�;�`v
��+WjԨQ ��`v�����r�ʔ ���͛��˗+???�6�>�'ԛ���l�2mذ!ep���2�]�V\p��^o��� ����裏jʔ)) �[�����Ν��HIIʔ$���k͚5***�������@�=�<i�2 C�g��c�=F���=�ܣ�~��]�v�L�2%E���˴n�:M�2�B���=�����[4lذ3�?��SE"UWW�ꫯ�+���3� c���顇Ғ%KTXXأ�t;3����hܸqz��g�r�Jf���4o�<=��SZ�lY���ԃ��Κ���e��{��R����L��~�V�X��#G������*S����Ԥ?��Ϻ����}�vJ�8%%%���t��7kԨQ�����7p�.S�������i�&=���Z�n����)V��JJJ�`�-\�P�/��ѣ������2�!
)���]�v��ƍUYY�@ �'N0sҢ��D'N����ܹs���~V���WAA�����<u*�e
`0;��|����ʦm'�C IEND�B`�
�PNG

IHDRR~IY��sBIT|d� pHYs���+ IDATx���y|T��?�Ͻ�d�BHB����ddp�BU����S+.�-��تն�Qk��H���
u7qG�7 �l !;�$�d�{��?&2LI��L�y�^��d����0g>s��("" """�S�]Q�2^��<x@^^D�w��b;�����+ 2 ���@NNƎ���� ��B��۵k�/_��K���� MDDDp���0{�l\���ꪫ~^�;� e����K/a�…(,,dx"""����n� �<���� U����N���������R("""
Z��Ѹ��;��_����
TRk׮�w��("""�V������w�u����������{�����ۺ��׿�iiiP��mw�Z�`����1DQ�7n�8,Y�999g=�w� e�X����}�C�iiix��1n�8���u� u��W���?��0HQ��(
��Ұl�2�9�՞��K_�`��'�!����zAQQ��.�z�6��… =c������'����׿�5***|��j������_������z<��ᅬ�555^�#e��ѯ_?���ti�DDDD�,44_�5ƌ�/��#��K/����ˋ#"""
dv�O<��)>�)�F�MQ�X��f͂�d��boQ�D�-BUU�3z�RSS�EDDDt����>ôi�N�H�]���QDDDD� "X�j�V�� �<{9�ݺu����p��^���QPP�ﺈ�����(ظq��Gj˖-mN}NDDDD�D�֭s���<��#"""ꀼ�<w�� s"""�������;��Z���lƈ#������F|��w<~}���O~�8p˖-������f >��lطo
�Eo{FFn��v���c����l�.��� �""S�Nܸqk�EFF��~�;�����%��y���<�9s�����:m��������ÇKjj�E?^DD�<��RYY��>�ڵK���j1�~]�g�կ~%���r���۷����ƍ�{KOO#�S{Dg���Ǜo���ӧC�u,_�;w��lƔ)S0q�D���k;v,{tϰa�lܸ۷oG]]������X�cƌ�UW]��[��woQ\\^{�5\y��+V��o���d��ɓ1a�,Y��_~9�����X��˗cܸq���k�y�f����mڴ 6l��]�|V�'"�)**DD�����TǍ[�l��ʋ/�(v�]�;&cƌ�� DQQEƏ/o��F������:��-,,L֭['uuu2iҤ���SUU-Z$���r��q���<=O��;v���꫒���S�������믿���Z�:u���υ~M�q�����[�! �P.���|��������o���iNV6oތ-[����INNƥ�^���8���c۶m�X,>�3�L���FQQjkk�I�&�h4bӦM^=Žz��e�]MӰ~�zTWW{��l6#++ 'N�@]]���1a������þ}���9ONN��ѣ֚�eeea���P�w�F~~�g��DUU���QQQ���@XXTUEzz:���a��QTT������t�=������G^^�N��}� �y��AQ���ضm�g?͵lݺ��~{��ӨQ����
l߾��um~����p��I��� 22&L@tt4���p����7?���p ���!;;6������b����ӧ�m�6��k0������j���u��3���a��ш��@~~>v���3���%%%�X,<x0� �`������F�m��dff�=�q�(�c�=&6�M֭['����~\BB���?����5N�f�ɓO>)^��9s�����3�<#?��Ͻ�b544�]w�%����V���<�������ʫGg�̙b�X�w����}��RZZ�5^hٲeҫW�Vk^�x�466����SOIdd���ccc孷��y�K�,���( W^y�TWW�ʕ+%::ZTU�%K�Hcc��.��{g��e֬Y����$y��7}���˓1c�x=�GyD���eÆ ���ԡ������444�<租~Z�����?c� ��������r��������<�QE^~�eihhh��6���ӧ�����R__�/��%�?��Ͽ�3fHEE�|��'�u[s]%%%^�Z�p�����<���Dy��W����g<����^��ӧKYY�,\�P�x� �X,�r����P������*7n�1Hq�vz3���_���?��b6�����������tJ^^��{�r������G���M��������z3k�,������rq:��b�
�?�����b�ۥ��N֬Y#6�M^y��?�|��g�p8�СC���浯��Z)..��)�W������C=$eee�i����K^a.::ZV�^-�Cv��%��w�\�����{j��_�"aaa��������y�wd�ĉr饗ʣ�>*o���� �9 ~�駞/�ɓ'�o�[)**��)/���<�裲`�IIIEQ$22R���Kq8���ʌ3d������J}}����KVV��}����n�˓O>)����z����=�صk����?�믿^���?HUU�h�&�>����t�WʩS�<�ӪU����g�yF�����t���.&�IȤI��G�'N���ŋ�c�=& ,���TQE��>�����_]~���W\!���/���T�N��v�m��5�PUU%���$$$x��\�W_}%���<��3R[[+N�S~�x�����O?�T�v�����2s�L?~���/���:9|�� 4�s
�9���ᐍ7�… �^���d�^�q ��A���[tt��ܹS\.���G?j�ؖ��Od˖-һwo�튢Ȍ3���F,� 6��� �i�<��c�0.�V���!v�]�����e/�w�����+��4M�'�x«'iƌR]]-��Ւ�������{���^�n�*}���y���R]]-�E�.��Hxx�lذA,��1«��؝� ��g�y����������j���ɓ}^�;�Cjkk��ޓ��8��F�Q^x�ill�������,QQQ�u�VO�io��?����ʶmۼ�M)�"ӦM���J�X,2j�(�ߚ�T�k���(��Wlٲe>�u�ڵRWW'ӦM�j0))IRRR|Ɖ���RWW'�����8�5TUU�_|��4M�'�|ҫW����*˖-�z-o��v����>����h4���?/������zs��4M�x� IJJ�X-n���<�`4EQP__߮ǘL&̙3&� �?��{^�&�Kl۶ ���7n�F���ׯ_�E������ЀU�VA�u����x뭷<cW, �o��=�EU�?�7nij�> ���mӦM8x� """0x�`���U�E�<c��k^�~=�o��U��ihhh@XX�L���<�w���h� 7��шW^y��j?�˅�?�v��_~9BCCa4a6��(
�u|�Ʉ뮻!!!x�PZZ�y��`Æ ؾ};���0v�X�L&��oܸ .��&"X�z5�������v?ߊ�
�����1:x� }��������ZO]k֬��h4b�ܹ0�Lx�׼��s�\���O��؈ &�<��G����Gee%D��j�Zh�'����u�3�<<<�]����Bzz:�v;8����p8�g�L�4 9990 ^�|[�:u
�������KKDPSSAhh(E�z\}}�ϾQXX�Q�F!##��������V��fâE�0f�<�쳘;w.-Z��+W�n���jKdd$���a4q���n�zީ�� C||<L&4M�������48�6��޽{1y�d 8F��k�uk�Smm-t]GHH�O�m���TL�0YYY���@vv6���`0|�۶466��USSMӼꊌ�DZZ�f3�ϟ�믿��5���@BB�f���
q��)(�V0H�����������ef2�
������e#"����� ""��_�mi�G��Ț{qL&BBB�iZ�!���W�X��s����DŽ 0i�$���êU�|�I{5����aÆ!;;��>Ǐ�7�|����� ����0 >W��v���P�s��S���#�GLL ���?��[oEhh(D�F������əu)�����m���ŀ|WTT��k�zzG���xj���Áo����c�ԩ���8�c\.��K��^���@UU�_.���ϔ.� N�����暛O�4[�f &O���c����CZZ�x� 2��_����f��[n��A����� 8�=�����p8�s�N�\.L�2����:���8�s�����(~�:|E��?�[o�6l��1c���\u�U�N��Y-��u���z�<xp���>�uj��ΎA������a��1~�xL�8�l�V+JKK���\�����c���P;v��t�M{������������!"8r�4M��jEII�Yk5jTU���Dyyy�����'� **
�G���`hW�g�j���ɓ0��۷���m�[�b1n�8L�8��n�> :�g ҹ�sg�����0u�Th������صk\.�E{���7�Ɗ���5&��a�":æM��z�j(��ŋ��+����WU7�p�n݊!C���t��?��iX�`RSS��w��7#77���زe�E Rcƌ�O<���h�m���Cff&����o�>O��G}�˅_���ӧ��~�͛�aÆyjv�\0������z-Z��lll<k����DCCL&����u_�Ӊ+V@�4���?G�^�|o6���ϖ-[�z�j����/̞=�+L����s�bӦM>|8\.V�\ �Á_��HKK����7ވK.�ǎ�<��r:�hll��dBjj��sm�ߊ�x=�ٌ9s�th�zGk�裏�p8p����;m����܉ȍ��3�l6<��X�|9� �O>���}�`00~�x$%%����3��?��n��f�96l�ҥKQYY��c��ꫯ��׿��:�b���?ń ���#-- s��EHH�~�i���yz^y�̛7�G�ƺu���;��^z)����C=�a=-- �֭áC��b�
TVVb„ �3gJJJ�}�����Ӊm۶aҤIxꩧ0b�������;�����ob޼y�8q"֮]�7�|�������e�]�Y�f�?�)�/_� p ,@FFF��+V����طoTU�رcѫW/TTT�n�C�u���k�馛0f��]���.���1z�h\s�5P�<�JJJΫg��s}�'0|�p�����_Ğ={�q�Fdee���^z�%8�z�7n��Ղ�ҥKq�M7a����ꫯ��[o��ѣ�������1k�,̟?|��9ǜQ�#ō[�[||�<�䓞 -�g��Z����/�������ݻ����^�~�.;v쐙3g�̛4c� ����+Vx���Tjhh�g�y�kO�?�Il6��s�=�I����/<�\7���Z��^ �y��{��W^y�k&q]���o���qp���s�y�ƭ�lݺUƍ�i���b�X䣏>�Y�w����W_���]ץ��N.��2�c����Ϭ�v�]�-[&YYY>s�����?�ٻ���d�<x��|M)))�x�b���u]��;wzfo��iӦIUU��\��kN&���#����s�N��Ú���_��n�<�I�&��`���dy�7�^���<��[���òr�J��d�ԩRQQ!��g��nkY�ɓ'%//�k����x�…�9�Z��~�����x^��S�Jyy�|��ǒ�����$7n��)M����D��4L�^�������:CӴV{,EAdd$����������\�����f�Y�LQ��Ġ����T��`@TT��5�5k�}�]lܸ��̓�nGVVt]�ѣG�:=As͙��0�g�YQ����_�~GQQ***|����j�Gzz:bccq��q�5�E��lF�~����*?~N���^���SBB���Q\\�{���#""Я_?�F������)**
v���� M����x����=S HOOǩS�PTTM����s��j8���f3233�S�N����D0Hug��������`s"""�Nb�"�Fx�:Q��U{D���u�p�5נ����)u!��""""�$��#"""�$)"""�Nb�""""�$)"""�Nb�""""�$)"""�Nb�""""�$)"""�Nb�""""�$)"""�Nb�""""�$)"""�Nb�""""�$)"""�Nb�""""�$)"""�Nb�""""�$)"""�Nb�""""�$)"""�Nb�""""�$)"""�N2��� e���={6BCC������(��ﲈ�����i֭[���������.��������C�ׯ
�]K�M�27�|3fϞ���L6|D��b��U���b���Z��.�c�Atq����� R�f��SO=�#F��#�������s��o����9ol?��Nwk?ZTAjܸqxꩧp�W�$�bǎ�/�K�\�.����t�"� ���l�f���~�3�^�S�L�w)D=RFF>��<���0���.�C�~�W0��=R/���ϟ���_�D�#"X�r%n��6X,�sNl?�G����A�l6cٲe�={6E9g���{�YPPfE�ͅz���{���1 �WTU����%�c��D�� g���v�ލ���'O��Šۏ���՝ۏ�� ��d[oJ�Ձ׾:�-+Po�^�]��etv�^��3b`P[��֭[�9s栺���+<7�D��ڏ�� ���� /��b���åc��|��.�u��pnj,�&�Cm�s("X�x1��>��v?T�:�D���GGd�;v,֬Y����V�r� O�����D] <Ā�W�`d �ק���^����p:�~�����l�Ggd�ڱc�g��3ƒE�x��<v�u����+G������bذa����Ce��~�`i?:#�?����l�-66�D~���|�9M����� ,@HH�*;��Q`
�����Gjǎ9r�O#�p�X�(�l�SeDb�Sw�FzR�Ϙ���F\r�%8|����c�A���謀ꑚ9s&F����^��A"?k�kx�Cp8}h�����;��ۯJ�D�-�ۏ�PA��on�K�����;��T����[T��y7�����k���h�K]l?�_���#��Ԝ9sZ�}����D�(�|�����grذa�ׯ�_fg�A��8��L����X��.[V��""j˱�z�Z��1pTQ̘1��U��
��~��� R�Ǐo�[~oa5M���Up�r���ӻ�!d�A\��8_�rrrZ�}����W�������%$''CU��ia�A\��8_SmJJJ����غ�"j���F����0]=Ɓ�Qp ���|L����l��rKc�BD�RYcG+� 222��%���H���
�jCCC[������J���,�����_�l?��O���+`Ft���q9���{G!1:v��ceVT��J�-%DŽ`��T/�bӁ
�r�< ��T�K�Be� 5��� �K��w����ml?�٨ �w4�cC�p��?Y���o?�W�)�jR���}q�t��Tϔ���̊�_�co�ſE��I��p�� T�ر��u����wiv~:{ �bB��`%���;8�o���a�8��*n���/�����X��K��G�M�o��i R*2Ԁ_�4 C��B`��
-��lT1�_�E�o��/���.<}aT�?�x$2S"��oq�������D ������[Y6 ��E��٘84����f�����#�L�텫/Mé:6(GM����aD�xL���.���\�A�����+�1�o,��x�](h�༽�9iѸvl:����UEA�I�AQ`2�����k��;>�D����D�0|��U�v�hZ�E��G�9^ހ�t���{z�Wl>�����̑�1)�Vl>��:�� F R�_J& M��h�~�Fp�}(�Ł��Z}|L��}�bDM���k����66(@��pT����ƻ�� IDAT�jR1�o,B�*��X}.3�H� ����N� E��MT�ؼ�����B|�6��CE5��w�ԠHK GM�� ���jm�1�8ZbE�9.kO����Q0U��jpϢ���OM Ge�1ғ‘����VUz_�%P�#�
��)Ca�S����ۏ�k?��@Q��m���c��^3fb�
R Rh\N2L�jq���D����ݧ�Z �u�e���u�p��:�d@<�)m-B�ņ�f @��EQ Vl:��WE����\3��>������.��k;���$D���Yٸ4' ��x. ���|��)���L�#��7�r���yo/.w}��ǯo��'ۋQV݈O�ps��6���z=��%p��9����bLH�ϯ؇²�_*����77����p��O�ɠ��bÃ/oGM������+����� ����~��p���,X1HU�����(�]x���[��U<�K0�O4
�����bT[�'���/� U�\S๲EQ���#RfĮ���t�i��jL�7>�'�a�{��/v�D�\ui�Ì�rg *k�;5�lL� ���no��D]��zG�S2q��4,������>k��̱FͷO��][A56�@jb8����K���Zl�W��%jR��M�`PZ46��g;N���pyn/���o��^��M����q��^��2�`Q-���ɠ���&Q�c�\�G�^0(
J-��6�?xQ`a�
0!&�F(
PTQ��e��6<Y���?i���� uM�m�*��X5��\uiV���)�n�0#�~S����}���q��}1aH2���K�-� ��c&"��U;K���k_kw�bݞ2Tן��{�UQp۴���-*p�ʶ._�
3�u����cp55N�v 7����T������*�h�~������10mx
� J�'ۋ�^��(3��]�}v�VNa ����1`�%���
��[�z{`^qH�0r��A==����5 Ǡ� I��(X����/�}�,�?Y�0�9i�>��w��7��Z@2�h\���h�����ipz5��NT�CAt����YC�������{A�u����k3�kS��Y
V�x������낡}c=]��J�mxc��(
zl?Ψ-�ۏkǦ�Ob8NV5b��2h�> ��=RF�_;fc����C�pi(�l�i<���X���c�'1�����N�gͣ��� MF�S��&D�18#)��0� �UQ���.��ښ���-�l@bLT�fLL������H3 ���p ��56���VN�H��o��~��9�B������s'����å��41[��(�<g�a4�0Uh�x �l����3:4���(�x�w��Ƥ�T�i��z��oY[�/qEQ��W+�Cy��Z��a#DA��G�j���#�w�~L/}r��[�}
��T�qj�#%u�J��%�qX��8�縚C�.M��ljk�� P����U�������+�0)7�
����q��}�����x��:p��w�6]�W9]:�~g/���m�y�����GG�C���I�x𦡈3���G�vO�O���
@���C��3b1(=���94T�;a6����w��NQ�%u��ϙ?#C �$3NM�k_���z�&�4:4T�:`P$džx�{�F�ݱ�踮h?zŅ�yÐ����'[���nQ�b�
@��[�����`��s1,3���
� C���]c�;..M�y
�N�@l����SrS�����l8T��/��r��S��� !:Ļ.E��� -dUw���?�� 6(\7>Qᾝ�F�=���;c��q��H�2�7�r�+. �o8�e�s��n����S�����G -! �u$NT��De= ��A�1��0�bu���/w���dd&G�/�5��������>��������D���k���;ffa@jb#�X��8�*�������ϯ�O��L���>Q�!ܗNO�M��>����b�RT��jĠ�X���}�m��:�o�
�0)�M�^S�à�@NZ4�3���k�ɶ"�I���ۏι���-S�#=1�����0����]������^W?Rp`�
P�5v<���aB_�����pd$G�N ��J�ކBTչ���kt���څ�\�� C�0精ܿ>��X��W��S`��5���Fԥ�>�ֺ.q��8�+Ŧ�I���>ѸaB_؜>�R]�|qa&� L��k
J�����Ϯ팑�m�Оڴ3j��kxj�.�h�L��y�3=�Su]��P�����t �� CLL����p��1fL� H�4�˝'��8��ۏ�i?Ʀ��d��N!��Q��ӰED�_�~(,,�k!�۷��Us_�����&D��`s訬�{>ĭ�?Ԭ�W\TEAe�u��6�5���p��
3������(@RL�C�(���`?��WD����*kmq�����Xm����
R��f6��хJ� Z+��َ��s>�obz��7�{,2�#|z bccQS���I�ۏֱ���C�3��8��ۏ���'M�Qmu��z�nu�{Vᖿ�Φev�FGۿ�D�r����'��������V�������>�q�������>�X�������·=1$�$lNDDD�I RDDDD�� EDDD�I RDDDD�� EDDD�I RDDDD�� EDDD�I RDDDD�� EDDD�I RDDDD�� EDDD�I RDDDD�� EDDD�I RDDDD�� EDDD�IF@DD���+��PW@�A��(X�O��m-n���"8)
�����*h1H#wL���)�6"������ష�v���AU0c�""
6M!Jt �G��ss��Lnf<r3�a6�X���( QA��͉��I�%�����wEt���.��F
. RDD�Ft@t� �{ǰ7*�E���k.����W
: RDDAFD �]s���t��G��QA�A��(X40��Ds���0t� �u� (xp�9Q0D��]o;H��{]E�1����L>���AT���_:*�""
2��t����i�O�')"�����u�)~�v "-B��`� EDl��t�_�݂�}d0J#��a
^�@]�=R݇��ec�
\3+Hq�,"���A*pͬ��u���z&)�Y���""�8�ܟ�fV��u���z)�Y�
��""�Y���kfu?\7����`�����mq�,"�������kf5��EDD R~�5�����f1BQ�b0 *{ !!>W��Pw�P�����:����u��P{�@��O�Aʯ�fV��n�u�Fc胿���>=�.���NKu�v�(��GU��ڶŎ�A�?S\,�i�����ƾg��VW�%uP�� �o\3���Y�])UEٚ�(�� �\qA��ᬱtx��))��?�b�&\��K>7�&MB���8�b��#,�r��9b�]�ԙ�p��w/z �}0H�Hu/\7�����y��
�:xA��+�EQ��V�.��z�E�>MǪ/,@��ob�F��(F#�� ��}����J�: ɓ'#�� ���H�5��(��߇#K�������q�� ��cTZt��� ��|$_1�S����/#���G�eP��wh(.F�8��"�JJ�����!z�@x~!�էZ�O\��͈�ר;윺�:�A���.���ވ: �?���dTm�SL �F�D�Cc�C�����:+�55P��! t��t��ީ�<C����
��P�F8�O!fеH�0'��s\cl,Rf̀�������*f3Rg͆�(�ܴ��>}�� ���R+���ҵ4�����C�&_�𾙞Sc�Ӊ·߂��$���uT� ���4���{�G�S=(��nE�G�Ԏm����8��[X��+�(��hDHB�~�0���!��H��}$M���O>���M�Csa��F�ˡ�lg}�#F"vh.����>��8��&*�n �S��R"�/%�z>�^��r�=N�IDDb��Fxj�5m�}���u�����@�Q�c;a)��>��((x�Uw�jOj��D��=OKGxzF��<�r�.�v�8g�9}�������^��h:B`��+��L�5�]�=RDD�!'W�@�;K�����=���u����j6��X��h8y��Xek� q�x$O�k�!���=d0j�����=�d1��g ����n�zϜ���L�}�qh��?5��F��t��DD�q�Ww���A���ί��v�~�+*�0v ����SD$��}�cՎ��JJp���PtQ99���:�ڨga��Պ�-��z͵�����'��P��=�;5�I��`��@xZ:��a]6\��u��9 ���$��KK ����}O��{����ot��!"���|�z("H�~b� E��]p�Ԝ�A�sB���Ƙ���C\.�++�~�9u�H�d�iݬ&�ٌ��#�8u
�#��]Q�3���j��z�|�t��C����X�; �ḡh,{��VZr���?kAb� DP���sN�i���ȧ� [I *6m�������j�&'�l�W�o�犨=�z��nV��a�0�g����v~�}z��]@κZ��!z�`� ��7���۶�^^�4�����u����}�;���V���w߃��� �:v?�{��J�܏gJ׬FvV압��?t��ફC��eH�� �_wy~Dj6N��.��~��X�A�G�.�f�aa�;�2m�UPм����.���{�nލmߡ��~l�[8��2���j�����Чתl�W(߰���p���e��u?-��� ��ʭ[<�;+]G�ʏP��J�bb`���n��VY��qR�� Ճu�u�b F�%�q腿�z�F>��E?&Q����t[᧭��n?=�T;�P�L���b���!8-8-��H���S���U�+���t",���Qp IK�����Ǐ���x��S�u���xj��C���u���1pz�,��n��biuݬ���P_P�bݬ�H�0����f��Ͼn��sLQd��Cݑ�8��n1�&'�HQ�X7��z����������Խ�G��źYD�C�m ?c�u�u������=R����"""�b R���
IL� �fu)���|�,"""?�)
�u�@ �@��C5��  �� ��|�r�j�v������.��;���i}�u�O��L����R���m�tMC �] R=X�X7 ���!��e�9�х� ��ںYӦwz�,":m�{��]�I���A�FHr/� �u��.�`�w D=���u�JW�u���((0HQ��YD�((��C��������<����x– Cѹ)
�(P�`��#����Æ]��k�;8�)"�����U�����p>]��$�l�S��������1L%��#"
2��BQ p:��*<��VBs9 ��9Z��7p4�"*T� S !0��@Q�/`�
6 RDD��i�pEQ��0�]���P��v:<1DE�@Q P &(��3T�EQ�(<I��������Ñ�@U � Shӟ �5'Dt�H��08���N�j0A5�a0�@5�����7�� . RDDADETT� �4�N���.��=�R� 0�� �4��U�&w�2�ܽT��{A�A��(�(
U�
#�E5B�5��@s��S{�Fiy��
U5@1ݧ�T�=QA�A*p������DQ����jh
QM���[s�T�E����7
. RA�K=���0�O�nr�7���t�@����Xu�Q0j>M$-� Rx�|a����z���u�3������S�� �og,�p�����C�r
J�'���v�C���m#�/%{ -x��`�wtx?�$��s`6�����َ�Pm��Ѳ~ť��-{
���=�Ep��,�O���(�/O�9&CǾ�'IƂ�ET� !&����Tq��)?;s����|�'������<s�4M�g4��������50=9. ���6k��w�̆�b��d�� 8XT{Qj�)�����D��B��z�Wr�i�܃j0A1���]eV$Džy����əX�WҮS|�&g">���S����"T۳0H� �z���u���`TVLFիG��Y�x����ؤ�P\7.�{�[T`oa�E���`��#.�ܸ�u��R+>�Q�kǥ{nSL���[N���w\���w�å��5G��r0H��z^\���k p��^��4{~�)�������/�[}̈�?8ɧ7���(����5� R�ĥ�.�@D]�������Y�^����Y�����dTq�h��գ�����u�0H��z���u��[N`���K9=ys�)�3 L�iuo�>�S�xE�0 R��K=t PDt� ��_�o�u{k����Z�ծҋS\� H��Cpbp"�.���[T`ܠ�����G�y��c�
t��&"�3��>�!���]%8ZRwQ��8c Q���:�=�9�����Q�`�1X��v��w�)ĩ:�E��'b�"""
B���>9x���Z�َ�.��gb�"""
R�˼��W��5���bb�"""
bm�j��ַ�U]XM�ë���(����)(����'p��t�+�.�����z�U� RDD�-�쥕��������Gq��d�F�x��G������"����y����ݓ0H���c�� O��������� �g��3/�q�����U�`�1��y��A�����)D��a���x`n.T��͌Gnf<�&K�@�[_����`s""�!Jt �����<\;.�]�==�=������5���aoT�5A�\]s��=����@t���w)t�ZS�T��������u ���Z]���������CD�����ν� �������PM&��E� �@��ot�)""�iSz�SӝIӘ7��#""���_��0�s�x�5�!�g�� RDD�?M_��C�t�;��؃�1��{��A�{/�����:�A�����������:�A�����������:�A�����������:�A�������h1�L�����u]� �;t(('�4��!*{ �����h��K������G�5C� U� RV+�=p?����TQ50��*�++.`���!��Gٯ?���·D}aa��ѓ0HQ�� PTekV���/�r�]�f�����}���`�����M�pp��.���}�LD���U[Ch�OO]x R�.�� >�n�(�4� {ej� �(PսoE��6<�W/�]?�[6C5�?bd��'c�
D->x��m�*��EpR(��Q�K�: ɓ'#�� ���H�5��(��߇#K�������q�� ��cTZt��� ��|$_1�S����/#���G�eP��wh(.F�8��"�JJ�����!z�@x~!�է�.RQ�9�f���}}o�w1_j�A*Ј�c�� O�����~������p>�p :������ވ: �?���dTm�SL �F�D�Cc�C�����:+�55P��! t��t���;���b��/�RSa=r��g�)� �I&����y�k��EʌpTVB�5��Ƙ��H�8 �K�Bci�Y�K�T i
Q�k�>�7���dr3㑛�I�ҵ�tp�Q�K�|��fzz�u��o�[�IM�� �&���h,.T9�ޏ�+�"zPNm݊�>ĩ�p�s qj�8�h!���(��hDHB�~�0���!��H��}$M���O>���M�Csa��F�ˡ�lm֯�����oC�ɓ([���1���<R��E�]���g��":׎�tDtO#&St4�S� �i ����P��(��_����ۡKIm��EA�믺C� {e%���AxZ:��3��� ��_��IDAT�Cw�P�c�Yې����7o���
a{ӥ�#HDD���пw�����j��� 04 :�o�@ur�
���;��FD���u����j6��X��h8y��Xek� q�x$O�k�!���=d0j��������ƛpj�6T����/{���T��Cל�.�.]sAT"�v�(�5�u�!���O�+8� �j�� c�����".wL�([��g�Ukz]1 ��X�̛oqߨ����H��{�9��_~�\����� ���u ��{w�kN ��~�R$�6��VTnٌ�k�EL� $]> ��z���}ր��S-$M����S�MG���(_�����U~�� (D�!�C��Rk�^ׅEQ{Lz�}�&���kU �n'�!t��!"�ß�� ����k�v�D��S۷�QSs��_�6�����FE��_�
c�"��ZP�q��T��0�+.�i�&"���(�� �}E����P��/��n�wh_ZC=� bs�����M�e���1%A��c� f�P@�߬���t��BR'NYR�0H �?t�?��C���30Ng]-D�=h0b����Ѐ�m�`//�h���{/�+M��ow�]V+
�]���A���t��=le�m�dz?��kV#;+ ��J����s��3&�_l R���KW8sy��y��R�޽X7�ƶ����=��-��p��\N5{�`Ï��kU��+�oX���D8kj�ZϺ��l�e]G��-��u�,Z�@θҐ.<�@���C���(е�3�V�i�v��O�9Վ�)Ӧ"�ظ��&�a��"�܆��(�$�B��h(.B����.�ډ=RDDD���#�Q��+h�g_[��Q�;�{�=���#""
 QA�A�����������:�A�����������:�A������8�������]� �;t(x�$QD����PTu����AWEDD��!~�h }�7PT83HY�����pZ�;�SEA��8��`����ն-v���w?�� ��"8�+���w�AR�w�?��م}�eY�' �4Y�уP9�N�R+,sW�.&�:=S1��L4^<��*�r1gE$\N��ȃA|Z5QV���<��>����t�3�<�,���L����U���]��;���~ݭm��ś�2R��ל_�:�%�\Z))�ض�e�n�z�ݫ�7M�G[k8����//���PG�zK;�x<##Z��^���ǵ{ųj��' 5J��. ��
���ϵ�_���U���v�K�D�B�t^뱣jܹ�s =�c%^ۘ��]?{Zn���x\�=rD��W�=��AӦ���W�����A
�Vv�<�͙�O�� �n�*�l�BEEjضU�W<�Sj%Icn�M�Y�H���̺F3F���i׳Ϩy�'*�{�ʾ�e�~��^�D�/�V�����A�����������c��6_v�����}v<m}�͝��~zLn<.c;��ct��& R$����-֞���INtۀ��*�2MS�{@c��jܶU�;�k�_���ONq�$���Y��I^[��N�Pۉ�b��� �Pi�M��;z�tr��Q��*�T����=�}��R��p������F��e�d,K��:��� �Qk#�M؝�j� �?ܛX��Z�B��s�j����pn,��/�R�Ç$%��l[V(���-�:xP�,M��ߩl��*�4Q��}W׼���W�����?|��O<~��$c���(o����S�O$Iy��F-^��������_�ɻ��N��pQ���?=��s �������7vL���nj ��/U� ?��MaT*Ǽ�e�~��&�]',�Q�"H�C��X+F�K)�=&{@�Y�1�v��D��$�է￧as�׀�n��1F{��D�J�_�c��f��\u����;$cT6�:�������{��j؜�*�4Y�}����a�\��G!ʒ�l��<�ˊ�韟Z�x{���X�'��pP%G-K�� ;o�B�y2����� ��~�������qN��<On[�Y��N��<Y�p���s]�:���^ߠȬkT6�Z5�S���U<�R�۶*z��ۯ_8~�.��N�����嶶v��2�I�S,ۑ���D?1�<7.y���y��g9G##�X�,;$�e�aY��<Ѩ��"H�l��㑛��I6E�⨱q�6�=�!W�Ҿի4h�4�
U���k�.$Ĉ��bm�ɣ:u��z\$��y��e����P~r�-7�繉��ѓ�
���#R��ʓ�dYv�ڷ�0�G�B��77��;o�b��*�8IC����[N�a�G�
xyee�v�r
����a�� T �#Iƒ,[���%G��r���Ԟ��^uL�%�e-'�TvHƲ۳]d��pQ���y����G$���Ј�j��*�t���W���� >/4d�����ƒk�O���Ⱥ( �R�l��8F�rd�qy�+�F�$��Ac�<Q��e�2����Ks���� �%Ӧk��կ�-'u�w��x�Q��b'N�t�4 ��Fy�N�lQ��� >���}j޳G%��H���߿.���'�M��o5p�(�ܽK%��U2��c���U���:u�@���12�'�X2Vb�ö�d��#P�`;���g������XS�<7��I�*��|־xK��UW���.q��K,=C��퉦��ܬ��Vj�]wk��$��G?���uG�|���kkӑ �5a�x�;��Ov^�o0��p� cT8~�
�O���Suu) h�a*��&q���<I���(Z�������,V�Y)���F��~��$�پ��T�K��t-���-ڼ��N�Vu�ש~�ʏDkhP{s�y_�L��:y��c�����Z[��w�u�є�@JM���?��+ =�T
A
� ]����{����9Ս�K��Qy� ����ot�F�% ���#l$��A��ӹR���a4�r�<����g���5� �� ��ݻtd�:�O���zdA
�Ӵ}����� ���\����)�R>�|"H�D��� �ב�1s~��l��sY�@E��1ƶ�]H�P�'�T�#�6�k{箶X{�KdA*H�����Ѧ?��v5���Ma�\}A*0?�&��~�Zk���Q��Ζ��� �w��a
�,�H"DY2��X�����5=��ooo�纒��KE+n��QDc۲��P�����d����)�RAa�$#c,Y�#� �s�r]WFFr��!*X���d,[��8y��,ˑ1��a��*�T�G�ȲlyvHv(?�˖���\y�wF�"L�I~v�,;$� ���rB�,�c�S|����H��$˖�$y�ѩ�\�=1���A�#H�I)�����P"P١�(�����>� $��X�,92���Yn\��J�)����1g�(`ɲl�IL�Y#QЇ���ϓg,+1�a[v2D%���-5*�:i �or��!HI2L%��$��2�'�;=�@3ɓR Г�X�b"HMj��;�D���s
��TP��#l$������A*��C @�p�@�R>�|"H�D��� �A
�'��O)�R>�|"H�D��� �A
�'��O)�R>�|"H�D��� �A
�'��O)�R>�|"H�D��� �A
�'��O)�R>�|"H�D��� �A
�'��O)�R>�|"H�D��)�Aj`���t��M�K8/�\A��� �F�n/- g��URVZ!��=A��� UWW�v{ia^�+��Y�Ș�[a}}�<��h-� ���V`�Ծ}��n/+��p%��� ,��p���^��f���[��?z+0A����i�OQ��JtǨ����4º���Q�?�����[� R;w�L�� ��p%�c�Ĉ�4����F�x<���?�����[� Rk֬Q4�D� ����,U ǒ��)���nذA������䎠���
L�:v옪��;m�,�E׌�BE�r�G�h@(�B�M�6e��?�����[� R��i͚5i�}��L��
2\�t�:���Qr��g�lܸQ�N��xM� 7��V`��$�\�2��c[���I
���w��Y�TR��hR��z�)���e�*�� ��?z#PA���Z�bE�}��,�_W��pE�4g�0Ϳr�B�թ���z��w��P��[��Go*Hy����?�鏶e��ʑ����Y��ߦ�.Ѳ�q*ȳ�M>��#jii�Be � ���?z#PAJ�N�8��~8�c�/�|��q�D�� �3u���+�5�(�� �Z�Jo��v֏&�@��J���x��]r�%ڻwo�k鐗���^K�,I��kwU�^�C�����4 W [Zr�͟9R���$u�N~��Z�x�jkk�Qb'� r��� %I��ڵku�UW�m�q�S�-�׷����Q��X��&ǒ\9R��HI��N�����Z�|�ͪ�� �m�@��z���)I7n�֭[�ѣG�����ek,��t\��:�]����d�+r_�@GG�j������A\��pȖQ�HIjhh�ҥK�~��@^���dN_�=� e�ь3������.�JR{�U{�S���&����N�f�\ ']R^���%�ٶ�cYr�k�������kٲeڸqc`OW�__�=� %I�e���BO>��.\x�fx.��� =�:�;����n�M[�nU,�)1�pq����]��<���R۷o�v-]2ƨ��@����������!�|�Z�J��{�<�3k�@0�b��K���ʲ]�yy����f=�����+�bŊN׉p���[������}Mȩ&H��+��DžD"�Ĉ��߮�{.��t�1F �ԩSu�]w���꼋I���Р�7����֭[�������K
�Ȍ��?ҩ���#I���ٮ��<�SKK��{�=���(
i���Z�p�fϞ���M�6���Pmm���߯]�v�W^�k���h4�h4��gդ�?���?�t"�H���u;.'��o���Z�P�F��mg�: ���+�u������B�t���?��3 :4�ƌ��Zz%�+�+�f�9�����c�&�H566jذa4�nZ�zu⬽��b-X� ��䄊�
M�>=�$i���٬ g�NP�R�-R~~~6k� UUU*((8����4o޼l�x�HD�^{� p:Hc����Q)����׿��#G�s:HI��ɓu��g�.�@�8q���N���J��Aʲ,}���eT
��˗k���w@��}�رc�|��d3g���ŋUXXر�xin���ܬE�i���- �***�j�*]}��r�c{�)I*,,Գ�>� &d�@� ***�O<�3f���.��$�=Z/���JJJ�:�~�����*��.��1FӧO���s��x��z�*))I��� %%��馛�v�ZM�0�0����"=����7��!C�t��������U[[�e˖i�����SrREE�{�1-X�@����}�yG�Rl�֘1c���/k���L�>i�̙Z�z�-Zt�%usD�L��ͪ������=F�@�PQQ�o��Z�t����e�v���� %I���jjj�o�[=��C���!P���Dt�w������Õ��ߣ�7_A*���MMMMڴi�^y��]�V����*X�HD�g�ּy�4�|�1B��.�*H��b1E�Q���jǎڰa�6nܨh4���FF�@VD"]z�rG3f��ܹs5k�,)�x�\�K����Z4��I|IEND�B`�
The MIT License (MIT)
Copyright (c) 2013 container-interop
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Container Interoperability

Latest Stable Version

container-interop tries to identify and standardize features in container objects (service locators, dependency injection containers, etc.) to achieve interopererability.

Through discussions and trials, we try to create a standard, made of common interfaces but also recommendations.

If PHP projects that provide container implementations begin to adopt these common standards, then PHP applications and projects that use containers can depend on the common interfaces instead of specific implementations. This facilitates a high-level of interoperability and flexibility that allows users to consume any container implementation that can be adapted to these interfaces.

The work done in this project is not officially endorsed by the PHP-FIG, but it is being worked on by members of PHP-FIG and other good developers. We adhere to the spirit and ideals of PHP-FIG, and hope this project will pave the way for one or more future PSRs.

Installation

You can install this package through Composer:

{
    "require": {
        "container-interop/container-interop": "~1.0"
    }
}

The packages adheres to the SemVer specification, and there will be full backward compatibility between minor versions.

Standards

Available

Proposed

View open request for comments

Compatible projects

Projects implementing ContainerInterface

Projects implementing the delegate lookup feature

Workflow

Everyone is welcome to join and contribute.

The general workflow looks like this:

  1. Someone opens a discussion (GitHub issue) to suggest an interface
  2. Feedback is gathered
  3. The interface is added to a development branch
  4. We release alpha versions so that the interface can be experimented with
  5. Discussions and edits ensue until the interface is deemed stable by a general consensus
  6. A new minor version of the package is released

We try to not break BC by creating new interfaces instead of editing existing ones.

While we currently work on interfaces, we are open to anything that might help towards interoperability, may that be code, best practices, etc.

<?php
/**
* @license http://www.opensource.org/licenses/mit-license.php MIT (see the LICENSE file)
*/
namespace Interop\Container;
use Interop\Container\Exception\ContainerException;
use Interop\Container\Exception\NotFoundException;
/**
* Describes the interface of a container that exposes methods to read its entries.
*/
interface ContainerInterface
{
/**
* Finds an entry of the container by its identifier and returns it.
*
* @param string $id Identifier of the entry to look for.
*
* @throws NotFoundException No entry was found for this identifier.
* @throws ContainerException Error while retrieving the entry.
*
* @return mixed Entry.
*/
public function get($id);
/**
* Returns true if the container can return an entry for the given identifier.
* Returns false otherwise.
*
* @param string $id Identifier of the entry to look for.
*
* @return boolean
*/
public function has($id);
}
<?php
/**
* @license http://www.opensource.org/licenses/mit-license.php MIT (see the LICENSE file)
*/
namespace Interop\Container\Exception;
/**
* Base interface representing a generic exception in a container.
*/
interface ContainerException
{
}
<?php
/**
* @license http://www.opensource.org/licenses/mit-license.php MIT (see the LICENSE file)
*/
namespace Interop\Container\Exception;
/**
* No entry was found in the container.
*/
interface NotFoundException extends ContainerException
{
}
vendor/
composer.lock
composer.phar
phpunit.xml
language: php
sudo: false
cache:
directory:
- $HOME/.composer/cache
php:
- 5.3
- 5.4
- 5.5
- 5.6
- 7.0
- hhvm
install:
- composer install -n
script:
- phpunit
{
"name": "doctrine/inflector",
"type": "library",
"description": "Common String Manipulations with regard to casing and singular/plural rules.",
"keywords": ["string", "inflection", "singularize", "pluralize"],
"homepage": "http://www.doctrine-project.org",
"license": "MIT",
"authors": [
{"name": "Guilherme Blanco", "email": "guilhermeblanco@gmail.com"},
{"name": "Roman Borschel", "email": "roman@code-factory.org"},
{"name": "Benjamin Eberlei", "email": "kontakt@beberlei.de"},
{"name": "Jonathan Wage", "email": "jonwage@gmail.com"},
{"name": "Johannes Schmitt", "email": "schmittjoh@gmail.com"}
],
"require": {
"php": ">=5.3.2"
},
"require-dev": {
"phpunit/phpunit": "4.*"
},
"autoload": {
"psr-0": { "Doctrine\\Common\\Inflector\\": "lib/" }
},
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}
}
}
<?php
/*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the MIT license. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\Common\Inflector;
/**
* Doctrine inflector has static methods for inflecting text.
*
* The methods in these classes are from several different sources collected
* across several different php projects and several different authors. The
* original author names and emails are not known.
*
* Pluralize & Singularize implementation are borrowed from CakePHP with some modifications.
*
* @link www.doctrine-project.org
* @since 1.0
* @author Konsta Vesterinen <kvesteri@cc.hut.fi>
* @author Jonathan H. Wage <jonwage@gmail.com>
*/
class Inflector
{
/**
* Plural inflector rules.
*
* @var array
*/
private static $plural = array(
'rules' => array(
'/(s)tatus$/i' => '\1\2tatuses',
'/(quiz)$/i' => '\1zes',
'/^(ox)$/i' => '\1\2en',
'/([m|l])ouse$/i' => '\1ice',
'/(matr|vert|ind)(ix|ex)$/i' => '\1ices',
'/(x|ch|ss|sh)$/i' => '\1es',
'/([^aeiouy]|qu)y$/i' => '\1ies',
'/(hive)$/i' => '\1s',
'/(?:([^f])fe|([lr])f)$/i' => '\1\2ves',
'/sis$/i' => 'ses',
'/([ti])um$/i' => '\1a',
'/(p)erson$/i' => '\1eople',
'/(m)an$/i' => '\1en',
'/(c)hild$/i' => '\1hildren',
'/(f)oot$/i' => '\1eet',
'/(buffal|her|potat|tomat|volcan)o$/i' => '\1\2oes',
'/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|vir)us$/i' => '\1i',
'/us$/i' => 'uses',
'/(alias)$/i' => '\1es',
'/(analys|ax|cris|test|thes)is$/i' => '\1es',
'/s$/' => 's',
'/^$/' => '',
'/$/' => 's',
),
'uninflected' => array(
'.*[nrlm]ese', '.*deer', '.*fish', '.*measles', '.*ois', '.*pox', '.*sheep', 'people', 'cookie'
),
'irregular' => array(
'atlas' => 'atlases',
'axe' => 'axes',
'beef' => 'beefs',
'brother' => 'brothers',
'cafe' => 'cafes',
'chateau' => 'chateaux',
'child' => 'children',
'cookie' => 'cookies',
'corpus' => 'corpuses',
'cow' => 'cows',
'criterion' => 'criteria',
'curriculum' => 'curricula',
'demo' => 'demos',
'domino' => 'dominoes',
'echo' => 'echoes',
'foot' => 'feet',
'fungus' => 'fungi',
'ganglion' => 'ganglions',
'genie' => 'genies',
'genus' => 'genera',
'graffito' => 'graffiti',
'hippopotamus' => 'hippopotami',
'hoof' => 'hoofs',
'human' => 'humans',
'iris' => 'irises',
'leaf' => 'leaves',
'loaf' => 'loaves',
'man' => 'men',
'medium' => 'media',
'memorandum' => 'memoranda',
'money' => 'monies',
'mongoose' => 'mongooses',
'motto' => 'mottoes',
'move' => 'moves',
'mythos' => 'mythoi',
'niche' => 'niches',
'nucleus' => 'nuclei',
'numen' => 'numina',
'occiput' => 'occiputs',
'octopus' => 'octopuses',
'opus' => 'opuses',
'ox' => 'oxen',
'penis' => 'penises',
'person' => 'people',
'plateau' => 'plateaux',
'runner-up' => 'runners-up',
'sex' => 'sexes',
'soliloquy' => 'soliloquies',
'son-in-law' => 'sons-in-law',
'syllabus' => 'syllabi',
'testis' => 'testes',
'thief' => 'thieves',
'tooth' => 'teeth',
'tornado' => 'tornadoes',
'trilby' => 'trilbys',
'turf' => 'turfs',
'volcano' => 'volcanoes',
)
);
/**
* Singular inflector rules.
*
* @var array
*/
private static $singular = array(
'rules' => array(
'/(s)tatuses$/i' => '\1\2tatus',
'/^(.*)(menu)s$/i' => '\1\2',
'/(quiz)zes$/i' => '\\1',
'/(matr)ices$/i' => '\1ix',
'/(vert|ind)ices$/i' => '\1ex',
'/^(ox)en/i' => '\1',
'/(alias)(es)*$/i' => '\1',
'/(buffal|her|potat|tomat|volcan)oes$/i' => '\1o',
'/(alumn|bacill|cact|foc|fung|nucle|radi|stimul|syllab|termin|viri?)i$/i' => '\1us',
'/([ftw]ax)es/i' => '\1',
'/(analys|ax|cris|test|thes)es$/i' => '\1is',
'/(shoe|slave)s$/i' => '\1',
'/(o)es$/i' => '\1',
'/ouses$/' => 'ouse',
'/([^a])uses$/' => '\1us',
'/([m|l])ice$/i' => '\1ouse',
'/(x|ch|ss|sh)es$/i' => '\1',
'/(m)ovies$/i' => '\1\2ovie',
'/(s)eries$/i' => '\1\2eries',
'/([^aeiouy]|qu)ies$/i' => '\1y',
'/([lr])ves$/i' => '\1f',
'/(tive)s$/i' => '\1',
'/(hive)s$/i' => '\1',
'/(drive)s$/i' => '\1',
'/([^fo])ves$/i' => '\1fe',
'/(^analy)ses$/i' => '\1sis',
'/(analy|diagno|^ba|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' => '\1\2sis',
'/([ti])a$/i' => '\1um',
'/(p)eople$/i' => '\1\2erson',
'/(m)en$/i' => '\1an',
'/(c)hildren$/i' => '\1\2hild',
'/(f)eet$/i' => '\1oot',
'/(n)ews$/i' => '\1\2ews',
'/eaus$/' => 'eau',
'/^(.*us)$/' => '\\1',
'/s$/i' => '',
),
'uninflected' => array(
'.*[nrlm]ese',
'.*deer',
'.*fish',
'.*measles',
'.*ois',
'.*pox',
'.*sheep',
'.*ss',
),
'irregular' => array(
'criteria' => 'criterion',
'curves' => 'curve',
'emphases' => 'emphasis',
'foes' => 'foe',
'hoaxes' => 'hoax',
'media' => 'medium',
'neuroses' => 'neurosis',
'waves' => 'wave',
'oases' => 'oasis',
)
);
/**
* Words that should not be inflected.
*
* @var array
*/
private static $uninflected = array(
'Amoyese', 'bison', 'Borghese', 'bream', 'breeches', 'britches', 'buffalo', 'cantus',
'carp', 'chassis', 'clippers', 'cod', 'coitus', 'Congoese', 'contretemps', 'corps',
'debris', 'diabetes', 'djinn', 'eland', 'elk', 'equipment', 'Faroese', 'flounder',
'Foochowese', 'gallows', 'Genevese', 'Genoese', 'Gilbertese', 'graffiti',
'headquarters', 'herpes', 'hijinks', 'Hottentotese', 'information', 'innings',
'jackanapes', 'Kiplingese', 'Kongoese', 'Lucchese', 'mackerel', 'Maltese', '.*?media',
'mews', 'moose', 'mumps', 'Nankingese', 'news', 'nexus', 'Niasese',
'Pekingese', 'Piedmontese', 'pincers', 'Pistoiese', 'pliers', 'Portuguese',
'proceedings', 'rabies', 'rice', 'rhinoceros', 'salmon', 'Sarawakese', 'scissors',
'sea[- ]bass', 'series', 'Shavese', 'shears', 'siemens', 'species', 'staff', 'swine',
'testes', 'trousers', 'trout', 'tuna', 'Vermontese', 'Wenchowese', 'whiting',
'wildebeest', 'Yengeese'
);
/**
* Method cache array.
*
* @var array
*/
private static $cache = array();
/**
* The initial state of Inflector so reset() works.
*
* @var array
*/
private static $initialState = array();
/**
* Converts a word into the format for a Doctrine table name. Converts 'ModelName' to 'model_name'.
*
* @param string $word The word to tableize.
*
* @return string The tableized word.
*/
public static function tableize($word)
{
return strtolower(preg_replace('~(?<=\\w)([A-Z])~', '_$1', $word));
}
/**
* Converts a word into the format for a Doctrine class name. Converts 'table_name' to 'TableName'.
*
* @param string $word The word to classify.
*
* @return string The classified word.
*/
public static function classify($word)
{
return str_replace(" ", "", ucwords(strtr($word, "_-", " ")));
}
/**
* Camelizes a word. This uses the classify() method and turns the first character to lowercase.
*
* @param string $word The word to camelize.
*
* @return string The camelized word.
*/
public static function camelize($word)
{
return lcfirst(self::classify($word));
}
/**
* Uppercases words with configurable delimeters between words.
*
* Takes a string and capitalizes all of the words, like PHP's built-in
* ucwords function. This extends that behavior, however, by allowing the
* word delimeters to be configured, rather than only separating on
* whitespace.
*
* Here is an example:
* <code>
* <?php
* $string = 'top-o-the-morning to all_of_you!';
* echo \Doctrine\Common\Inflector\Inflector::ucwords($string);
* // Top-O-The-Morning To All_of_you!
*
* echo \Doctrine\Common\Inflector\Inflector::ucwords($string, '-_ ');
* // Top-O-The-Morning To All_Of_You!
* ?>
* </code>
*
* @param string $string The string to operate on.
* @param string $delimiters A list of word separators.
*
* @return string The string with all delimeter-separated words capitalized.
*/
public static function ucwords($string, $delimiters = " \n\t\r\0\x0B-")
{
return preg_replace_callback(
'/[^' . preg_quote($delimiters, '/') . ']+/',
function($matches) {
return ucfirst($matches[0]);
},
$string
);
}
/**
* Clears Inflectors inflected value caches, and resets the inflection
* rules to the initial values.
*
* @return void
*/
public static function reset()
{
if (empty(self::$initialState)) {
self::$initialState = get_class_vars('Inflector');
return;
}
foreach (self::$initialState as $key => $val) {
if ($key != 'initialState') {
self::${$key} = $val;
}
}
}
/**
* Adds custom inflection $rules, of either 'plural' or 'singular' $type.
*
* ### Usage:
*
* {{{
* Inflector::rules('plural', array('/^(inflect)or$/i' => '\1ables'));
* Inflector::rules('plural', array(
* 'rules' => array('/^(inflect)ors$/i' => '\1ables'),
* 'uninflected' => array('dontinflectme'),
* 'irregular' => array('red' => 'redlings')
* ));
* }}}
*
* @param string $type The type of inflection, either 'plural' or 'singular'
* @param array $rules An array of rules to be added.
* @param boolean $reset If true, will unset default inflections for all
* new rules that are being defined in $rules.
*
* @return void
*/
public static function rules($type, $rules, $reset = false)
{
foreach ($rules as $rule => $pattern) {
if ( ! is_array($pattern)) {
continue;
}
if ($reset) {
self::${$type}[$rule] = $pattern;
} else {
self::${$type}[$rule] = ($rule === 'uninflected')
? array_merge($pattern, self::${$type}[$rule])
: $pattern + self::${$type}[$rule];
}
unset($rules[$rule], self::${$type}['cache' . ucfirst($rule)]);
if (isset(self::${$type}['merged'][$rule])) {
unset(self::${$type}['merged'][$rule]);
}
if ($type === 'plural') {
self::$cache['pluralize'] = self::$cache['tableize'] = array();
} elseif ($type === 'singular') {
self::$cache['singularize'] = array();
}
}
self::${$type}['rules'] = $rules + self::${$type}['rules'];
}
/**
* Returns a word in plural form.
*
* @param string $word The word in singular form.
*
* @return string The word in plural form.
*/
public static function pluralize($word)
{
if (isset(self::$cache['pluralize'][$word])) {
return self::$cache['pluralize'][$word];
}
if (!isset(self::$plural['merged']['irregular'])) {
self::$plural['merged']['irregular'] = self::$plural['irregular'];
}
if (!isset(self::$plural['merged']['uninflected'])) {
self::$plural['merged']['uninflected'] = array_merge(self::$plural['uninflected'], self::$uninflected);
}
if (!isset(self::$plural['cacheUninflected']) || !isset(self::$plural['cacheIrregular'])) {
self::$plural['cacheUninflected'] = '(?:' . implode('|', self::$plural['merged']['uninflected']) . ')';
self::$plural['cacheIrregular'] = '(?:' . implode('|', array_keys(self::$plural['merged']['irregular'])) . ')';
}
if (preg_match('/(.*)\\b(' . self::$plural['cacheIrregular'] . ')$/i', $word, $regs)) {
self::$cache['pluralize'][$word] = $regs[1] . substr($word, 0, 1) . substr(self::$plural['merged']['irregular'][strtolower($regs[2])], 1);
return self::$cache['pluralize'][$word];
}
if (preg_match('/^(' . self::$plural['cacheUninflected'] . ')$/i', $word, $regs)) {
self::$cache['pluralize'][$word] = $word;
return $word;
}
foreach (self::$plural['rules'] as $rule => $replacement) {
if (preg_match($rule, $word)) {
self::$cache['pluralize'][$word] = preg_replace($rule, $replacement, $word);
return self::$cache['pluralize'][$word];
}
}
}
/**
* Returns a word in singular form.
*
* @param string $word The word in plural form.
*
* @return string The word in singular form.
*/
public static function singularize($word)
{
if (isset(self::$cache['singularize'][$word])) {
return self::$cache['singularize'][$word];
}
if (!isset(self::$singular['merged']['uninflected'])) {
self::$singular['merged']['uninflected'] = array_merge(
self::$singular['uninflected'],
self::$uninflected
);
}
if (!isset(self::$singular['merged']['irregular'])) {
self::$singular['merged']['irregular'] = array_merge(
self::$singular['irregular'],
array_flip(self::$plural['irregular'])
);
}
if (!isset(self::$singular['cacheUninflected']) || !isset(self::$singular['cacheIrregular'])) {
self::$singular['cacheUninflected'] = '(?:' . join('|', self::$singular['merged']['uninflected']) . ')';
self::$singular['cacheIrregular'] = '(?:' . join('|', array_keys(self::$singular['merged']['irregular'])) . ')';
}
if (preg_match('/(.*)\\b(' . self::$singular['cacheIrregular'] . ')$/i', $word, $regs)) {
self::$cache['singularize'][$word] = $regs[1] . substr($word, 0, 1) . substr(self::$singular['merged']['irregular'][strtolower($regs[2])], 1);
return self::$cache['singularize'][$word];
}
if (preg_match('/^(' . self::$singular['cacheUninflected'] . ')$/i', $word, $regs)) {
self::$cache['singularize'][$word] = $word;
return $word;
}
foreach (self::$singular['rules'] as $rule => $replacement) {
if (preg_match($rule, $word)) {
self::$cache['singularize'][$word] = preg_replace($rule, $replacement, $word);
return self::$cache['singularize'][$word];
}
}
self::$cache['singularize'][$word] = $word;
return $word;
}
}
Copyright (c) 2006-2015 Doctrine Project
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="./tests/Doctrine/Tests/TestInit.php"
>
<testsuites>
<testsuite name="Doctrine Inflector Test Suite">
<directory>./tests/Doctrine/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>./lib/Doctrine/</directory>
</whitelist>
</filter>
<groups>
<exclude>
<group>performance</group>
</exclude>
</groups>
</phpunit>

Doctrine Inflector

Doctrine Inflector is a small library that can perform string manipulations with regard to upper-/lowercase and singular/plural forms of words.

Build Status

<?php
namespace Doctrine\Tests\Common\Inflector;
use Doctrine\Tests\DoctrineTestCase;
use Doctrine\Common\Inflector\Inflector;
class InflectorTest extends DoctrineTestCase
{
/**
* Singular & Plural test data. Returns an array of sample words.
*
* @return array
*/
public function dataSampleWords()
{
Inflector::reset();
// In the format array('singular', 'plural')
return array(
array('', ''),
array('Alias', 'Aliases'),
array('alumnus', 'alumni'),
array('analysis', 'analyses'),
array('aquarium', 'aquaria'),
array('arch', 'arches'),
array('atlas', 'atlases'),
array('axe', 'axes'),
array('baby', 'babies'),
array('bacillus', 'bacilli'),
array('bacterium', 'bacteria'),
array('bureau', 'bureaus'),
array('bus', 'buses'),
array('Bus', 'Buses'),
array('cactus', 'cacti'),
array('cafe', 'cafes'),
array('calf', 'calves'),
array('categoria', 'categorias'),
array('chateau', 'chateaux'),
array('cherry', 'cherries'),
array('child', 'children'),
array('church', 'churches'),
array('circus', 'circuses'),
array('city', 'cities'),
array('cod', 'cod'),
array('cookie', 'cookies'),
array('copy', 'copies'),
array('crisis', 'crises'),
array('criterion', 'criteria'),
array('curriculum', 'curricula'),
array('curve', 'curves'),
array('deer', 'deer'),
array('demo', 'demos'),
array('dictionary', 'dictionaries'),
array('domino', 'dominoes'),
array('dwarf', 'dwarves'),
array('echo', 'echoes'),
array('elf', 'elves'),
array('emphasis', 'emphases'),
array('family', 'families'),
array('fax', 'faxes'),
array('fish', 'fish'),
array('flush', 'flushes'),
array('fly', 'flies'),
array('focus', 'foci'),
array('foe', 'foes'),
array('food_menu', 'food_menus'),
array('FoodMenu', 'FoodMenus'),
array('foot', 'feet'),
array('fungus', 'fungi'),
array('glove', 'gloves'),
array('half', 'halves'),
array('hero', 'heroes'),
array('hippopotamus', 'hippopotami'),
array('hoax', 'hoaxes'),
array('house', 'houses'),
array('human', 'humans'),
array('identity', 'identities'),
array('index', 'indices'),
array('iris', 'irises'),
array('kiss', 'kisses'),
array('knife', 'knives'),
array('leaf', 'leaves'),
array('life', 'lives'),
array('loaf', 'loaves'),
array('man', 'men'),
array('matrix', 'matrices'),
array('matrix_row', 'matrix_rows'),
array('medium', 'media'),
array('memorandum', 'memoranda'),
array('menu', 'menus'),
array('Menu', 'Menus'),
array('mess', 'messes'),
array('moose', 'moose'),
array('motto', 'mottoes'),
array('mouse', 'mice'),
array('neurosis', 'neuroses'),
array('news', 'news'),
array('NodeMedia', 'NodeMedia'),
array('nucleus', 'nuclei'),
array('oasis', 'oases'),
array('octopus', 'octopuses'),
array('pass', 'passes'),
array('person', 'people'),
array('plateau', 'plateaux'),
array('potato', 'potatoes'),
array('powerhouse', 'powerhouses'),
array('quiz', 'quizzes'),
array('radius', 'radii'),
array('reflex', 'reflexes'),
array('roof', 'roofs'),
array('runner-up', 'runners-up'),
array('scarf', 'scarves'),
array('scratch', 'scratches'),
array('series', 'series'),
array('sheep', 'sheep'),
array('shelf', 'shelves'),
array('shoe', 'shoes'),
array('son-in-law', 'sons-in-law'),
array('species', 'species'),
array('splash', 'splashes'),
array('spy', 'spies'),
array('stimulus', 'stimuli'),
array('stitch', 'stitches'),
array('story', 'stories'),
array('syllabus', 'syllabi'),
array('tax', 'taxes'),
array('terminus', 'termini'),
array('thesis', 'theses'),
array('thief', 'thieves'),
array('tomato', 'tomatoes'),
array('tooth', 'teeth'),
array('tornado', 'tornadoes'),
array('try', 'tries'),
array('vertex', 'vertices'),
array('virus', 'viri'),
array('volcano', 'volcanoes'),
array('wash', 'washes'),
array('watch', 'watches'),
array('wave', 'waves'),
array('wharf', 'wharves'),
array('wife', 'wives'),
array('woman', 'women'),
);
}
/**
* testInflectingSingulars method
*
* @dataProvider dataSampleWords
* @return void
*/
public function testInflectingSingulars($singular, $plural)
{
$this->assertEquals(
$singular,
Inflector::singularize($plural),
"'$plural' should be singularized to '$singular'"
);
}
/**
* testInflectingPlurals method
*
* @dataProvider dataSampleWords
* @return void
*/
public function testInflectingPlurals($singular, $plural)
{
$this->assertEquals(
$plural,
Inflector::pluralize($singular),
"'$singular' should be pluralized to '$plural'"
);
}
/**
* testCustomPluralRule method
*
* @return void
*/
public function testCustomPluralRule()
{
Inflector::reset();
Inflector::rules('plural', array('/^(custom)$/i' => '\1izables'));
$this->assertEquals(Inflector::pluralize('custom'), 'customizables');
Inflector::rules('plural', array('uninflected' => array('uninflectable')));
$this->assertEquals(Inflector::pluralize('uninflectable'), 'uninflectable');
Inflector::rules('plural', array(
'rules' => array('/^(alert)$/i' => '\1ables'),
'uninflected' => array('noflect', 'abtuse'),
'irregular' => array('amaze' => 'amazable', 'phone' => 'phonezes')
));
$this->assertEquals(Inflector::pluralize('noflect'), 'noflect');
$this->assertEquals(Inflector::pluralize('abtuse'), 'abtuse');
$this->assertEquals(Inflector::pluralize('alert'), 'alertables');
$this->assertEquals(Inflector::pluralize('amaze'), 'amazable');
$this->assertEquals(Inflector::pluralize('phone'), 'phonezes');
}
/**
* testCustomSingularRule method
*
* @return void
*/
public function testCustomSingularRule()
{
Inflector::reset();
Inflector::rules('singular', array('/(eple)r$/i' => '\1', '/(jente)r$/i' => '\1'));
$this->assertEquals(Inflector::singularize('epler'), 'eple');
$this->assertEquals(Inflector::singularize('jenter'), 'jente');
Inflector::rules('singular', array(
'rules' => array('/^(bil)er$/i' => '\1', '/^(inflec|contribu)tors$/i' => '\1ta'),
'uninflected' => array('singulars'),
'irregular' => array('spins' => 'spinor')
));
$this->assertEquals(Inflector::singularize('inflectors'), 'inflecta');
$this->assertEquals(Inflector::singularize('contributors'), 'contributa');
$this->assertEquals(Inflector::singularize('spins'), 'spinor');
$this->assertEquals(Inflector::singularize('singulars'), 'singulars');
}
/**
* test that setting new rules clears the inflector caches.
*
* @return void
*/
public function testRulesClearsCaches()
{
Inflector::reset();
$this->assertEquals(Inflector::singularize('Bananas'), 'Banana');
$this->assertEquals(Inflector::pluralize('Banana'), 'Bananas');
Inflector::rules('singular', array(
'rules' => array('/(.*)nas$/i' => '\1zzz')
));
$this->assertEquals('Banazzz', Inflector::singularize('Bananas'), 'Was inflected with old rules.');
Inflector::rules('plural', array(
'rules' => array('/(.*)na$/i' => '\1zzz'),
'irregular' => array('corpus' => 'corpora')
));
$this->assertEquals(Inflector::pluralize('Banana'), 'Banazzz', 'Was inflected with old rules.');
$this->assertEquals(Inflector::pluralize('corpus'), 'corpora', 'Was inflected with old irregular form.');
}
/**
* Test resetting inflection rules.
*
* @return void
*/
public function testCustomRuleWithReset()
{
Inflector::reset();
$uninflected = array('atlas', 'lapis', 'onibus', 'pires', 'virus', '.*x');
$pluralIrregular = array('as' => 'ases');
Inflector::rules('singular', array(
'rules' => array('/^(.*)(a|e|o|u)is$/i' => '\1\2l'),
'uninflected' => $uninflected,
), true);
Inflector::rules('plural', array(
'rules' => array(
'/^(.*)(a|e|o|u)l$/i' => '\1\2is',
),
'uninflected' => $uninflected,
'irregular' => $pluralIrregular
), true);
$this->assertEquals(Inflector::pluralize('Alcool'), 'Alcoois');
$this->assertEquals(Inflector::pluralize('Atlas'), 'Atlas');
$this->assertEquals(Inflector::singularize('Alcoois'), 'Alcool');
$this->assertEquals(Inflector::singularize('Atlas'), 'Atlas');
}
/**
* Test basic ucwords functionality.
*
* @return void
*/
public function testUcwords()
{
$this->assertSame('Top-O-The-Morning To All_of_you!', Inflector::ucwords( 'top-o-the-morning to all_of_you!'));
}
/**
* Test ucwords functionality with custom delimeters.
*
* @return void
*/
public function testUcwordsWithCustomDelimeters()
{
$this->assertSame('Top-O-The-Morning To All_Of_You!', Inflector::ucwords( 'top-o-the-morning to all_of_you!', '-_ '));
}
}
<?php
namespace Doctrine\Tests;
/**
* Base testcase class for all Doctrine testcases.
*/
abstract class DoctrineTestCase extends \PHPUnit_Framework_TestCase
{
}
<?php
/*
* This file bootstraps the test environment.
*/
namespace Doctrine\Tests;
error_reporting(E_ALL | E_STRICT);
// register silently failing autoloader
spl_autoload_register(function($class)
{
if (0 === strpos($class, 'Doctrine\Tests\\')) {
$path = __DIR__.'/../../'.strtr($class, '\\', '/').'.php';
if (is_file($path) && is_readable($path)) {
require_once $path;
return true;
}
} else if (0 === strpos($class, 'Doctrine\Common\\')) {
$path = __DIR__.'/../../../lib/'.($class = strtr($class, '\\', '/')).'.php';
if (is_file($path) && is_readable($path)) {
require_once $path;
return true;
}
}
});
{
"name": "hiropeke/slim-blade-view",
"type": "library",
"description": "Slim Framework 3 view helper built on the Blade component",
"keywords": [
"slim",
"framework",
"view",
"template",
"blade",
"renderer"
],
"license": "MIT",
"authors": [
{
"name": "Hiroaki Matsuura",
"email": "hiropeke.jp@gmail.com"
}
],
"require": {
"illuminate/view": "5.*",
"philo/laravel-blade": "3.*",
"psr/http-message": "^1.0"
},
"autoload": {
"psr-4": {
"Slim\\Views\\": "src"
}
},
"require-dev": {
"phpunit/phpunit": "^5.0",
"slim/slim": "^3.0"
}
}
The MIT License (MIT)
Copyright (c) 2016 Hiroaki Matsuura
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
>
<testsuites>
<testsuite name="Renderer Tests">
<directory>tests/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory>src/</directory>
</whitelist>
</filter>
</phpunit>
<?php
namespace Slim\Views;
use Illuminate\Events\Dispatcher;
use Psr\Http\Message\ResponseInterface;
class Blade
{
/**
* @var array
*/
protected $viewPaths;
/**
* @var string
*/
protected $cachePath;
/**
* @var Dispatcher|null
*/
protected $events;
/**
* @var array
*/
protected $attributes;
/**
* Blade constructor.
* @param array $viewPaths
* @param $cachePath
* @param Dispatcher|null $events
*/
public function __construct($viewPaths = [], $cachePath = '', Dispatcher $events = null, $attributes = [])
{
if (is_string($viewPaths)) {
$viewPaths = [$viewPaths];
}
$this->viewPaths = $viewPaths;
$this->cachePath = $cachePath;
$this->events = $events;
$this->attributes = $attributes;
}
/**
* Render a template
*
* $data cannot contain template as a key
*
* throws RuntimeException if $templatePath . $template does not exist
*
* @param ResponseInterface $response
* @param string $template
* @param array $data
*
* @return ResponseInterface
*
* @throws \InvalidArgumentException
* @throws \RuntimeException
*/
public function render(ResponseInterface $response, $template, array $data = [])
{
$output = $this->fetch($template, $data);
$response->getBody()->write($output);
return $response;
}
/**
* Get the attributes for the renderer
*
* @return array
*/
public function getAttributes()
{
return $this->attributes;
}
/**
* Set the attributes for the renderer
*
* @param array $attributes
*/
public function setAttributes(array $attributes)
{
$this->attributes = $attributes;
}
/**
* Set the attribute for the renderer
*
* @param $key
* @param $value
*/
public function set($key, $value)
{
$this->attributes[$key] = $value;
}
/**
* Retrieve an attribute
*
* @param $key
* @return mixed
*/
public function get($key)
{
if (!isset($this->attributes[$key])) {
return false;
}
return $this->attributes[$key];
}
/**
* @return array
*/
public function getViewPaths()
{
return $this->viewPaths;
}
/**
* @param array $viewPaths
*/
public function setViewPaths($viewPaths)
{
$this->viewPaths = $viewPaths;
}
/**
* @return string
*/
public function getCachePath()
{
return $this->cachePath;
}
/**
* @param string $cachePath
*/
public function setCachePath($cachePath)
{
$this->cachePath = $cachePath;
}
/**
* Renders a template and returns the result as a string
*
* cannot contain template as a key
*
* throws RuntimeException if $templatePath . $template does not exist
*
* @param $template
* @param array $data
*
* @return mixed
*
* @throws \InvalidArgumentException
* @throws \RuntimeException
*/
public function fetch($template, array $data = [])
{
if (isset($data['template'])) {
throw new \InvalidArgumentException("Duplicate template key found");
}
$data = array_merge($this->attributes, $data);
$renderer = new \Philo\Blade\Blade($this->viewPaths, $this->cachePath, $this->events);
return $renderer->view()->make($template, $data)->render();
}
}
<?php
namespace Slim\Tests\Views;
use Slim\Views\Blade;
require __DIR__ . '/../vendor/autoload.php';
class BladeTest extends \PHPUnit_Framework_TestCase
{
/**
* @var Blade
*/
protected $view;
public function setUp()
{
$this->view = new Blade([__DIR__ . '/templates', __DIR__ . '/another'], __DIR__ . '/../data/cache');
}
public function testFetch()
{
$output = $this->view->fetch('example', [
'name' => 'Josh',
]);
$this->assertEquals("<p>Hi, my name is Josh.</p>\n", $output);
}
public function testSingleTemplateWithANamespace()
{
$views = new Blade([
'One' => __DIR__ . '/templates',
]);
$output = $views->fetch('example', [
'name' => 'Josh',
]);
$this->assertEquals("<p>Hi, my name is Josh.</p>\n", $output);
}
public function testMultipleTemplatesWithMulNamespace()
{
$views = new Blade([
'One' => __DIR__ . '/templates',
'Two' => __DIR__ . '/another',
]);
$outputOne = $views->fetch('example', [
'name' => 'Peter',
]);
$outputTwo = $views->fetch('example2', [
'name' => 'Peter',
'gender' => 'male',
]);
$this->assertEquals("<p>Hi, my name is Peter.</p>\n", $outputOne);
$this->assertEquals("<p>Hi, my name is Peter and I am male.</p>\n", $outputTwo);
}
public function testRender()
{
$mockBody = $this->getMockBuilder('Psr\Http\Message\StreamInterface')
->disableOriginalConstructor()
->getMock();
$mockResponse = $this->getMockBuilder('Psr\Http\Message\ResponseInterface')
->disableOriginalConstructor()
->getMock();
$mockBody->expects($this->once())
->method('write')
->with("<p>Hi, my name is Josh.</p>\n")
->willReturn(28);
$mockResponse->expects($this->once())
->method('getBody')
->willReturn($mockBody);
$response = $this->view->render($mockResponse, 'example', [
'name' => 'Josh',
]);
$this->assertInstanceOf('Psr\Http\Message\ResponseInterface', $response);
}
}
{
"name": "illuminate/container",
"description": "The Illuminate Container package.",
"license": "MIT",
"homepage": "http://laravel.com",
"support": {
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"authors": [
{
"name": "Taylor Otwell",
"email": "taylorotwell@gmail.com"
}
],
"require": {
"php": ">=5.5.9",
"illuminate/contracts": "5.2.*"
},
"autoload": {
"psr-4": {
"Illuminate\\Container\\": ""
}
},
"extra": {
"branch-alias": {
"dev-master": "5.2-dev"
}
},
"minimum-stability": "dev"
}
<?php
namespace Illuminate\Container;
use Closure;
use ArrayAccess;
use ReflectionClass;
use ReflectionMethod;
use ReflectionFunction;
use ReflectionParameter;
use InvalidArgumentException;
use Illuminate\Contracts\Container\BindingResolutionException;
use Illuminate\Contracts\Container\Container as ContainerContract;
class Container implements ArrayAccess, ContainerContract
{
/**
* The current globally available container (if any).
*
* @var static
*/
protected static $instance;
/**
* An array of the types that have been resolved.
*
* @var array
*/
protected $resolved = [];
/**
* The container's bindings.
*
* @var array
*/
protected $bindings = [];
/**
* The container's shared instances.
*
* @var array
*/
protected $instances = [];
/**
* The registered type aliases.
*
* @var array
*/
protected $aliases = [];
/**
* The extension closures for services.
*
* @var array
*/
protected $extenders = [];
/**
* All of the registered tags.
*
* @var array
*/
protected $tags = [];
/**
* The stack of concretions currently being built.
*
* @var array
*/
protected $buildStack = [];
/**
* The contextual binding map.
*
* @var array
*/
public $contextual = [];
/**
* All of the registered rebound callbacks.
*
* @var array
*/
protected $reboundCallbacks = [];
/**
* All of the global resolving callbacks.
*
* @var array
*/
protected $globalResolvingCallbacks = [];
/**
* All of the global after resolving callbacks.
*
* @var array
*/
protected $globalAfterResolvingCallbacks = [];
/**
* All of the resolving callbacks by class type.
*
* @var array
*/
protected $resolvingCallbacks = [];
/**
* All of the after resolving callbacks by class type.
*
* @var array
*/
protected $afterResolvingCallbacks = [];
/**
* Define a contextual binding.
*
* @param string $concrete
* @return \Illuminate\Contracts\Container\ContextualBindingBuilder
*/
public function when($concrete)
{
$concrete = $this->normalize($concrete);
return new ContextualBindingBuilder($this, $concrete);
}
/**
* Determine if the given abstract type has been bound.
*
* @param string $abstract
* @return bool
*/
public function bound($abstract)
{
$abstract = $this->normalize($abstract);
return isset($this->bindings[$abstract]) || isset($this->instances[$abstract]) || $this->isAlias($abstract);
}
/**
* Determine if the given abstract type has been resolved.
*
* @param string $abstract
* @return bool
*/
public function resolved($abstract)
{
$abstract = $this->normalize($abstract);
if ($this->isAlias($abstract)) {
$abstract = $this->getAlias($abstract);
}
return isset($this->resolved[$abstract]) || isset($this->instances[$abstract]);
}
/**
* Determine if a given string is an alias.
*
* @param string $name
* @return bool
*/
public function isAlias($name)
{
return isset($this->aliases[$this->normalize($name)]);
}
/**
* Register a binding with the container.
*
* @param string|array $abstract
* @param \Closure|string|null $concrete
* @param bool $shared
* @return void
*/
public function bind($abstract, $concrete = null, $shared = false)
{
$abstract = $this->normalize($abstract);
$concrete = $this->normalize($concrete);
// If the given types are actually an array, we will assume an alias is being
// defined and will grab this "real" abstract class name and register this
// alias with the container so that it can be used as a shortcut for it.
if (is_array($abstract)) {
list($abstract, $alias) = $this->extractAlias($abstract);
$this->alias($abstract, $alias);
}
// If no concrete type was given, we will simply set the concrete type to the
// abstract type. This will allow concrete type to be registered as shared
// without being forced to state their classes in both of the parameter.
$this->dropStaleInstances($abstract);
if (is_null($concrete)) {
$concrete = $abstract;
}
// If the factory is not a Closure, it means it is just a class name which is
// bound into this container to the abstract type and we will just wrap it
// up inside its own Closure to give us more convenience when extending.
if (! $concrete instanceof Closure) {
$concrete = $this->getClosure($abstract, $concrete);
}
$this->bindings[$abstract] = compact('concrete', 'shared');
// If the abstract type was already resolved in this container we'll fire the
// rebound listener so that any objects which have already gotten resolved
// can have their copy of the object updated via the listener callbacks.
if ($this->resolved($abstract)) {
$this->rebound($abstract);
}
}
/**
* Get the Closure to be used when building a type.
*
* @param string $abstract
* @param string $concrete
* @return \Closure
*/
protected function getClosure($abstract, $concrete)
{
return function ($c, $parameters = []) use ($abstract, $concrete) {
$method = ($abstract == $concrete) ? 'build' : 'make';
return $c->$method($concrete, $parameters);
};
}
/**
* Add a contextual binding to the container.
*
* @param string $concrete
* @param string $abstract
* @param \Closure|string $implementation
* @return void
*/
public function addContextualBinding($concrete, $abstract, $implementation)
{
$this->contextual[$this->normalize($concrete)][$this->normalize($abstract)] = $this->normalize($implementation);
}
/**
* Register a binding if it hasn't already been registered.
*
* @param string $abstract
* @param \Closure|string|null $concrete
* @param bool $shared
* @return void
*/
public function bindIf($abstract, $concrete = null, $shared = false)
{
if (! $this->bound($abstract)) {
$this->bind($abstract, $concrete, $shared);
}
}
/**
* Register a shared binding in the container.
*
* @param string|array $abstract
* @param \Closure|string|null $concrete
* @return void
*/
public function singleton($abstract, $concrete = null)
{
$this->bind($abstract, $concrete, true);
}
/**
* Wrap a Closure such that it is shared.
*
* @param \Closure $closure
* @return \Closure
*/
public function share(Closure $closure)
{
return function ($container) use ($closure) {
// We'll simply declare a static variable within the Closures and if it has
// not been set we will execute the given Closures to resolve this value
// and return it back to these consumers of the method as an instance.
static $object;
if (is_null($object)) {
$object = $closure($container);
}
return $object;
};
}
/**
* "Extend" an abstract type in the container.
*
* @param string $abstract
* @param \Closure $closure
* @return void
*
* @throws \InvalidArgumentException
*/
public function extend($abstract, Closure $closure)
{
$abstract = $this->normalize($abstract);
if (isset($this->instances[$abstract])) {
$this->instances[$abstract] = $closure($this->instances[$abstract], $this);
$this->rebound($abstract);
} else {
$this->extenders[$abstract][] = $closure;
}
}
/**
* Register an existing instance as shared in the container.
*
* @param string $abstract
* @param mixed $instance
* @return void
*/
public function instance($abstract, $instance)
{
$abstract = $this->normalize($abstract);
// First, we will extract the alias from the abstract if it is an array so we
// are using the correct name when binding the type. If we get an alias it
// will be registered with the container so we can resolve it out later.
if (is_array($abstract)) {
list($abstract, $alias) = $this->extractAlias($abstract);
$this->alias($abstract, $alias);
}
unset($this->aliases[$abstract]);
// We'll check to determine if this type has been bound before, and if it has
// we will fire the rebound callbacks registered with the container and it
// can be updated with consuming classes that have gotten resolved here.
$bound = $this->bound($abstract);
$this->instances[$abstract] = $instance;
if ($bound) {
$this->rebound($abstract);
}
}
/**
* Assign a set of tags to a given binding.
*
* @param array|string $abstracts
* @param array|mixed ...$tags
* @return void
*/
public function tag($abstracts, $tags)
{
$tags = is_array($tags) ? $tags : array_slice(func_get_args(), 1);
foreach ($tags as $tag) {
if (! isset($this->tags[$tag])) {
$this->tags[$tag] = [];
}
foreach ((array) $abstracts as $abstract) {
$this->tags[$tag][] = $this->normalize($abstract);
}
}
}
/**
* Resolve all of the bindings for a given tag.
*
* @param string $tag
* @return array
*/
public function tagged($tag)
{
$results = [];
if (isset($this->tags[$tag])) {
foreach ($this->tags[$tag] as $abstract) {
$results[] = $this->make($abstract);
}
}
return $results;
}
/**
* Alias a type to a different name.
*
* @param string $abstract
* @param string $alias
* @return void
*/
public function alias($abstract, $alias)
{
$this->aliases[$alias] = $this->normalize($abstract);
}
/**
* Extract the type and alias from a given definition.
*
* @param array $definition
* @return array
*/
protected function extractAlias(array $definition)
{
return [key($definition), current($definition)];
}
/**
* Bind a new callback to an abstract's rebind event.
*
* @param string $abstract
* @param \Closure $callback
* @return mixed
*/
public function rebinding($abstract, Closure $callback)
{
$this->reboundCallbacks[$this->normalize($abstract)][] = $callback;
if ($this->bound($abstract)) {
return $this->make($abstract);
}
}
/**
* Refresh an instance on the given target and method.
*
* @param string $abstract
* @param mixed $target
* @param string $method
* @return mixed
*/
public function refresh($abstract, $target, $method)
{
return $this->rebinding($this->normalize($abstract), function ($app, $instance) use ($target, $method) {
$target->{$method}($instance);
});
}
/**
* Fire the "rebound" callbacks for the given abstract type.
*
* @param string $abstract
* @return void
*/
protected function rebound($abstract)
{
$instance = $this->make($abstract);
foreach ($this->getReboundCallbacks($abstract) as $callback) {
call_user_func($callback, $this, $instance);
}
}
/**
* Get the rebound callbacks for a given type.
*
* @param string $abstract
* @return array
*/
protected function getReboundCallbacks($abstract)
{
if (isset($this->reboundCallbacks[$abstract])) {
return $this->reboundCallbacks[$abstract];
}
return [];
}
/**
* Wrap the given closure such that its dependencies will be injected when executed.
*
* @param \Closure $callback
* @param array $parameters
* @return \Closure
*/
public function wrap(Closure $callback, array $parameters = [])
{
return function () use ($callback, $parameters) {
return $this->call($callback, $parameters);
};
}
/**
* Call the given Closure / class@method and inject its dependencies.
*
* @param callable|string $callback
* @param array $parameters
* @param string|null $defaultMethod
* @return mixed
*/
public function call($callback, array $parameters = [], $defaultMethod = null)
{
if ($this->isCallableWithAtSign($callback) || $defaultMethod) {
return $this->callClass($callback, $parameters, $defaultMethod);
}
$dependencies = $this->getMethodDependencies($callback, $parameters);
return call_user_func_array($callback, $dependencies);
}
/**
* Determine if the given string is in Class@method syntax.
*
* @param mixed $callback
* @return bool
*/
protected function isCallableWithAtSign($callback)
{
if (! is_string($callback)) {
return false;
}
return strpos($callback, '@') !== false;
}
/**
* Get all dependencies for a given method.
*
* @param callable|string $callback
* @param array $parameters
* @return array
*/
protected function getMethodDependencies($callback, array $parameters = [])
{
$dependencies = [];
foreach ($this->getCallReflector($callback)->getParameters() as $parameter) {
$this->addDependencyForCallParameter($parameter, $parameters, $dependencies);
}
return array_merge($dependencies, $parameters);
}
/**
* Get the proper reflection instance for the given callback.
*
* @param callable|string $callback
* @return \ReflectionFunctionAbstract
*/
protected function getCallReflector($callback)
{
if (is_string($callback) && strpos($callback, '::') !== false) {
$callback = explode('::', $callback);
}
if (is_array($callback)) {
return new ReflectionMethod($callback[0], $callback[1]);
}
return new ReflectionFunction($callback);
}
/**
* Get the dependency for the given call parameter.
*
* @param \ReflectionParameter $parameter
* @param array $parameters
* @param array $dependencies
* @return mixed
*/
protected function addDependencyForCallParameter(ReflectionParameter $parameter, array &$parameters, &$dependencies)
{
if (array_key_exists($parameter->name, $parameters)) {
$dependencies[] = $parameters[$parameter->name];
unset($parameters[$parameter->name]);
} elseif ($parameter->getClass()) {
$dependencies[] = $this->make($parameter->getClass()->name);
} elseif ($parameter->isDefaultValueAvailable()) {
$dependencies[] = $parameter->getDefaultValue();
}
}
/**
* Call a string reference to a class using Class@method syntax.
*
* @param string $target
* @param array $parameters
* @param string|null $defaultMethod
* @return mixed
*
* @throws \InvalidArgumentException
*/
protected function callClass($target, array $parameters = [], $defaultMethod = null)
{
$segments = explode('@', $target);
// If the listener has an @ sign, we will assume it is being used to delimit
// the class name from the handle method name. This allows for handlers
// to run multiple handler methods in a single class for convenience.
$method = count($segments) == 2 ? $segments[1] : $defaultMethod;
if (is_null($method)) {
throw new InvalidArgumentException('Method not provided.');
}
return $this->call([$this->make($segments[0]), $method], $parameters);
}
/**
* Resolve the given type from the container.
*
* @param string $abstract
* @param array $parameters
* @return mixed
*/
public function make($abstract, array $parameters = [])
{
$abstract = $this->getAlias($this->normalize($abstract));
// If an instance of the type is currently being managed as a singleton we'll
// just return an existing instance instead of instantiating new instances
// so the developer can keep using the same objects instance every time.
if (isset($this->instances[$abstract])) {
return $this->instances[$abstract];
}
$concrete = $this->getConcrete($abstract);
// We're ready to instantiate an instance of the concrete type registered for
// the binding. This will instantiate the types, as well as resolve any of
// its "nested" dependencies recursively until all have gotten resolved.
if ($this->isBuildable($concrete, $abstract)) {
$object = $this->build($concrete, $parameters);
} else {
$object = $this->make($concrete, $parameters);
}
// If we defined any extenders for this type, we'll need to spin through them
// and apply them to the object being built. This allows for the extension
// of services, such as changing configuration or decorating the object.
foreach ($this->getExtenders($abstract) as $extender) {
$object = $extender($object, $this);
}
// If the requested type is registered as a singleton we'll want to cache off
// the instances in "memory" so we can return it later without creating an
// entirely new instance of an object on each subsequent request for it.
if ($this->isShared($abstract)) {
$this->instances[$abstract] = $object;
}
$this->fireResolvingCallbacks($abstract, $object);
$this->resolved[$abstract] = true;
return $object;
}
/**
* Get the concrete type for a given abstract.
*
* @param string $abstract
* @return mixed $concrete
*/
protected function getConcrete($abstract)
{
if (! is_null($concrete = $this->getContextualConcrete($abstract))) {
return $concrete;
}
// If we don't have a registered resolver or concrete for the type, we'll just
// assume each type is a concrete name and will attempt to resolve it as is
// since the container should be able to resolve concretes automatically.
if (! isset($this->bindings[$abstract])) {
return $abstract;
}
return $this->bindings[$abstract]['concrete'];
}
/**
* Get the contextual concrete binding for the given abstract.
*
* @param string $abstract
* @return string|null
*/
protected function getContextualConcrete($abstract)
{
if (isset($this->contextual[end($this->buildStack)][$abstract])) {
return $this->contextual[end($this->buildStack)][$abstract];
}
}
/**
* Normalize the given class name by removing leading slashes.
*
* @param mixed $service
* @return mixed
*/
protected function normalize($service)
{
return is_string($service) ? ltrim($service, '\\') : $service;
}
/**
* Get the extender callbacks for a given type.
*
* @param string $abstract
* @return array
*/
protected function getExtenders($abstract)
{
if (isset($this->extenders[$abstract])) {
return $this->extenders[$abstract];
}
return [];
}
/**
* Instantiate a concrete instance of the given type.
*
* @param string $concrete
* @param array $parameters
* @return mixed
*
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
public function build($concrete, array $parameters = [])
{
// If the concrete type is actually a Closure, we will just execute it and
// hand back the results of the functions, which allows functions to be
// used as resolvers for more fine-tuned resolution of these objects.
if ($concrete instanceof Closure) {
return $concrete($this, $parameters);
}
$reflector = new ReflectionClass($concrete);
// If the type is not instantiable, the developer is attempting to resolve
// an abstract type such as an Interface of Abstract Class and there is
// no binding registered for the abstractions so we need to bail out.
if (! $reflector->isInstantiable()) {
if (! empty($this->buildStack)) {
$previous = implode(', ', $this->buildStack);
$message = "Target [$concrete] is not instantiable while building [$previous].";
} else {
$message = "Target [$concrete] is not instantiable.";
}
throw new BindingResolutionException($message);
}
$this->buildStack[] = $concrete;
$constructor = $reflector->getConstructor();
// If there are no constructors, that means there are no dependencies then
// we can just resolve the instances of the objects right away, without
// resolving any other types or dependencies out of these containers.
if (is_null($constructor)) {
array_pop($this->buildStack);
return new $concrete;
}
$dependencies = $constructor->getParameters();
// Once we have all the constructor's parameters we can create each of the
// dependency instances and then use the reflection instances to make a
// new instance of this class, injecting the created dependencies in.
$parameters = $this->keyParametersByArgument(
$dependencies, $parameters
);
$instances = $this->getDependencies(
$dependencies, $parameters
);
array_pop($this->buildStack);
return $reflector->newInstanceArgs($instances);
}
/**
* Resolve all of the dependencies from the ReflectionParameters.
*
* @param array $parameters
* @param array $primitives
* @return array
*/
protected function getDependencies(array $parameters, array $primitives = [])
{
$dependencies = [];
foreach ($parameters as $parameter) {
$dependency = $parameter->getClass();
// If the class is null, it means the dependency is a string or some other
// primitive type which we can not resolve since it is not a class and
// we will just bomb out with an error since we have no-where to go.
if (array_key_exists($parameter->name, $primitives)) {
$dependencies[] = $primitives[$parameter->name];
} elseif (is_null($dependency)) {
$dependencies[] = $this->resolveNonClass($parameter);
} else {
$dependencies[] = $this->resolveClass($parameter);
}
}
return $dependencies;
}
/**
* Resolve a non-class hinted dependency.
*
* @param \ReflectionParameter $parameter
* @return mixed
*
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
protected function resolveNonClass(ReflectionParameter $parameter)
{
if (! is_null($concrete = $this->getContextualConcrete('$'.$parameter->name))) {
if ($concrete instanceof Closure) {
return call_user_func($concrete, $this);
} else {
return $concrete;
}
}
if ($parameter->isDefaultValueAvailable()) {
return $parameter->getDefaultValue();
}
$message = "Unresolvable dependency resolving [$parameter] in class {$parameter->getDeclaringClass()->getName()}";
throw new BindingResolutionException($message);
}
/**
* Resolve a class based dependency from the container.
*
* @param \ReflectionParameter $parameter
* @return mixed
*
* @throws \Illuminate\Contracts\Container\BindingResolutionException
*/
protected function resolveClass(ReflectionParameter $parameter)
{
try {
return $this->make($parameter->getClass()->name);
}
// If we can not resolve the class instance, we will check to see if the value
// is optional, and if it is we will return the optional parameter value as
// the value of the dependency, similarly to how we do this with scalars.
catch (BindingResolutionException $e) {
if ($parameter->isOptional()) {
return $parameter->getDefaultValue();
}
throw $e;
}
}
/**
* If extra parameters are passed by numeric ID, rekey them by argument name.
*
* @param array $dependencies
* @param array $parameters
* @return array
*/
protected function keyParametersByArgument(array $dependencies, array $parameters)
{
foreach ($parameters as $key => $value) {
if (is_numeric($key)) {
unset($parameters[$key]);
$parameters[$dependencies[$key]->name] = $value;
}
}
return $parameters;
}
/**
* Register a new resolving callback.
*
* @param string $abstract
* @param \Closure|null $callback
* @return void
*/
public function resolving($abstract, Closure $callback = null)
{
if ($callback === null && $abstract instanceof Closure) {
$this->resolvingCallback($abstract);
} else {
$this->resolvingCallbacks[$this->normalize($abstract)][] = $callback;
}
}
/**
* Register a new after resolving callback for all types.
*
* @param string $abstract
* @param \Closure|null $callback
* @return void
*/
public function afterResolving($abstract, Closure $callback = null)
{
if ($abstract instanceof Closure && $callback === null) {
$this->afterResolvingCallback($abstract);
} else {
$this->afterResolvingCallbacks[$this->normalize($abstract)][] = $callback;
}
}
/**
* Register a new resolving callback by type of its first argument.
*
* @param \Closure $callback
* @return void
*/
protected function resolvingCallback(Closure $callback)
{
$abstract = $this->getFunctionHint($callback);
if ($abstract) {
$this->resolvingCallbacks[$abstract][] = $callback;
} else {
$this->globalResolvingCallbacks[] = $callback;
}
}
/**
* Register a new after resolving callback by type of its first argument.
*
* @param \Closure $callback
* @return void
*/
protected function afterResolvingCallback(Closure $callback)
{
$abstract = $this->getFunctionHint($callback);
if ($abstract) {
$this->afterResolvingCallbacks[$abstract][] = $callback;
} else {
$this->globalAfterResolvingCallbacks[] = $callback;
}
}
/**
* Get the type hint for this closure's first argument.
*
* @param \Closure $callback
* @return mixed
*/
protected function getFunctionHint(Closure $callback)
{
$function = new ReflectionFunction($callback);
if ($function->getNumberOfParameters() == 0) {
return;
}
$expected = $function->getParameters()[0];
if (! $expected->getClass()) {
return;
}
return $expected->getClass()->name;
}
/**
* Fire all of the resolving callbacks.
*
* @param string $abstract
* @param mixed $object
* @return void
*/
protected function fireResolvingCallbacks($abstract, $object)
{
$this->fireCallbackArray($object, $this->globalResolvingCallbacks);
$this->fireCallbackArray(
$object, $this->getCallbacksForType(
$abstract, $object, $this->resolvingCallbacks
)
);
$this->fireCallbackArray($object, $this->globalAfterResolvingCallbacks);
$this->fireCallbackArray(
$object, $this->getCallbacksForType(
$abstract, $object, $this->afterResolvingCallbacks
)
);
}
/**
* Get all callbacks for a given type.
*
* @param string $abstract
* @param object $object
* @param array $callbacksPerType
*
* @return array
*/
protected function getCallbacksForType($abstract, $object, array $callbacksPerType)
{
$results = [];
foreach ($callbacksPerType as $type => $callbacks) {
if ($type === $abstract || $object instanceof $type) {
$results = array_merge($results, $callbacks);
}
}
return $results;
}
/**
* Fire an array of callbacks with an object.
*
* @param mixed $object
* @param array $callbacks
* @return void
*/
protected function fireCallbackArray($object, array $callbacks)
{
foreach ($callbacks as $callback) {
$callback($object, $this);
}
}
/**
* Determine if a given type is shared.
*
* @param string $abstract
* @return bool
*/
public function isShared($abstract)
{
$abstract = $this->normalize($abstract);
if (isset($this->instances[$abstract])) {
return true;
}
if (! isset($this->bindings[$abstract]['shared'])) {
return false;
}
return $this->bindings[$abstract]['shared'] === true;
}
/**
* Determine if the given concrete is buildable.
*
* @param mixed $concrete
* @param string $abstract
* @return bool
*/
protected function isBuildable($concrete, $abstract)
{
return $concrete === $abstract || $concrete instanceof Closure;
}
/**
* Get the alias for an abstract if available.
*
* @param string $abstract
* @return string
*/
protected function getAlias($abstract)
{
return isset($this->aliases[$abstract]) ? $this->aliases[$abstract] : $abstract;
}
/**
* Get the container's bindings.
*
* @return array
*/
public function getBindings()
{
return $this->bindings;
}
/**
* Drop all of the stale instances and aliases.
*
* @param string $abstract
* @return void
*/
protected function dropStaleInstances($abstract)
{
unset($this->instances[$abstract], $this->aliases[$abstract]);
}
/**
* Remove a resolved instance from the instance cache.
*
* @param string $abstract
* @return void
*/
public function forgetInstance($abstract)
{
unset($this->instances[$this->normalize($abstract)]);
}
/**
* Clear all of the instances from the container.
*
* @return void
*/
public function forgetInstances()
{
$this->instances = [];
}
/**
* Flush the container of all bindings and resolved instances.
*
* @return void
*/
public function flush()
{
$this->aliases = [];
$this->resolved = [];
$this->bindings = [];
$this->instances = [];
}
/**
* Set the globally available instance of the container.
*
* @return static
*/
public static function getInstance()
{
return static::$instance;
}
/**
* Set the shared instance of the container.
*
* @param \Illuminate\Contracts\Container\Container $container
* @return void
*/
public static function setInstance(ContainerContract $container)
{
static::$instance = $container;
}
/**
* Determine if a given offset exists.
*
* @param string $key
* @return bool
*/
public function offsetExists($key)
{
return $this->bound($key);
}
/**
* Get the value at a given offset.
*
* @param string $key
* @return mixed
*/
public function offsetGet($key)
{
return $this->make($key);
}
/**
* Set the value at a given offset.
*
* @param string $key
* @param mixed $value
* @return void
*/
public function offsetSet($key, $value)
{
// If the value is not a Closure, we will make it one. This simply gives
// more "drop-in" replacement functionality for the Pimple which this
// container's simplest functions are base modeled and built after.
if (! $value instanceof Closure) {
$value = function () use ($value) {
return $value;
};
}
$this->bind($key, $value);
}
/**
* Unset the value at a given offset.
*
* @param string $key
* @return void
*/
public function offsetUnset($key)
{
$key = $this->normalize($key);
unset($this->bindings[$key], $this->instances[$key], $this->resolved[$key]);
}
/**
* Dynamically access container services.
*
* @param string $key
* @return mixed
*/
public function __get($key)
{
return $this[$key];
}
/**
* Dynamically set container services.
*
* @param string $key
* @param mixed $value
* @return void
*/
public function __set($key, $value)
{
$this[$key] = $value;
}
}
<?php
namespace Illuminate\Container;
use Illuminate\Contracts\Container\ContextualBindingBuilder as ContextualBindingBuilderContract;
class ContextualBindingBuilder implements ContextualBindingBuilderContract
{
/**
* The underlying container instance.
*
* @var \Illuminate\Container\Container
*/
protected $container;
/**
* The concrete instance.
*
* @var string
*/
protected $concrete;
/**
* The abstract target.
*
* @var string
*/
protected $needs;
/**
* Create a new contextual binding builder.
*
* @param \Illuminate\Container\Container $container
* @param string $concrete
* @return void
*/
public function __construct(Container $container, $concrete)
{
$this->concrete = $concrete;
$this->container = $container;
}
/**
* Define the abstract target that depends on the context.
*
* @param string $abstract
* @return $this
*/
public function needs($abstract)
{
$this->needs = $abstract;
return $this;
}
/**
* Define the implementation for the contextual binding.
*
* @param \Closure|string $implementation
* @return void
*/
public function give($implementation)
{
$this->container->addContextualBinding($this->concrete, $this->needs, $implementation);
}
}
<?php
namespace Illuminate\Contracts\Auth\Access;
interface Authorizable
{
/**
* Determine if the entity has a given ability.
*
* @param string $ability
* @param array|mixed $arguments
* @return bool
*/
public function can($ability, $arguments = []);
}
<?php
namespace Illuminate\Contracts\Auth\Access;
interface Gate
{
/**
* Determine if a given ability has been defined.
*
* @param string $ability
* @return bool
*/
public function has($ability);
/**
* Define a new ability.
*
* @param string $ability
* @param callable|string $callback
* @return $this
*/
public function define($ability, $callback);
/**
* Define a policy class for a given class type.
*
* @param string $class
* @param string $policy
* @return $this
*/
public function policy($class, $policy);
/**
* Register a callback to run before all Gate checks.
*
* @param callable $callback
* @return $this
*/
public function before(callable $callback);
/**
* Determine if the given ability should be granted for the current user.
*
* @param string $ability
* @param array|mixed $arguments
* @return bool
*/
public function allows($ability, $arguments = []);
/**
* Determine if the given ability should be denied for the current user.
*
* @param string $ability
* @param array|mixed $arguments
* @return bool
*/
public function denies($ability, $arguments = []);
/**
* Determine if the given ability should be granted.
*
* @param string $ability
* @param array|mixed $arguments
* @return bool
*/
public function check($ability, $arguments = []);
/**
* Get a guard instance for the given user.
*
* @param \Illuminate\Contracts\Auth\Authenticatable|mixed $user
* @return static
*/
public function forUser($user);
}
<?php
namespace Illuminate\Contracts\Auth;
interface Authenticatable
{
/**
* Get the name of the unique identifier for the user.
*
* @return string
*/
public function getAuthIdentifierName();
/**
* Get the unique identifier for the user.
*
* @return mixed
*/
public function getAuthIdentifier();
/**
* Get the password for the user.
*
* @return string
*/
public function getAuthPassword();
/**
* Get the token value for the "remember me" session.
*
* @return string
*/
public function getRememberToken();
/**
* Set the token value for the "remember me" session.
*
* @param string $value
* @return void
*/
public function setRememberToken($value);
/**
* Get the column name for the "remember me" token.
*
* @return string
*/
public function getRememberTokenName();
}
<?php
namespace Illuminate\Contracts\Auth;
interface CanResetPassword
{
/**
* Get the e-mail address where password reset links are sent.
*
* @return string
*/
public function getEmailForPasswordReset();
}
<?php
namespace Illuminate\Contracts\Auth;
interface Factory
{
/**
* Get a guard instance by name.
*
* @param string|null $name
* @return mixed
*/
public function guard($name = null);
/**
* Set the default guard the factory should serve.
*
* @param string $name
* @return void
*/
public function shouldUse($name);
}
<?php
namespace Illuminate\Contracts\Auth;
interface Guard
{
/**
* Determine if the current user is authenticated.
*
* @return bool
*/
public function check();
/**
* Determine if the current user is a guest.
*
* @return bool
*/
public function guest();
/**
* Get the currently authenticated user.
*
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function user();
/**
* Get the ID for the currently authenticated user.
*
* @return int|null
*/
public function id();
/**
* Validate a user's credentials.
*
* @param array $credentials
* @return bool
*/
public function validate(array $credentials = []);
/**
* Set the current user.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @return void
*/
public function setUser(Authenticatable $user);
}
<?php
namespace Illuminate\Contracts\Auth;
use Closure;
interface PasswordBroker
{
/**
* Constant representing a successfully sent reminder.
*
* @var string
*/
const RESET_LINK_SENT = 'passwords.sent';
/**
* Constant representing a successfully reset password.
*
* @var string
*/
const PASSWORD_RESET = 'passwords.reset';
/**
* Constant representing the user not found response.
*
* @var string
*/
const INVALID_USER = 'passwords.user';
/**
* Constant representing an invalid password.
*
* @var string
*/
const INVALID_PASSWORD = 'passwords.password';
/**
* Constant representing an invalid token.
*
* @var string
*/
const INVALID_TOKEN = 'passwords.token';
/**
* Send a password reset link to a user.
*
* @param array $credentials
* @param \Closure|null $callback
* @return string
*/
public function sendResetLink(array $credentials, Closure $callback = null);
/**
* Reset the password for the given token.
*
* @param array $credentials
* @param \Closure $callback
* @return mixed
*/
public function reset(array $credentials, Closure $callback);
/**
* Set a custom password validator.
*
* @param \Closure $callback
* @return void
*/
public function validator(Closure $callback);
/**
* Determine if the passwords match for the request.
*
* @param array $credentials
* @return bool
*/
public function validateNewPassword(array $credentials);
}
<?php
namespace Illuminate\Contracts\Auth;
interface PasswordBrokerFactory
{
/**
* Get a password broker instance by name.
*
* @param string|null $name
* @return mixed
*/
public function broker($name = null);
}
<?php
namespace Illuminate\Contracts\Auth;
interface Registrar
{
/**
* Get a validator for an incoming registration request.
*
* @param array $data
* @return \Illuminate\Contracts\Validation\Validator
*/
public function validator(array $data);
/**
* Create a new user instance after a valid registration.
*
* @param array $data
* @return \Illuminate\Contracts\Auth\Authenticatable
*/
public function create(array $data);
}
<?php
namespace Illuminate\Contracts\Auth;
interface StatefulGuard extends Guard
{
/**
* Attempt to authenticate a user using the given credentials.
*
* @param array $credentials
* @param bool $remember
* @param bool $login
* @return bool
*/
public function attempt(array $credentials = [], $remember = false, $login = true);
/**
* Log a user into the application without sessions or cookies.
*
* @param array $credentials
* @return bool
*/
public function once(array $credentials = []);
/**
* Log a user into the application.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param bool $remember
* @return void
*/
public function login(Authenticatable $user, $remember = false);
/**
* Log the given user ID into the application.
*
* @param mixed $id
* @param bool $remember
* @return \Illuminate\Contracts\Auth\Authenticatable
*/
public function loginUsingId($id, $remember = false);
/**
* Log the given user ID into the application without sessions or cookies.
*
* @param mixed $id
* @return bool
*/
public function onceUsingId($id);
/**
* Determine if the user was authenticated via "remember me" cookie.
*
* @return bool
*/
public function viaRemember();
/**
* Log the user out of the application.
*
* @return void
*/
public function logout();
}
<?php
namespace Illuminate\Contracts\Auth;
interface SupportsBasicAuth
{
/**
* Attempt to authenticate using HTTP Basic Auth.
*
* @param string $field
* @param array $extraConditions
* @return \Symfony\Component\HttpFoundation\Response|null
*/
public function basic($field = 'email', $extraConditions = []);
/**
* Perform a stateless HTTP Basic login attempt.
*
* @param string $field
* @param array $extraConditions
* @return \Symfony\Component\HttpFoundation\Response|null
*/
public function onceBasic($field = 'email', $extraConditions = []);
}
<?php
namespace Illuminate\Contracts\Auth;
interface UserProvider
{
/**
* Retrieve a user by their unique identifier.
*
* @param mixed $identifier
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveById($identifier);
/**
* Retrieve a user by their unique identifier and "remember me" token.
*
* @param mixed $identifier
* @param string $token
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveByToken($identifier, $token);
/**
* Update the "remember me" token for the given user in storage.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param string $token
* @return void
*/
public function updateRememberToken(Authenticatable $user, $token);
/**
* Retrieve a user by the given credentials.
*
* @param array $credentials
* @return \Illuminate\Contracts\Auth\Authenticatable|null
*/
public function retrieveByCredentials(array $credentials);
/**
* Validate a user against the given credentials.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param array $credentials
* @return bool
*/
public function validateCredentials(Authenticatable $user, array $credentials);
}
<?php
namespace Illuminate\Contracts\Broadcasting;
interface Broadcaster
{
/**
* Broadcast the given event.
*
* @param array $channels
* @param string $event
* @param array $payload
* @return void
*/
public function broadcast(array $channels, $event, array $payload = []);
}
<?php
namespace Illuminate\Contracts\Broadcasting;
interface Factory
{
/**
* Get a broadcaster implementation by name.
*
* @param string $name
* @return void
*/
public function connection($name = null);
}
<?php
namespace Illuminate\Contracts\Broadcasting;
interface ShouldBroadcast
{
/**
* Get the channels the event should broadcast on.
*
* @return array
*/
public function broadcastOn();
}
<?php
namespace Illuminate\Contracts\Broadcasting;
interface ShouldBroadcastNow extends ShouldBroadcast
{
//
}
<?php
namespace Illuminate\Contracts\Bus;
interface Dispatcher
{
/**
* Dispatch a command to its appropriate handler.
*
* @param mixed $command
* @param \Closure|null $afterResolving
* @return mixed
*/
public function dispatch($command);
/**
* Dispatch a command to its appropriate handler in the current process.
*
* @param mixed $command
* @param \Closure|null $afterResolving
* @return mixed
*/
public function dispatchNow($command);
/**
* Set the pipes commands should be piped through before dispatching.
*
* @param array $pipes
* @return $this
*/
public function pipeThrough(array $pipes);
}
<?php
namespace Illuminate\Contracts\Bus;
interface QueueingDispatcher extends Dispatcher
{
/**
* Dispatch a command to its appropriate handler behind a queue.
*
* @param mixed $command
* @return mixed
*/
public function dispatchToQueue($command);
}
<?php
namespace Illuminate\Contracts\Bus;
/**
* @deprecated since version 5.2. Remove from jobs since self-handling is default.
*/
interface SelfHandling
{
//
}
<?php
namespace Illuminate\Contracts\Cache;
interface Factory
{
/**
* Get a cache store instance by name.
*
* @param string|null $name
* @return mixed
*/
public function store($name = null);
}
<?php
namespace Illuminate\Contracts\Cache;
use Closure;
interface Repository
{
/**
* Determine if an item exists in the cache.
*
* @param string $key
* @return bool
*/
public function has($key);
/**
* Retrieve an item from the cache by key.
*
* @param string $key
* @param mixed $default
* @return mixed
*/
public function get($key, $default = null);
/**
* Retrieve an item from the cache and delete it.
*
* @param string $key
* @param mixed $default
* @return mixed
*/
public function pull($key, $default = null);
/**
* Store an item in the cache.
*
* @param string $key
* @param mixed $value
* @param \DateTime|int $minutes
* @return void
*/
public function put($key, $value, $minutes);
/**
* Store an item in the cache if the key does not exist.
*
* @param string $key
* @param mixed $value
* @param \DateTime|int $minutes
* @return bool
*/
public function add($key, $value, $minutes);
/**
* Store an item in the cache indefinitely.
*
* @param string $key
* @param mixed $value
* @return void
*/
public function forever($key, $value);
/**
* Get an item from the cache, or store the default value.
*
* @param string $key
* @param \DateTime|int $minutes
* @param \Closure $callback
* @return mixed
*/
public function remember($key, $minutes, Closure $callback);
/**
* Get an item from the cache, or store the default value forever.
*
* @param string $key
* @param \Closure $callback
* @return mixed
*/
public function sear($key, Closure $callback);
/**
* Get an item from the cache, or store the default value forever.
*
* @param string $key
* @param \Closure $callback
* @return mixed
*/
public function rememberForever($key, Closure $callback);
/**
* Remove an item from the cache.
*
* @param string $key
* @return bool
*/
public function forget($key);
}
<?php
namespace Illuminate\Contracts\Cache;
interface Store
{
/**
* Retrieve an item from the cache by key.
*
* @param string|array $key
* @return mixed
*/
public function get($key);
/**
* Retrieve multiple items from the cache by key.
*
* Items not found in the cache will have a null value.
*
* @param array $keys
* @return array
*/
public function many(array $keys);
/**
* Store an item in the cache for a given number of minutes.
*
* @param string $key
* @param mixed $value
* @param int $minutes
* @return void
*/
public function put($key, $value, $minutes);
/**
* Store multiple items in the cache for a given number of minutes.
*
* @param array $values
* @param int $minutes
* @return void
*/
public function putMany(array $values, $minutes);
/**
* Increment the value of an item in the cache.
*
* @param string $key
* @param mixed $value
* @return int|bool
*/
public function increment($key, $value = 1);
/**
* Decrement the value of an item in the cache.
*
* @param string $key
* @param mixed $value
* @return int|bool
*/
public function decrement($key, $value = 1);
/**
* Store an item in the cache indefinitely.
*
* @param string $key
* @param mixed $value
* @return void
*/
public function forever($key, $value);
/**
* Remove an item from the cache.
*
* @param string $key
* @return bool
*/
public function forget($key);
/**
* Remove all items from the cache.
*
* @return void
*/
public function flush();
/**
* Get the cache key prefix.
*
* @return string
*/
public function getPrefix();
}
{
"name": "illuminate/contracts",
"description": "The Illuminate Contracts package.",
"license": "MIT",
"homepage": "http://laravel.com",
"support": {
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"authors": [
{
"name": "Taylor Otwell",
"email": "taylorotwell@gmail.com"
}
],
"require": {
"php": ">=5.5.9"
},
"autoload": {
"psr-4": {
"Illuminate\\Contracts\\": ""
}
},
"extra": {
"branch-alias": {
"dev-master": "5.2-dev"
}
},
"minimum-stability": "dev"
}
<?php
namespace Illuminate\Contracts\Config;
interface Repository
{
/**
* Determine if the given configuration value exists.
*
* @param string $key
* @return bool
*/
public function has($key);
/**
* Get the specified configuration value.
*
* @param string $key
* @param mixed $default
* @return mixed
*/
public function get($key, $default = null);
/**
* Get all of the configuration items for the application.
*
* @return array
*/
public function all();
/**
* Set a given configuration value.
*
* @param array|string $key
* @param mixed $value
* @return void
*/
public function set($key, $value = null);
/**
* Prepend a value onto an array configuration value.
*
* @param string $key
* @param mixed $value
* @return void
*/
public function prepend($key, $value);
/**
* Push a value onto an array configuration value.
*
* @param string $key
* @param mixed $value
* @return void
*/
public function push($key, $value);
}
<?php
namespace Illuminate\Contracts\Console;
interface Application
{
/**
* Call a console application command.
*
* @param string $command
* @param array $parameters
* @return int
*/
public function call($command, array $parameters = []);
/**
* Get the output from the last command.
*
* @return string
*/
public function output();
}
<?php
namespace Illuminate\Contracts\Console;
interface Kernel
{
/**
* Handle an incoming console command.
*
* @param \Symfony\Component\Console\Input\InputInterface $input
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @return int
*/
public function handle($input, $output = null);
/**
* Run an Artisan console command by name.
*
* @param string $command
* @param array $parameters
* @return int
*/
public function call($command, array $parameters = []);
/**
* Queue an Artisan console command by name.
*
* @param string $command
* @param array $parameters
* @return int
*/
public function queue($command, array $parameters = []);
/**
* Get all of the commands registered with the console.
*
* @return array
*/
public function all();
/**
* Get the output for the last run command.
*
* @return string
*/
public function output();
}
<?php
namespace Illuminate\Contracts\Container;
use Exception;
class BindingResolutionException extends Exception
{
//
}
<?php
namespace Illuminate\Contracts\Container;
use Closure;
interface Container
{
/**
* Determine if the given abstract type has been bound.
*
* @param string $abstract
* @return bool
*/
public function bound($abstract);
/**
* Alias a type to a different name.
*
* @param string $abstract
* @param string $alias
* @return void
*/
public function alias($abstract, $alias);
/**
* Assign a set of tags to a given binding.
*
* @param array|string $abstracts
* @param array|mixed ...$tags
* @return void
*/
public function tag($abstracts, $tags);
/**
* Resolve all of the bindings for a given tag.
*
* @param array $tag
* @return array
*/
public function tagged($tag);
/**
* Register a binding with the container.
*
* @param string|array $abstract
* @param \Closure|string|null $concrete
* @param bool $shared
* @return void
*/
public function bind($abstract, $concrete = null, $shared = false);
/**
* Register a binding if it hasn't already been registered.
*
* @param string $abstract
* @param \Closure|string|null $concrete
* @param bool $shared
* @return void
*/
public function bindIf($abstract, $concrete = null, $shared = false);
/**
* Register a shared binding in the container.
*
* @param string|array $abstract
* @param \Closure|string|null $concrete
* @return void
*/
public function singleton($abstract, $concrete = null);
/**
* "Extend" an abstract type in the container.
*
* @param string $abstract
* @param \Closure $closure
* @return void
*
* @throws \InvalidArgumentException
*/
public function extend($abstract, Closure $closure);
/**
* Register an existing instance as shared in the container.
*
* @param string $abstract
* @param mixed $instance
* @return void
*/
public function instance($abstract, $instance);
/**
* Define a contextual binding.
*
* @param string $concrete
* @return \Illuminate\Contracts\Container\ContextualBindingBuilder
*/
public function when($concrete);
/**
* Resolve the given type from the container.
*
* @param string $abstract
* @param array $parameters
* @return mixed
*/
public function make($abstract, array $parameters = []);
/**
* Call the given Closure / class@method and inject its dependencies.
*
* @param callable|string $callback
* @param array $parameters
* @param string|null $defaultMethod
* @return mixed
*/
public function call($callback, array $parameters = [], $defaultMethod = null);
/**
* Determine if the given abstract type has been resolved.
*
* @param string $abstract
* @return bool
*/
public function resolved($abstract);
/**
* Register a new resolving callback.
*
* @param string $abstract
* @param \Closure|null $callback
* @return void
*/
public function resolving($abstract, Closure $callback = null);
/**
* Register a new after resolving callback.
*
* @param string $abstract
* @param \Closure|null $callback
* @return void
*/
public function afterResolving($abstract, Closure $callback = null);
}
<?php
namespace Illuminate\Contracts\Container;
interface ContextualBindingBuilder
{
/**
* Define the abstract target that depends on the context.
*
* @param string $abstract
* @return $this
*/
public function needs($abstract);
/**
* Define the implementation for the contextual binding.
*
* @param \Closure|string $implementation
* @return void
*/
public function give($implementation);
}
<?php
namespace Illuminate\Contracts\Database;
class ModelIdentifier
{
/**
* The class name of the model.
*
* @var string
*/
public $class;
/**
* The unique identifier of the model.
*
* @var mixed
*/
public $id;
/**
* Create a new model identifier.
*
* @param string $class
* @param mixed $id
* @return void
*/
public function __construct($class, $id)
{
$this->id = $id;
$this->class = $class;
}
}
<?php
namespace Illuminate\Contracts\Debug;
use Exception;
interface ExceptionHandler
{
/**
* Report or log an exception.
*
* @param \Exception $e
* @return void
*/
public function report(Exception $e);
/**
* Render an exception into an HTTP response.
*
* @param \Illuminate\Http\Request $request
* @param \Exception $e
* @return \Symfony\Component\HttpFoundation\Response
*/
public function render($request, Exception $e);
/**
* Render an exception to the console.
*
* @param \Symfony\Component\Console\Output\OutputInterface $output
* @param \Exception $e
* @return void
*/
public function renderForConsole($output, Exception $e);
}
<?php
namespace Illuminate\Contracts\Encryption;
use RuntimeException;
class DecryptException extends RuntimeException
{
//
}
<?php
namespace Illuminate\Contracts\Encryption;
interface Encrypter
{
/**
* Encrypt the given value.
*
* @param string $value
* @return string
*/
public function encrypt($value);
/**
* Decrypt the given value.
*
* @param string $payload
* @return string
*/
public function decrypt($payload);
}
<?php
namespace Illuminate\Contracts\Encryption;
use RuntimeException;
class EncryptException extends RuntimeException
{
//
}
<?php
namespace Illuminate\Contracts\Events;
interface Dispatcher
{
/**
* Register an event listener with the dispatcher.
*
* @param string|array $events
* @param mixed $listener
* @param int $priority
* @return void
*/
public function listen($events, $listener, $priority = 0);
/**
* Determine if a given event has listeners.
*
* @param string $eventName
* @return bool
*/
public function hasListeners($eventName);
/**
* Register an event and payload to be fired later.
*
* @param string $event
* @param array $payload
* @return void
*/
public function push($event, $payload = []);
/**
* Register an event subscriber with the dispatcher.
*
* @param object|string $subscriber
* @return void
*/
public function subscribe($subscriber);
/**
* Fire an event until the first non-null response is returned.
*
* @param string $event
* @param array $payload
* @return mixed
*/
public function until($event, $payload = []);
/**
* Flush a set of pushed events.
*
* @param string $event
* @return void
*/
public function flush($event);
/**
* Fire an event and call the listeners.
*
* @param string|object $event
* @param mixed $payload
* @param bool $halt
* @return array|null
*/
public function fire($event, $payload = [], $halt = false);
/**
* Get the event that is currently firing.
*
* @return string
*/
public function firing();
/**
* Remove a set of listeners from the dispatcher.
*
* @param string $event
* @return void
*/
public function forget($event);
/**
* Forget all of the queued listeners.
*
* @return void
*/
public function forgetPushed();
}
<?php
namespace Illuminate\Contracts\Filesystem;
interface Cloud extends Filesystem
{
//
}
<?php
namespace Illuminate\Contracts\Filesystem;
interface Factory
{
/**
* Get a filesystem implementation.
*
* @param string $name
* @return \Illuminate\Contracts\Filesystem\Filesystem
*/
public function disk($name = null);
}
<?php
namespace Illuminate\Contracts\Filesystem;
use Exception;
class FileNotFoundException extends Exception
{
//
}
<?php
namespace Illuminate\Contracts\Filesystem;
interface Filesystem
{
/**
* The public visibility setting.
*
* @var string
*/
const VISIBILITY_PUBLIC = 'public';
/**
* The private visibility setting.
*
* @var string
*/
const VISIBILITY_PRIVATE = 'private';
/**
* Determine if a file exists.
*
* @param string $path
* @return bool
*/
public function exists($path);
/**
* Get the contents of a file.
*
* @param string $path
* @return string
*
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*/
public function get($path);
/**
* Write the contents of a file.
*
* @param string $path
* @param string|resource $contents
* @param string $visibility
* @return bool
*/
public function put($path, $contents, $visibility = null);
/**
* Get the visibility for the given path.
*
* @param string $path
* @return string
*/
public function getVisibility($path);
/**
* Set the visibility for the given path.
*
* @param string $path
* @param string $visibility
* @return void
*/
public function setVisibility($path, $visibility);
/**
* Prepend to a file.
*
* @param string $path
* @param string $data
* @return int
*/
public function prepend($path, $data);
/**
* Append to a file.
*
* @param string $path
* @param string $data
* @return int
*/
public function append($path, $data);
/**
* Delete the file at a given path.
*
* @param string|array $paths
* @return bool
*/
public function delete($paths);
/**
* Copy a file to a new location.
*
* @param string $from
* @param string $to
* @return bool
*/
public function copy($from, $to);
/**
* Move a file to a new location.
*
* @param string $from
* @param string $to
* @return bool
*/
public function move($from, $to);
/**
* Get the file size of a given file.
*
* @param string $path
* @return int
*/
public function size($path);
/**
* Get the file's last modification time.
*
* @param string $path
* @return int
*/
public function lastModified($path);
/**
* Get an array of all files in a directory.
*
* @param string|null $directory
* @param bool $recursive
* @return array
*/
public function files($directory = null, $recursive = false);
/**
* Get all of the files from the given directory (recursive).
*
* @param string|null $directory
* @return array
*/
public function allFiles($directory = null);
/**
* Get all of the directories within a given directory.
*
* @param string|null $directory
* @param bool $recursive
* @return array
*/
public function directories($directory = null, $recursive = false);
/**
* Get all (recursive) of the directories within a given directory.
*
* @param string|null $directory
* @return array
*/
public function allDirectories($directory = null);
/**
* Create a directory.
*
* @param string $path
* @return bool
*/
public function makeDirectory($path);
/**
* Recursively delete a directory.
*
* @param string $directory
* @return bool
*/
public function deleteDirectory($directory);
}
<?php
namespace Illuminate\Contracts\Foundation;
use Illuminate\Contracts\Container\Container;
interface Application extends Container
{
/**
* Get the version number of the application.
*
* @return string
*/
public function version();
/**
* Get the base path of the Laravel installation.
*
* @return string
*/
public function basePath();
/**
* Get or check the current application environment.
*
* @param mixed
* @return string
*/
public function environment();
/**
* Determine if the application is currently down for maintenance.
*
* @return bool
*/
public function isDownForMaintenance();
/**
* Register all of the configured providers.
*
* @return void
*/
public function registerConfiguredProviders();
/**
* Register a service provider with the application.
*
* @param \Illuminate\Support\ServiceProvider|string $provider
* @param array $options
* @param bool $force
* @return \Illuminate\Support\ServiceProvider
*/
public function register($provider, $options = [], $force = false);
/**
* Register a deferred provider and service.
*
* @param string $provider
* @param string $service
* @return void
*/
public function registerDeferredProvider($provider, $service = null);
/**
* Boot the application's service providers.
*
* @return void
*/
public function boot();
/**
* Register a new boot listener.
*
* @param mixed $callback
* @return void
*/
public function booting($callback);
/**
* Register a new "booted" listener.
*
* @param mixed $callback
* @return void
*/
public function booted($callback);
/**
* Get the path to the cached "compiled.php" file.
*
* @return string
*/
public function getCachedCompilePath();
/**
* Get the path to the cached services.php file.
*
* @return string
*/
public function getCachedServicesPath();
}
<?php
namespace Illuminate\Contracts\Hashing;
interface Hasher
{
/**
* Hash the given value.
*
* @param string $value
* @param array $options
* @return string
*/
public function make($value, array $options = []);
/**
* Check the given plain value against a hash.
*
* @param string $value
* @param string $hashedValue
* @param array $options
* @return bool
*/
public function check($value, $hashedValue, array $options = []);
/**
* Check if the given hash has been hashed using the given options.
*
* @param string $hashedValue
* @param array $options
* @return bool
*/
public function needsRehash($hashedValue, array $options = []);
}
<?php
namespace Illuminate\Contracts\Http;
interface Kernel
{
/**
* Bootstrap the application for HTTP requests.
*
* @return void
*/
public function bootstrap();
/**
* Handle an incoming HTTP request.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* @return \Symfony\Component\HttpFoundation\Response
*/
public function handle($request);
/**
* Perform any final actions for the request lifecycle.
*
* @param \Symfony\Component\HttpFoundation\Request $request
* @param \Symfony\Component\HttpFoundation\Response $response
* @return void
*/
public function terminate($request, $response);
/**
* Get the Laravel application instance.
*
* @return \Illuminate\Contracts\Foundation\Application
*/
public function getApplication();
}
<?php
namespace Illuminate\Contracts\Logging;
interface Log
{
/**
* Log an alert message to the logs.
*
* @param string $message
* @param array $context
* @return void
*/
public function alert($message, array $context = []);
/**
* Log a critical message to the logs.
*
* @param string $message
* @param array $context
* @return void
*/
public function critical($message, array $context = []);
/**
* Log an error message to the logs.
*
* @param string $message
* @param array $context
* @return void
*/
public function error($message, array $context = []);
/**
* Log a warning message to the logs.
*
* @param string $message
* @param array $context
* @return void
*/
public function warning($message, array $context = []);
/**
* Log a notice to the logs.
*
* @param string $message
* @param array $context
* @return void
*/
public function notice($message, array $context = []);
/**
* Log an informational message to the logs.
*
* @param string $message
* @param array $context
* @return void
*/
public function info($message, array $context = []);
/**
* Log a debug message to the logs.
*
* @param string $message
* @param array $context
* @return void
*/
public function debug($message, array $context = []);
/**
* Log a message to the logs.
*
* @param string $level
* @param string $message
* @param array $context
* @return void
*/
public function log($level, $message, array $context = []);
/**
* Register a file log handler.
*
* @param string $path
* @param string $level
* @return void
*/
public function useFiles($path, $level = 'debug');
/**
* Register a daily file log handler.
*
* @param string $path
* @param int $days
* @param string $level
* @return void
*/
public function useDailyFiles($path, $days = 0, $level = 'debug');
}
<?php
namespace Illuminate\Contracts\Mail;
interface Mailer
{
/**
* Send a new message when only a raw text part.
*
* @param string $text
* @param \Closure|string $callback
* @return int
*/
public function raw($text, $callback);
/**
* Send a new message using a view.
*
* @param string|array $view
* @param array $data
* @param \Closure|string $callback
* @return void
*/
public function send($view, array $data, $callback);
/**
* Get the array of failed recipients.
*
* @return array
*/
public function failures();
}
<?php
namespace Illuminate\Contracts\Mail;
interface MailQueue
{
/**
* Queue a new e-mail message for sending.
*
* @param string|array $view
* @param array $data
* @param \Closure|string $callback
* @param string $queue
* @return mixed
*/
public function queue($view, array $data, $callback, $queue = null);
/**
* Queue a new e-mail message for sending after (n) seconds.
*
* @param int $delay
* @param string|array $view
* @param array $data
* @param \Closure|string $callback
* @param string $queue
* @return mixed
*/
public function later($delay, $view, array $data, $callback, $queue = null);
}
<?php
namespace Illuminate\Contracts\Pagination;
interface LengthAwarePaginator extends Paginator
{
/**
* Determine the total number of items in the data store.
*
* @return int
*/
public function total();
/**
* Get the page number of the last available page.
*
* @return int
*/
public function lastPage();
}
<?php
namespace Illuminate\Contracts\Pagination;
interface Paginator
{
/**
* Get the URL for a given page.
*
* @param int $page
* @return string
*/
public function url($page);
/**
* Add a set of query string values to the paginator.
*
* @param array|string $key
* @param string|null $value
* @return $this
*/
public function appends($key, $value = null);
/**
* Get / set the URL fragment to be appended to URLs.
*
* @param string|null $fragment
* @return $this|string
*/
public function fragment($fragment = null);
/**
* The the URL for the next page, or null.
*
* @return string|null
*/
public function nextPageUrl();
/**
* Get the URL for the previous page, or null.
*
* @return string|null
*/
public function previousPageUrl();
/**
* Get all of the items being paginated.
*
* @return array
*/
public function items();
/**
* Get the "index" of the first item being paginated.
*
* @return int
*/
public function firstItem();
/**
* Get the "index" of the last item being paginated.
*
* @return int
*/
public function lastItem();
/**
* Determine how many items are being shown per page.
*
* @return int
*/
public function perPage();
/**
* Determine the current page being paginated.
*
* @return int
*/
public function currentPage();
/**
* Determine if there are enough items to split into multiple pages.
*
* @return bool
*/
public function hasPages();
/**
* Determine if there is more items in the data store.
*
* @return bool
*/
public function hasMorePages();
/**
* Determine if the list of items is empty or not.
*
* @return bool
*/
public function isEmpty();
/**
* Render the paginator using a given Presenter.
*
* @param \Illuminate\Contracts\Pagination\Presenter|null $presenter
* @return string
*/
public function render(Presenter $presenter = null);
}
<?php
namespace Illuminate\Contracts\Pagination;
interface Presenter
{
/**
* Render the given paginator.
*
* @return \Illuminate\Contracts\Support\Htmlable|string
*/
public function render();
/**
* Determine if the underlying paginator being presented has pages to show.
*
* @return bool
*/
public function hasPages();
}
<?php
namespace Illuminate\Contracts\Pipeline;
interface Hub
{
/**
* Send an object through one of the available pipelines.
*
* @param mixed $object
* @param string|null $pipeline
* @return mixed
*/
public function pipe($object, $pipeline = null);
}
<?php
namespace Illuminate\Contracts\Pipeline;
use Closure;
interface Pipeline
{
/**
* Set the traveler object being sent on the pipeline.
*
* @param mixed $traveler
* @return $this
*/
public function send($traveler);
/**
* Set the stops of the pipeline.
*
* @param dynamic|array $stops
* @return $this
*/
public function through($stops);
/**
* Set the method to call on the stops.
*
* @param string $method
* @return $this
*/
public function via($method);
/**
* Run the pipeline with a final destination callback.
*
* @param \Closure $destination
* @return mixed
*/
public function then(Closure $destination);
}
<?php
namespace Illuminate\Contracts\Queue;
use InvalidArgumentException;
class EntityNotFoundException extends InvalidArgumentException
{
/**
* Create a new exception instance.
*
* @param string $type
* @param mixed $id
* @return void
*/
public function __construct($type, $id)
{
$id = (string) $id;
parent::__construct("Queueable entity [{$type}] not found for ID [{$id}].");
}
}
<?php
namespace Illuminate\Contracts\Queue;
interface EntityResolver
{
/**
* Resolve the entity for the given ID.
*
* @param string $type
* @param mixed $id
* @return mixed
*/
public function resolve($type, $id);
}
<?php
namespace Illuminate\Contracts\Queue;
interface Factory
{
/**
* Resolve a queue connection instance.
*
* @param string $name
* @return \Illuminate\Contracts\Queue\Queue
*/
public function connection($name = null);
}
<?php
namespace Illuminate\Contracts\Queue;
interface Job
{
/**
* Fire the job.
*
* @return void
*/
public function fire();
/**
* Delete the job from the queue.
*
* @return void
*/
public function delete();
/**
* Determine if the job has been deleted.
*
* @return bool
*/
public function isDeleted();
/**
* Release the job back into the queue.
*
* @param int $delay
* @return void
*/
public function release($delay = 0);
/**
* Determine if the job has been deleted or released.
*
* @return bool
*/
public function isDeletedOrReleased();
/**
* Get the number of times the job has been attempted.
*
* @return int
*/
public function attempts();
/**
* Get the name of the queued job class.
*
* @return string
*/
public function getName();
/**
* Call the failed method on the job instance.
*
* @return void
*/
public function failed();
/**
* Get the name of the queue the job belongs to.
*
* @return string
*/
public function getQueue();
/**
* Get the raw body string for the job.
*
* @return string
*/
public function getRawBody();
}
<?php
namespace Illuminate\Contracts\Queue;
interface Monitor
{
/**
* Register a callback to be executed on every iteration through the queue loop.
*
* @param mixed $callback
* @return void
*/
public function looping($callback);
/**
* Register a callback to be executed when a job fails after the maximum amount of retries.
*
* @param mixed $callback
* @return void
*/
public function failing($callback);
/**
* Register a callback to be executed when a daemon queue is stopping.
*
* @param mixed $callback
* @return void
*/
public function stopping($callback);
}
<?php
namespace Illuminate\Contracts\Queue;
interface Queue
{
/**
* Push a new job onto the queue.
*
* @param string $job
* @param mixed $data
* @param string $queue
* @return mixed
*/
public function push($job, $data = '', $queue = null);
/**
* Push a raw payload onto the queue.
*
* @param string $payload
* @param string $queue
* @param array $options
* @return mixed
*/
public function pushRaw($payload, $queue = null, array $options = []);
/**
* Push a new job onto the queue after a delay.
*
* @param \DateTime|int $delay
* @param string $job
* @param mixed $data
* @param string $queue
* @return mixed
*/
public function later($delay, $job, $data = '', $queue = null);
/**
* Push a new job onto the queue.
*
* @param string $queue
* @param string $job
* @param mixed $data
* @return mixed
*/
public function pushOn($queue, $job, $data = '');
/**
* Push a new job onto the queue after a delay.
*
* @param string $queue
* @param \DateTime|int $delay
* @param string $job
* @param mixed $data
* @return mixed
*/
public function laterOn($queue, $delay, $job, $data = '');
/**
* Pop the next job off of the queue.
*
* @param string $queue
* @return \Illuminate\Contracts\Queue\Job|null
*/
public function pop($queue = null);
}
<?php
namespace Illuminate\Contracts\Queue;
interface QueueableEntity
{
/**
* Get the queueable identity for the entity.
*
* @return mixed
*/
public function getQueueableId();
}
<?php
namespace Illuminate\Contracts\Queue;
interface ShouldQueue
{
//
}
<?php
namespace Illuminate\Contracts\Redis;
interface Database
{
/**
* Run a command against the Redis database.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function command($method, array $parameters = []);
}
<?php
namespace Illuminate\Contracts\Routing;
use Closure;
interface Registrar
{
/**
* Register a new GET route with the router.
*
* @param string $uri
* @param \Closure|array|string $action
* @return void
*/
public function get($uri, $action);
/**
* Register a new POST route with the router.
*
* @param string $uri
* @param \Closure|array|string $action
* @return void
*/
public function post($uri, $action);
/**
* Register a new PUT route with the router.
*
* @param string $uri
* @param \Closure|array|string $action
* @return void
*/
public function put($uri, $action);
/**
* Register a new DELETE route with the router.
*
* @param string $uri
* @param \Closure|array|string $action
* @return void
*/
public function delete($uri, $action);
/**
* Register a new PATCH route with the router.
*
* @param string $uri
* @param \Closure|array|string $action
* @return void
*/
public function patch($uri, $action);
/**
* Register a new OPTIONS route with the router.
*
* @param string $uri
* @param \Closure|array|string $action
* @return void
*/
public function options($uri, $action);
/**
* Register a new route with the given verbs.
*
* @param array|string $methods
* @param string $uri
* @param \Closure|array|string $action
* @return void
*/
public function match($methods, $uri, $action);
/**
* Route a resource to a controller.
*
* @param string $name
* @param string $controller
* @param array $options
* @return void
*/
public function resource($name, $controller, array $options = []);
/**
* Create a route group with shared attributes.
*
* @param array $attributes
* @param \Closure $callback
* @return void
*/
public function group(array $attributes, Closure $callback);
}
<?php
namespace Illuminate\Contracts\Routing;
interface ResponseFactory
{
/**
* Return a new response from the application.
*
* @param string $content
* @param int $status
* @param array $headers
* @return \Illuminate\Http\Response
*/
public function make($content = '', $status = 200, array $headers = []);
/**
* Return a new view response from the application.
*
* @param string $view
* @param array $data
* @param int $status
* @param array $headers
* @return \Illuminate\Http\Response
*/
public function view($view, $data = [], $status = 200, array $headers = []);
/**
* Return a new JSON response from the application.
*
* @param string|array $data
* @param int $status
* @param array $headers
* @param int $options
* @return \Illuminate\Http\JsonResponse
*/
public function json($data = [], $status = 200, array $headers = [], $options = 0);
/**
* Return a new JSONP response from the application.
*
* @param string $callback
* @param string|array $data
* @param int $status
* @param array $headers
* @param int $options
* @return \Illuminate\Http\JsonResponse
*/
public function jsonp($callback, $data = [], $status = 200, array $headers = [], $options = 0);
/**
* Return a new streamed response from the application.
*
* @param \Closure $callback
* @param int $status
* @param array $headers
* @return \Symfony\Component\HttpFoundation\StreamedResponse
*/
public function stream($callback, $status = 200, array $headers = []);
/**
* Create a new file download response.
*
* @param \SplFileInfo|string $file
* @param string $name
* @param array $headers
* @param string|null $disposition
* @return \Symfony\Component\HttpFoundation\BinaryFileResponse
*/
public function download($file, $name = null, array $headers = [], $disposition = 'attachment');
/**
* Create a new redirect response to the given path.
*
* @param string $path
* @param int $status
* @param array $headers
* @param bool|null $secure
* @return \Illuminate\Http\RedirectResponse
*/
public function redirectTo($path, $status = 302, $headers = [], $secure = null);
/**
* Create a new redirect response to a named route.
*
* @param string $route
* @param array $parameters
* @param int $status
* @param array $headers
* @return \Illuminate\Http\RedirectResponse
*/
public function redirectToRoute($route, $parameters = [], $status = 302, $headers = []);
/**
* Create a new redirect response to a controller action.
*
* @param string $action
* @param array $parameters
* @param int $status
* @param array $headers
* @return \Illuminate\Http\RedirectResponse
*/
public function redirectToAction($action, $parameters = [], $status = 302, $headers = []);
/**
* Create a new redirect response, while putting the current URL in the session.
*
* @param string $path
* @param int $status
* @param array $headers
* @param bool|null $secure
* @return \Illuminate\Http\RedirectResponse
*/
public function redirectGuest($path, $status = 302, $headers = [], $secure = null);
/**
* Create a new redirect response to the previously intended location.
*
* @param string $default
* @param int $status
* @param array $headers
* @param bool|null $secure
* @return \Illuminate\Http\RedirectResponse
*/
public function redirectToIntended($default = '/', $status = 302, $headers = [], $secure = null);
}
<?php
namespace Illuminate\Contracts\Routing;
interface UrlGenerator
{
/**
* Get the current URL for the request.
*
* @return string
*/
public function current();
/**
* Generate a absolute URL to the given path.
*
* @param string $path
* @param mixed $extra
* @param bool $secure
* @return string
*/
public function to($path, $extra = [], $secure = null);
/**
* Generate a secure, absolute URL to the given path.
*
* @param string $path
* @param array $parameters
* @return string
*/
public function secure($path, $parameters = []);
/**
* Generate a URL to an application asset.
*
* @param string $path
* @param bool $secure
* @return string
*/
public function asset($path, $secure = null);
/**
* Get the URL to a named route.
*
* @param string $name
* @param mixed $parameters
* @param bool $absolute
* @return string
*
* @throws \InvalidArgumentException
*/
public function route($name, $parameters = [], $absolute = true);
/**
* Get the URL to a controller action.
*
* @param string $action
* @param mixed $parameters
* @param bool $absolute
* @return string
*/
public function action($action, $parameters = [], $absolute = true);
/**
* Set the root controller namespace.
*
* @param string $rootNamespace
* @return $this
*/
public function setRootControllerNamespace($rootNamespace);
}
<?php
namespace Illuminate\Contracts\Routing;
interface UrlRoutable
{
/**
* Get the value of the model's route key.
*
* @return mixed
*/
public function getRouteKey();
/**
* Get the route key for the model.
*
* @return string
*/
public function getRouteKeyName();
}
<?php
namespace Illuminate\Contracts\Support;
interface Arrayable
{
/**
* Get the instance as an array.
*
* @return array
*/
public function toArray();
}
<?php
namespace Illuminate\Contracts\Support;
interface Htmlable
{
/**
* Get content as a string of HTML.
*
* @return string
*/
public function toHtml();
}
<?php
namespace Illuminate\Contracts\Support;
interface Jsonable
{
/**
* Convert the object to its JSON representation.
*
* @param int $options
* @return string
*/
public function toJson($options = 0);
}
<?php
namespace Illuminate\Contracts\Support;
interface MessageBag
{
/**
* Get the keys present in the message bag.
*
* @return array
*/
public function keys();
/**
* Add a message to the bag.
*
* @param string $key
* @param string $message
* @return $this
*/
public function add($key, $message);
/**
* Merge a new array of messages into the bag.
*
* @param \Illuminate\Contracts\Support\MessageProvider|array $messages
* @return $this
*/
public function merge($messages);
/**
* Determine if messages exist for a given key.
*
* @param string $key
* @return bool
*/
public function has($key = null);
/**
* Get the first message from the bag for a given key.
*
* @param string $key
* @param string $format
* @return string
*/
public function first($key = null, $format = null);
/**
* Get all of the messages from the bag for a given key.
*
* @param string $key
* @param string $format
* @return array
*/
public function get($key, $format = null);
/**
* Get all of the messages for every key in the bag.
*
* @param string $format
* @return array
*/
public function all($format = null);
/**
* Get the default message format.
*
* @return string
*/
public function getFormat();
/**
* Set the default message format.
*
* @param string $format
* @return $this
*/
public function setFormat($format = ':message');
/**
* Determine if the message bag has any messages.
*
* @return bool
*/
public function isEmpty();
/**
* Get the number of messages in the container.
*
* @return int
*/
public function count();
/**
* Get the instance as an array.
*
* @return array
*/
public function toArray();
}
<?php
namespace Illuminate\Contracts\Support;
interface MessageProvider
{
/**
* Get the messages for the instance.
*
* @return \Illuminate\Contracts\Support\MessageBag
*/
public function getMessageBag();
}
<?php
namespace Illuminate\Contracts\Support;
interface Renderable
{
/**
* Get the evaluated contents of the object.
*
* @return string
*/
public function render();
}
<?php
namespace Illuminate\Contracts\Validation;
interface Factory
{
/**
* Create a new Validator instance.
*
* @param array $data
* @param array $rules
* @param array $messages
* @param array $customAttributes
* @return \Illuminate\Contracts\Validation\Validator
*/
public function make(array $data, array $rules, array $messages = [], array $customAttributes = []);
/**
* Register a custom validator extension.
*
* @param string $rule
* @param \Closure|string $extension
* @param string $message
* @return void
*/
public function extend($rule, $extension, $message = null);
/**
* Register a custom implicit validator extension.
*
* @param string $rule
* @param \Closure|string $extension
* @param string $message
* @return void
*/
public function extendImplicit($rule, $extension, $message = null);
/**
* Register a custom implicit validator message replacer.
*
* @param string $rule
* @param \Closure|string $replacer
* @return void
*/
public function replacer($rule, $replacer);
}
<?php
namespace Illuminate\Contracts\Validation;
use RuntimeException;
class UnauthorizedException extends RuntimeException
{
//
}
<?php
namespace Illuminate\Contracts\Validation;
interface ValidatesWhenResolved
{
/**
* Validate the given class instance.
*
* @return void
*/
public function validate();
}
<?php
namespace Illuminate\Contracts\Validation;
use RuntimeException;
use Illuminate\Contracts\Support\MessageProvider;
class ValidationException extends RuntimeException
{
/**
* The message provider implementation.
*
* @var \Illuminate\Contracts\Support\MessageProvider
*/
protected $provider;
/**
* Create a new validation exception instance.
*
* @param \Illuminate\Contracts\Support\MessageProvider $provider
* @return void
*/
public function __construct(MessageProvider $provider)
{
$this->provider = $provider;
}
/**
* Get the validation error message provider.
*
* @return \Illuminate\Contracts\Support\MessageBag
*/
public function errors()
{
return $this->provider->getMessageBag();
}
/**
* Get the validation error message provider.
*
* @return \Illuminate\Contracts\Support\MessageProvider
*/
public function getMessageProvider()
{
return $this->provider;
}
}
<?php
namespace Illuminate\Contracts\Validation;
use Illuminate\Contracts\Support\MessageProvider;
interface Validator extends MessageProvider
{
/**
* Determine if the data fails the validation rules.
*
* @return bool
*/
public function fails();
/**
* Get the failed validation rules.
*
* @return array
*/
public function failed();
/**
* Add conditions to a given field based on a Closure.
*
* @param string $attribute
* @param string|array $rules
* @param callable $callback
* @return void
*/
public function sometimes($attribute, $rules, callable $callback);
/**
* After an after validation callback.
*
* @param callable|string $callback
* @return $this
*/
public function after($callback);
}
<?php
namespace Illuminate\Contracts\View;
interface Factory
{
/**
* Determine if a given view exists.
*
* @param string $view
* @return bool
*/
public function exists($view);
/**
* Get the evaluated view contents for the given path.
*
* @param string $path
* @param array $data
* @param array $mergeData
* @return \Illuminate\Contracts\View\View
*/
public function file($path, $data = [], $mergeData = []);
/**
* Get the evaluated view contents for the given view.
*
* @param string $view
* @param array $data
* @param array $mergeData
* @return \Illuminate\Contracts\View\View
*/
public function make($view, $data = [], $mergeData = []);
/**
* Add a piece of shared data to the environment.
*
* @param array|string $key
* @param mixed $value
* @return mixed
*/
public function share($key, $value = null);
/**
* Register a view composer event.
*
* @param array|string $views
* @param \Closure|string $callback
* @param int|null $priority
* @return array
*/
public function composer($views, $callback, $priority = null);
/**
* Register a view creator event.
*
* @param array|string $views
* @param \Closure|string $callback
* @return array
*/
public function creator($views, $callback);
/**
* Add a new namespace to the loader.
*
* @param string $namespace
* @param string|array $hints
* @return void
*/
public function addNamespace($namespace, $hints);
}
<?php
namespace Illuminate\Contracts\View;
use Illuminate\Contracts\Support\Renderable;
interface View extends Renderable
{
/**
* Get the name of the view.
*
* @return string
*/
public function name();
/**
* Add a piece of data to the view.
*
* @param string|array $key
* @param mixed $value
* @return $this
*/
public function with($key, $value = null);
}
<?php
namespace Illuminate\Events;
use Illuminate\Contracts\Queue\Job;
use Illuminate\Contracts\Container\Container;
class CallQueuedHandler
{
/**
* The container instance.
*
* @var \Illuminate\Contracts\Container\Container
*/
protected $container;
/**
* Create a new job instance.
*
* @param \Illuminate\Contracts\Container\Container $container
* @return void
*/
public function __construct(Container $container)
{
$this->container = $container;
}
/**
* Handle the queued job.
*
* @param \Illuminate\Contracts\Queue\Job $job
* @param array $data
* @return void
*/
public function call(Job $job, array $data)
{
$handler = $this->setJobInstanceIfNecessary(
$job, $this->container->make($data['class'])
);
call_user_func_array(
[$handler, $data['method']], unserialize($data['data'])
);
if (! $job->isDeletedOrReleased()) {
$job->delete();
}
}
/**
* Set the job instance of the given class if necessary.
*
* @param \Illuminate\Contracts\Queue\Job $job
* @param mixed $instance
* @return mixed
*/
protected function setJobInstanceIfNecessary(Job $job, $instance)
{
if (in_array('Illuminate\Queue\InteractsWithQueue', class_uses_recursive(get_class($instance)))) {
$instance->setJob($job);
}
return $instance;
}
/**
* Call the failed method on the job instance.
*
* @param array $data
* @return void
*/
public function failed(array $data)
{
$handler = $this->container->make($data['class']);
if (method_exists($handler, 'failed')) {
call_user_func_array([$handler, 'failed'], unserialize($data['data']));
}
}
}
{
"name": "illuminate/events",
"description": "The Illuminate Events package.",
"license": "MIT",
"homepage": "http://laravel.com",
"support": {
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"authors": [
{
"name": "Taylor Otwell",
"email": "taylorotwell@gmail.com"
}
],
"require": {
"php": ">=5.5.9",
"illuminate/container": "5.2.*",
"illuminate/contracts": "5.2.*",
"illuminate/support": "5.2.*"
},
"autoload": {
"psr-4": {
"Illuminate\\Events\\": ""
}
},
"extra": {
"branch-alias": {
"dev-master": "5.2-dev"
}
},
"minimum-stability": "dev"
}
<?php
namespace Illuminate\Events;
use Exception;
use ReflectionClass;
use Illuminate\Support\Str;
use Illuminate\Container\Container;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;
use Illuminate\Contracts\Events\Dispatcher as DispatcherContract;
use Illuminate\Contracts\Container\Container as ContainerContract;
class Dispatcher implements DispatcherContract
{
/**
* The IoC container instance.
*
* @var \Illuminate\Contracts\Container\Container
*/
protected $container;
/**
* The registered event listeners.
*
* @var array
*/
protected $listeners = [];
/**
* The wildcard listeners.
*
* @var array
*/
protected $wildcards = [];
/**
* The sorted event listeners.
*
* @var array
*/
protected $sorted = [];
/**
* The event firing stack.
*
* @var array
*/
protected $firing = [];
/**
* The queue resolver instance.
*
* @var callable
*/
protected $queueResolver;
/**
* Create a new event dispatcher instance.
*
* @param \Illuminate\Contracts\Container\Container|null $container
* @return void
*/
public function __construct(ContainerContract $container = null)
{
$this->container = $container ?: new Container;
}
/**
* Register an event listener with the dispatcher.
*
* @param string|array $events
* @param mixed $listener
* @param int $priority
* @return void
*/
public function listen($events, $listener, $priority = 0)
{
foreach ((array) $events as $event) {
if (Str::contains($event, '*')) {
$this->setupWildcardListen($event, $listener);
} else {
$this->listeners[$event][$priority][] = $this->makeListener($listener);
unset($this->sorted[$event]);
}
}
}
/**
* Setup a wildcard listener callback.
*
* @param string $event
* @param mixed $listener
* @return void
*/
protected function setupWildcardListen($event, $listener)
{
$this->wildcards[$event][] = $this->makeListener($listener);
}
/**
* Determine if a given event has listeners.
*
* @param string $eventName
* @return bool
*/
public function hasListeners($eventName)
{
return isset($this->listeners[$eventName]) || isset($this->wildcards[$eventName]);
}
/**
* Register an event and payload to be fired later.
*
* @param string $event
* @param array $payload
* @return void
*/
public function push($event, $payload = [])
{
$this->listen($event.'_pushed', function () use ($event, $payload) {
$this->fire($event, $payload);
});
}
/**
* Register an event subscriber with the dispatcher.
*
* @param object|string $subscriber
* @return void
*/
public function subscribe($subscriber)
{
$subscriber = $this->resolveSubscriber($subscriber);
$subscriber->subscribe($this);
}
/**
* Resolve the subscriber instance.
*
* @param object|string $subscriber
* @return mixed
*/
protected function resolveSubscriber($subscriber)
{
if (is_string($subscriber)) {
return $this->container->make($subscriber);
}
return $subscriber;
}
/**
* Fire an event until the first non-null response is returned.
*
* @param string|object $event
* @param array $payload
* @return mixed
*/
public function until($event, $payload = [])
{
return $this->fire($event, $payload, true);
}
/**
* Flush a set of pushed events.
*
* @param string $event
* @return void
*/
public function flush($event)
{
$this->fire($event.'_pushed');
}
/**
* Get the event that is currently firing.
*
* @return string
*/
public function firing()
{
return last($this->firing);
}
/**
* Fire an event and call the listeners.
*
* @param string|object $event
* @param mixed $payload
* @param bool $halt
* @return array|null
*/
public function fire($event, $payload = [], $halt = false)
{
// When the given "event" is actually an object we will assume it is an event
// object and use the class as the event name and this event itself as the
// payload to the handler, which makes object based events quite simple.
if (is_object($event)) {
list($payload, $event) = [[$event], get_class($event)];
}
$responses = [];
// If an array is not given to us as the payload, we will turn it into one so
// we can easily use call_user_func_array on the listeners, passing in the
// payload to each of them so that they receive each of these arguments.
if (! is_array($payload)) {
$payload = [$payload];
}
$this->firing[] = $event;
if (isset($payload[0]) && $payload[0] instanceof ShouldBroadcast) {
$this->broadcastEvent($payload[0]);
}
foreach ($this->getListeners($event) as $listener) {
$response = call_user_func_array($listener, $payload);
// If a response is returned from the listener and event halting is enabled
// we will just return this response, and not call the rest of the event
// listeners. Otherwise we will add the response on the response list.
if (! is_null($response) && $halt) {
array_pop($this->firing);
return $response;
}
// If a boolean false is returned from a listener, we will stop propagating
// the event to any further listeners down in the chain, else we keep on
// looping through the listeners and firing every one in our sequence.
if ($response === false) {
break;
}
$responses[] = $response;
}
array_pop($this->firing);
return $halt ? null : $responses;
}
/**
* Broadcast the given event class.
*
* @param \Illuminate\Contracts\Broadcasting\ShouldBroadcast $event
* @return void
*/
protected function broadcastEvent($event)
{
if ($this->queueResolver) {
$connection = $event instanceof ShouldBroadcastNow ? 'sync' : null;
$queue = method_exists($event, 'onQueue') ? $event->onQueue() : null;
$this->resolveQueue()->connection($connection)->pushOn($queue, 'Illuminate\Broadcasting\BroadcastEvent', [
'event' => serialize(clone $event),
]);
}
}
/**
* Get all of the listeners for a given event name.
*
* @param string $eventName
* @return array
*/
public function getListeners($eventName)
{
$wildcards = $this->getWildcardListeners($eventName);
if (! isset($this->sorted[$eventName])) {
$this->sortListeners($eventName);
}
return array_merge($this->sorted[$eventName], $wildcards);
}
/**
* Get the wildcard listeners for the event.
*
* @param string $eventName
* @return array
*/
protected function getWildcardListeners($eventName)
{
$wildcards = [];
foreach ($this->wildcards as $key => $listeners) {
if (Str::is($key, $eventName)) {
$wildcards = array_merge($wildcards, $listeners);
}
}
return $wildcards;
}
/**
* Sort the listeners for a given event by priority.
*
* @param string $eventName
* @return array
*/
protected function sortListeners($eventName)
{
$this->sorted[$eventName] = [];
// If listeners exist for the given event, we will sort them by the priority
// so that we can call them in the correct order. We will cache off these
// sorted event listeners so we do not have to re-sort on every events.
if (isset($this->listeners[$eventName])) {
krsort($this->listeners[$eventName]);
$this->sorted[$eventName] = call_user_func_array(
'array_merge', $this->listeners[$eventName]
);
}
}
/**
* Register an event listener with the dispatcher.
*
* @param mixed $listener
* @return mixed
*/
public function makeListener($listener)
{
return is_string($listener) ? $this->createClassListener($listener) : $listener;
}
/**
* Create a class based listener using the IoC container.
*
* @param mixed $listener
* @return \Closure
*/
public function createClassListener($listener)
{
$container = $this->container;
return function () use ($listener, $container) {
return call_user_func_array(
$this->createClassCallable($listener, $container), func_get_args()
);
};
}
/**
* Create the class based event callable.
*
* @param string $listener
* @param \Illuminate\Container\Container $container
* @return callable
*/
protected function createClassCallable($listener, $container)
{
list($class, $method) = $this->parseClassCallable($listener);
if ($this->handlerShouldBeQueued($class)) {
return $this->createQueuedHandlerCallable($class, $method);
} else {
return [$container->make($class), $method];
}
}
/**
* Parse the class listener into class and method.
*
* @param string $listener
* @return array
*/
protected function parseClassCallable($listener)
{
$segments = explode('@', $listener);
return [$segments[0], count($segments) == 2 ? $segments[1] : 'handle'];
}
/**
* Determine if the event handler class should be queued.
*
* @param string $class
* @return bool
*/
protected function handlerShouldBeQueued($class)
{
try {
return (new ReflectionClass($class))->implementsInterface(
'Illuminate\Contracts\Queue\ShouldQueue'
);
} catch (Exception $e) {
return false;
}
}
/**
* Create a callable for putting an event handler on the queue.
*
* @param string $class
* @param string $method
* @return \Closure
*/
protected function createQueuedHandlerCallable($class, $method)
{
return function () use ($class, $method) {
$arguments = $this->cloneArgumentsForQueueing(func_get_args());
if (method_exists($class, 'queue')) {
$this->callQueueMethodOnHandler($class, $method, $arguments);
} else {
$this->resolveQueue()->push('Illuminate\Events\CallQueuedHandler@call', [
'class' => $class, 'method' => $method, 'data' => serialize($arguments),
]);
}
};
}
/**
* Clone the given arguments for queueing.
*
* @param array $arguments
* @return array
*/
protected function cloneArgumentsForQueueing(array $arguments)
{
return array_map(function ($a) {
return is_object($a) ? clone $a : $a;
}, $arguments);
}
/**
* Call the queue method on the handler class.
*
* @param string $class
* @param string $method
* @param array $arguments
* @return void
*/
protected function callQueueMethodOnHandler($class, $method, $arguments)
{
$handler = (new ReflectionClass($class))->newInstanceWithoutConstructor();
$handler->queue($this->resolveQueue(), 'Illuminate\Events\CallQueuedHandler@call', [
'class' => $class, 'method' => $method, 'data' => serialize($arguments),
]);
}
/**
* Remove a set of listeners from the dispatcher.
*
* @param string $event
* @return void
*/
public function forget($event)
{
if (Str::contains($event, '*')) {
unset($this->wildcards[$event]);
} else {
unset($this->listeners[$event], $this->sorted[$event]);
}
}
/**
* Forget all of the pushed listeners.
*
* @return void
*/
public function forgetPushed()
{
foreach ($this->listeners as $key => $value) {
if (Str::endsWith($key, '_pushed')) {
$this->forget($key);
}
}
}
/**
* Get the queue implementation from the resolver.
*
* @return \Illuminate\Contracts\Queue\Queue
*/
protected function resolveQueue()
{
return call_user_func($this->queueResolver);
}
/**
* Set the queue resolver implementation.
*
* @param callable $resolver
* @return $this
*/
public function setQueueResolver(callable $resolver)
{
$this->queueResolver = $resolver;
return $this;
}
}
<?php
namespace Illuminate\Events;
use Illuminate\Support\ServiceProvider;
class EventServiceProvider extends ServiceProvider
{
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->app->singleton('events', function ($app) {
return (new Dispatcher($app))->setQueueResolver(function () use ($app) {
return $app->make('Illuminate\Contracts\Queue\Factory');
});
});
}
}
<?php
namespace Illuminate\Filesystem;
use Symfony\Component\Finder\Finder;
class ClassFinder
{
/**
* Find all the class and interface names in a given directory.
*
* @param string $directory
* @return array
*/
public function findClasses($directory)
{
$classes = [];
foreach (Finder::create()->in($directory)->name('*.php') as $file) {
$classes[] = $this->findClass($file->getRealPath());
}
return array_filter($classes);
}
/**
* Extract the class name from the file at the given path.
*
* @param string $path
* @return string|null
*/
public function findClass($path)
{
$namespace = null;
$tokens = token_get_all(file_get_contents($path));
foreach ($tokens as $key => $token) {
if ($this->tokenIsNamespace($token)) {
$namespace = $this->getNamespace($key + 2, $tokens);
} elseif ($this->tokenIsClassOrInterface($token)) {
return ltrim($namespace.'\\'.$this->getClass($key + 2, $tokens), '\\');
}
}
}
/**
* Find the namespace in the tokens starting at a given key.
*
* @param int $key
* @param array $tokens
* @return string|null
*/
protected function getNamespace($key, array $tokens)
{
$namespace = null;
$tokenCount = count($tokens);
for ($i = $key; $i < $tokenCount; $i++) {
if ($this->isPartOfNamespace($tokens[$i])) {
$namespace .= $tokens[$i][1];
} elseif ($tokens[$i] == ';') {
return $namespace;
}
}
}
/**
* Find the class in the tokens starting at a given key.
*
* @param int $key
* @param array $tokens
* @return string|null
*/
protected function getClass($key, array $tokens)
{
$class = null;
$tokenCount = count($tokens);
for ($i = $key; $i < $tokenCount; $i++) {
if ($this->isPartOfClass($tokens[$i])) {
$class .= $tokens[$i][1];
} elseif ($this->isWhitespace($tokens[$i])) {
return $class;
}
}
}
/**
* Determine if the given token is a namespace keyword.
*
* @param array|string $token
* @return bool
*/
protected function tokenIsNamespace($token)
{
return is_array($token) && $token[0] == T_NAMESPACE;
}
/**
* Determine if the given token is a class or interface keyword.
*
* @param array|string $token
* @return bool
*/
protected function tokenIsClassOrInterface($token)
{
return is_array($token) && ($token[0] == T_CLASS || $token[0] == T_INTERFACE);
}
/**
* Determine if the given token is part of the namespace.
*
* @param array|string $token
* @return bool
*/
protected function isPartOfNamespace($token)
{
return is_array($token) && ($token[0] == T_STRING || $token[0] == T_NS_SEPARATOR);
}
/**
* Determine if the given token is part of the class.
*
* @param array|string $token
* @return bool
*/
protected function isPartOfClass($token)
{
return is_array($token) && $token[0] == T_STRING;
}
/**
* Determine if the given token is whitespace.
*
* @param array|string $token
* @return bool
*/
protected function isWhitespace($token)
{
return is_array($token) && $token[0] == T_WHITESPACE;
}
}
{
"name": "illuminate/filesystem",
"description": "The Illuminate Filesystem package.",
"license": "MIT",
"homepage": "http://laravel.com",
"support": {
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"authors": [
{
"name": "Taylor Otwell",
"email": "taylorotwell@gmail.com"
}
],
"require": {
"php": ">=5.5.9",
"illuminate/contracts": "5.2.*",
"illuminate/support": "5.2.*",
"symfony/finder": "2.8.*|3.0.*"
},
"autoload": {
"psr-4": {
"Illuminate\\Filesystem\\": ""
}
},
"extra": {
"branch-alias": {
"dev-master": "5.2-dev"
}
},
"suggest": {
"league/flysystem": "Required to use the Flysystem local and FTP drivers (~1.0).",
"league/flysystem-aws-s3-v3": "Required to use the Flysystem S3 driver (~1.0).",
"league/flysystem-rackspace": "Required to use the Flysystem Rackspace driver (~1.0)."
},
"minimum-stability": "dev"
}
<?php
namespace Illuminate\Filesystem;
use ErrorException;
use FilesystemIterator;
use Symfony\Component\Finder\Finder;
use Illuminate\Support\Traits\Macroable;
use Illuminate\Contracts\Filesystem\FileNotFoundException;
class Filesystem
{
use Macroable;
/**
* Determine if a file or directory exists.
*
* @param string $path
* @return bool
*/
public function exists($path)
{
return file_exists($path);
}
/**
* Get the contents of a file.
*
* @param string $path
* @param bool $lock
* @return string
*
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*/
public function get($path, $lock = false)
{
if ($this->isFile($path)) {
return $lock ? $this->sharedGet($path, $lock) : file_get_contents($path);
}
throw new FileNotFoundException("File does not exist at path {$path}");
}
/**
* Get contents of a file with shared access.
*
* @param string $path
* @return string
*/
public function sharedGet($path)
{
$contents = '';
$handle = fopen($path, 'r');
if ($handle) {
try {
if (flock($handle, LOCK_SH)) {
while (! feof($handle)) {
$contents .= fread($handle, 1048576);
}
}
} finally {
fclose($handle);
}
}
return $contents;
}
/**
* Get the returned value of a file.
*
* @param string $path
* @return mixed
*
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*/
public function getRequire($path)
{
if ($this->isFile($path)) {
return require $path;
}
throw new FileNotFoundException("File does not exist at path {$path}");
}
/**
* Require the given file once.
*
* @param string $file
* @return mixed
*/
public function requireOnce($file)
{
require_once $file;
}
/**
* Write the contents of a file.
*
* @param string $path
* @param string $contents
* @param bool $lock
* @return int
*/
public function put($path, $contents, $lock = false)
{
return file_put_contents($path, $contents, $lock ? LOCK_EX : 0);
}
/**
* Prepend to a file.
*
* @param string $path
* @param string $data
* @return int
*/
public function prepend($path, $data)
{
if ($this->exists($path)) {
return $this->put($path, $data.$this->get($path));
}
return $this->put($path, $data);
}
/**
* Append to a file.
*
* @param string $path
* @param string $data
* @return int
*/
public function append($path, $data)
{
return file_put_contents($path, $data, FILE_APPEND);
}
/**
* Delete the file at a given path.
*
* @param string|array $paths
* @return bool
*/
public function delete($paths)
{
$paths = is_array($paths) ? $paths : func_get_args();
$success = true;
foreach ($paths as $path) {
try {
if (! @unlink($path)) {
$success = false;
}
} catch (ErrorException $e) {
$success = false;
}
}
return $success;
}
/**
* Move a file to a new location.
*
* @param string $path
* @param string $target
* @return bool
*/
public function move($path, $target)
{
return rename($path, $target);
}
/**
* Copy a file to a new location.
*
* @param string $path
* @param string $target
* @return bool
*/
public function copy($path, $target)
{
return copy($path, $target);
}
/**
* Extract the file name from a file path.
*
* @param string $path
* @return string
*/
public function name($path)
{
return pathinfo($path, PATHINFO_FILENAME);
}
/**
* Extract the trailing name component from a file path.
*
* @param string $path
* @return string
*/
public function basename($path)
{
return pathinfo($path, PATHINFO_BASENAME);
}
/**
* Extract the parent directory from a file path.
*
* @param string $path
* @return string
*/
public function dirname($path)
{
return pathinfo($path, PATHINFO_DIRNAME);
}
/**
* Extract the file extension from a file path.
*
* @param string $path
* @return string
*/
public function extension($path)
{
return pathinfo($path, PATHINFO_EXTENSION);
}
/**
* Get the file type of a given file.
*
* @param string $path
* @return string
*/
public function type($path)
{
return filetype($path);
}
/**
* Get the mime-type of a given file.
*
* @param string $path
* @return string|false
*/
public function mimeType($path)
{
return finfo_file(finfo_open(FILEINFO_MIME_TYPE), $path);
}
/**
* Get the file size of a given file.
*
* @param string $path
* @return int
*/
public function size($path)
{
return filesize($path);
}
/**
* Get the file's last modification time.
*
* @param string $path
* @return int
*/
public function lastModified($path)
{
return filemtime($path);
}
/**
* Determine if the given path is a directory.
*
* @param string $directory
* @return bool
*/
public function isDirectory($directory)
{
return is_dir($directory);
}
/**
* Determine if the given path is writable.
*
* @param string $path
* @return bool
*/
public function isWritable($path)
{
return is_writable($path);
}
/**
* Determine if the given path is a file.
*
* @param string $file
* @return bool
*/
public function isFile($file)
{
return is_file($file);
}
/**
* Find path names matching a given pattern.
*
* @param string $pattern
* @param int $flags
* @return array
*/
public function glob($pattern, $flags = 0)
{
return glob($pattern, $flags);
}
/**
* Get an array of all files in a directory.
*
* @param string $directory
* @return array
*/
public function files($directory)
{
$glob = glob($directory.'/*');
if ($glob === false) {
return [];
}
// To get the appropriate files, we'll simply glob the directory and filter
// out any "files" that are not truly files so we do not end up with any
// directories in our list, but only true files within the directory.
return array_filter($glob, function ($file) {
return filetype($file) == 'file';
});
}
/**
* Get all of the files from the given directory (recursive).
*
* @param string $directory
* @return array
*/
public function allFiles($directory)
{
return iterator_to_array(Finder::create()->files()->in($directory), false);
}
/**
* Get all of the directories within a given directory.
*
* @param string $directory
* @return array
*/
public function directories($directory)
{
$directories = [];
foreach (Finder::create()->in($directory)->directories()->depth(0) as $dir) {
$directories[] = $dir->getPathname();
}
return $directories;
}
/**
* Create a directory.
*
* @param string $path
* @param int $mode
* @param bool $recursive
* @param bool $force
* @return bool
*/
public function makeDirectory($path, $mode = 0755, $recursive = false, $force = false)
{
if ($force) {
return @mkdir($path, $mode, $recursive);
}
return mkdir($path, $mode, $recursive);
}
/**
* Copy a directory from one location to another.
*
* @param string $directory
* @param string $destination
* @param int $options
* @return bool
*/
public function copyDirectory($directory, $destination, $options = null)
{
if (! $this->isDirectory($directory)) {
return false;
}
$options = $options ?: FilesystemIterator::SKIP_DOTS;
// If the destination directory does not actually exist, we will go ahead and
// create it recursively, which just gets the destination prepared to copy
// the files over. Once we make the directory we'll proceed the copying.
if (! $this->isDirectory($destination)) {
$this->makeDirectory($destination, 0777, true);
}
$items = new FilesystemIterator($directory, $options);
foreach ($items as $item) {
// As we spin through items, we will check to see if the current file is actually
// a directory or a file. When it is actually a directory we will need to call
// back into this function recursively to keep copying these nested folders.
$target = $destination.'/'.$item->getBasename();
if ($item->isDir()) {
$path = $item->getPathname();
if (! $this->copyDirectory($path, $target, $options)) {
return false;
}
}
// If the current items is just a regular file, we will just copy this to the new
// location and keep looping. If for some reason the copy fails we'll bail out
// and return false, so the developer is aware that the copy process failed.
else {
if (! $this->copy($item->getPathname(), $target)) {
return false;
}
}
}
return true;
}
/**
* Recursively delete a directory.
*
* The directory itself may be optionally preserved.
*
* @param string $directory
* @param bool $preserve
* @return bool
*/
public function deleteDirectory($directory, $preserve = false)
{
if (! $this->isDirectory($directory)) {
return false;
}
$items = new FilesystemIterator($directory);
foreach ($items as $item) {
// If the item is a directory, we can just recurse into the function and
// delete that sub-directory otherwise we'll just delete the file and
// keep iterating through each file until the directory is cleaned.
if ($item->isDir() && ! $item->isLink()) {
$this->deleteDirectory($item->getPathname());
}
// If the item is just a file, we can go ahead and delete it since we're
// just looping through and waxing all of the files in this directory
// and calling directories recursively, so we delete the real path.
else {
$this->delete($item->getPathname());
}
}
if (! $preserve) {
@rmdir($directory);
}
return true;
}
/**
* Empty the specified directory of all files and folders.
*
* @param string $directory
* @return bool
*/
public function cleanDirectory($directory)
{
return $this->deleteDirectory($directory, true);
}
}
<?php
namespace Illuminate\Filesystem;
use RuntimeException;
use InvalidArgumentException;
use Illuminate\Support\Collection;
use League\Flysystem\AdapterInterface;
use League\Flysystem\FilesystemInterface;
use League\Flysystem\AwsS3v3\AwsS3Adapter;
use League\Flysystem\FileNotFoundException;
use League\Flysystem\Adapter\Local as LocalAdapter;
use Illuminate\Contracts\Filesystem\Filesystem as FilesystemContract;
use Illuminate\Contracts\Filesystem\Cloud as CloudFilesystemContract;
use Illuminate\Contracts\Filesystem\FileNotFoundException as ContractFileNotFoundException;
class FilesystemAdapter implements FilesystemContract, CloudFilesystemContract
{
/**
* The Flysystem filesystem implementation.
*
* @var \League\Flysystem\FilesystemInterface
*/
protected $driver;
/**
* Create a new filesystem adapter instance.
*
* @param \League\Flysystem\FilesystemInterface $driver
* @return void
*/
public function __construct(FilesystemInterface $driver)
{
$this->driver = $driver;
}
/**
* Determine if a file exists.
*
* @param string $path
* @return bool
*/
public function exists($path)
{
return $this->driver->has($path);
}
/**
* Get the contents of a file.
*
* @param string $path
* @return string
*
* @throws \Illuminate\Contracts\Filesystem\FileNotFoundException
*/
public function get($path)
{
try {
return $this->driver->read($path);
} catch (FileNotFoundException $e) {
throw new ContractFileNotFoundException($path, $e->getCode(), $e);
}
}
/**
* Write the contents of a file.
*
* @param string $path
* @param string|resource $contents
* @param string $visibility
* @return bool
*/
public function put($path, $contents, $visibility = null)
{
if ($visibility = $this->parseVisibility($visibility)) {
$config = ['visibility' => $visibility];
} else {
$config = [];
}
if (is_resource($contents)) {
return $this->driver->putStream($path, $contents, $config);
} else {
return $this->driver->put($path, $contents, $config);
}
}
/**
* Get the visibility for the given path.
*
* @param string $path
* @return string
*/
public function getVisibility($path)
{
if ($this->driver->getVisibility($path) == AdapterInterface::VISIBILITY_PUBLIC) {
return FilesystemContract::VISIBILITY_PUBLIC;
}
return FilesystemContract::VISIBILITY_PRIVATE;
}
/**
* Set the visibility for the given path.
*
* @param string $path
* @param string $visibility
* @return void
*/
public function setVisibility($path, $visibility)
{
return $this->driver->setVisibility($path, $this->parseVisibility($visibility));
}
/**
* Prepend to a file.
*
* @param string $path
* @param string $data
* @return int
*/
public function prepend($path, $data, $separator = PHP_EOL)
{
if ($this->exists($path)) {
return $this->put($path, $data.$separator.$this->get($path));
}
return $this->put($path, $data);
}
/**
* Append to a file.
*
* @param string $path
* @param string $data
* @return int
*/
public function append($path, $data, $separator = PHP_EOL)
{
if ($this->exists($path)) {
return $this->put($path, $this->get($path).$separator.$data);
}
return $this->put($path, $data);
}
/**
* Delete the file at a given path.
*
* @param string|array $paths
* @return bool
*/
public function delete($paths)
{
$paths = is_array($paths) ? $paths : func_get_args();
foreach ($paths as $path) {
try {
$this->driver->delete($path);
} catch (FileNotFoundException $e) {
//
}
}
return true;
}
/**
* Copy a file to a new location.
*
* @param string $from
* @param string $to
* @return bool
*/
public function copy($from, $to)
{
return $this->driver->copy($from, $to);
}
/**
* Move a file to a new location.
*
* @param string $from
* @param string $to
* @return bool
*/
public function move($from, $to)
{
return $this->driver->rename($from, $to);
}
/**
* Get the file size of a given file.
*
* @param string $path
* @return int
*/
public function size($path)
{
return $this->driver->getSize($path);
}
/**
* Get the mime-type of a given file.
*
* @param string $path
* @return string|false
*/
public function mimeType($path)
{
return $this->driver->getMimetype($path);
}
/**
* Get the file's last modification time.
*
* @param string $path
* @return int
*/
public function lastModified($path)
{
return $this->driver->getTimestamp($path);
}
/**
* Get the URL for the file at the given path.
*
* @param string $path
* @return string
*/
public function url($path)
{
$adapter = $this->driver->getAdapter();
if ($adapter instanceof AwsS3Adapter) {
$path = $adapter->getPathPrefix().$path;
return $adapter->getClient()->getObjectUrl($adapter->getBucket(), $path);
} elseif ($adapter instanceof LocalAdapter) {
return '/storage/'.$path;
} else {
throw new RuntimeException('This driver does not support retrieving URLs.');
}
}
/**
* Get an array of all files in a directory.
*
* @param string|null $directory
* @param bool $recursive
* @return array
*/
public function files($directory = null, $recursive = false)
{
$contents = $this->driver->listContents($directory, $recursive);
return $this->filterContentsByType($contents, 'file');
}
/**
* Get all of the files from the given directory (recursive).
*
* @param string|null $directory
* @return array
*/
public function allFiles($directory = null)
{
return $this->files($directory, true);
}
/**
* Get all of the directories within a given directory.
*
* @param string|null $directory
* @param bool $recursive
* @return array
*/
public function directories($directory = null, $recursive = false)
{
$contents = $this->driver->listContents($directory, $recursive);
return $this->filterContentsByType($contents, 'dir');
}
/**
* Get all (recursive) of the directories within a given directory.
*
* @param string|null $directory
* @return array
*/
public function allDirectories($directory = null)
{
return $this->directories($directory, true);
}
/**
* Create a directory.
*
* @param string $path
* @return bool
*/
public function makeDirectory($path)
{
return $this->driver->createDir($path);
}
/**
* Recursively delete a directory.
*
* @param string $directory
* @return bool
*/
public function deleteDirectory($directory)
{
return $this->driver->deleteDir($directory);
}
/**
* Get the Flysystem driver.
*
* @return \League\Flysystem\FilesystemInterface
*/
public function getDriver()
{
return $this->driver;
}
/**
* Filter directory contents by type.
*
* @param array $contents
* @param string $type
* @return array
*/
protected function filterContentsByType($contents, $type)
{
return Collection::make($contents)
->where('type', $type)
->pluck('path')
->values()
->all();
}
/**
* Parse the given visibility value.
*
* @param string|null $visibility
* @return string|null
*
* @throws \InvalidArgumentException
*/
protected function parseVisibility($visibility)
{
if (is_null($visibility)) {
return;
}
switch ($visibility) {
case FilesystemContract::VISIBILITY_PUBLIC:
return AdapterInterface::VISIBILITY_PUBLIC;
case FilesystemContract::VISIBILITY_PRIVATE:
return AdapterInterface::VISIBILITY_PRIVATE;
}
throw new InvalidArgumentException('Unknown visibility: '.$visibility);
}
/**
* Pass dynamic methods call onto Flysystem.
*
* @param string $method
* @param array $parameters
* @return mixed
*
* @throws \BadMethodCallException
*/
public function __call($method, array $parameters)
{
return call_user_func_array([$this->driver, $method], $parameters);
}
}
<?php
namespace Illuminate\Filesystem;
use Closure;
use Aws\S3\S3Client;
use OpenCloud\Rackspace;
use Illuminate\Support\Arr;
use InvalidArgumentException;
use League\Flysystem\AdapterInterface;
use League\Flysystem\FilesystemInterface;
use League\Flysystem\Filesystem as Flysystem;
use League\Flysystem\Adapter\Ftp as FtpAdapter;
use League\Flysystem\Rackspace\RackspaceAdapter;
use League\Flysystem\Adapter\Local as LocalAdapter;
use League\Flysystem\AwsS3v3\AwsS3Adapter as S3Adapter;
use Illuminate\Contracts\Filesystem\Factory as FactoryContract;
class FilesystemManager implements FactoryContract
{
/**
* The application instance.
*
* @var \Illuminate\Contracts\Foundation\Application
*/
protected $app;
/**
* The array of resolved filesystem drivers.
*
* @var array
*/
protected $disks = [];
/**
* The registered custom driver creators.
*
* @var array
*/
protected $customCreators = [];
/**
* Create a new filesystem manager instance.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @return void
*/
public function __construct($app)
{
$this->app = $app;
}
/**
* Get a filesystem instance.
*
* @param string $name
* @return \Illuminate\Contracts\Filesystem\Filesystem
*/
public function drive($name = null)
{
return $this->disk($name);
}
/**
* Get a filesystem instance.
*
* @param string $name
* @return \Illuminate\Contracts\Filesystem\Filesystem
*/
public function disk($name = null)
{
$name = $name ?: $this->getDefaultDriver();
return $this->disks[$name] = $this->get($name);
}
/**
* Get a default cloud filesystem instance.
*
* @return \Illuminate\Contracts\Filesystem\Filesystem
*/
public function cloud()
{
$name = $this->getDefaultCloudDriver();
return $this->disks[$name] = $this->get($name);
}
/**
* Attempt to get the disk from the local cache.
*
* @param string $name
* @return \Illuminate\Contracts\Filesystem\Filesystem
*/
protected function get($name)
{
return isset($this->disks[$name]) ? $this->disks[$name] : $this->resolve($name);
}
/**
* Resolve the given disk.
*
* @param string $name
* @return \Illuminate\Contracts\Filesystem\Filesystem
*
* @throws \InvalidArgumentException
*/
protected function resolve($name)
{
$config = $this->getConfig($name);
if (isset($this->customCreators[$config['driver']])) {
return $this->callCustomCreator($config);
}
$driverMethod = 'create'.ucfirst($config['driver']).'Driver';
if (method_exists($this, $driverMethod)) {
return $this->{$driverMethod}($config);
} else {
throw new InvalidArgumentException("Driver [{$config['driver']}] is not supported.");
}
}
/**
* Call a custom driver creator.
*
* @param array $config
* @return \Illuminate\Contracts\Filesystem\Filesystem
*/
protected function callCustomCreator(array $config)
{
$driver = $this->customCreators[$config['driver']]($this->app, $config);
if ($driver instanceof FilesystemInterface) {
return $this->adapt($driver);
}
return $driver;
}
/**
* Create an instance of the local driver.
*
* @param array $config
* @return \Illuminate\Contracts\Filesystem\Filesystem
*/
public function createLocalDriver(array $config)
{
$permissions = isset($config['permissions']) ? $config['permissions'] : [];
$links = Arr::get($config, 'links') === 'skip'
? LocalAdapter::SKIP_LINKS
: LocalAdapter::DISALLOW_LINKS;
return $this->adapt($this->createFlysystem(new LocalAdapter(
$config['root'], LOCK_EX, $links, $permissions
), $config));
}
/**
* Create an instance of the ftp driver.
*
* @param array $config
* @return \Illuminate\Contracts\Filesystem\Filesystem
*/
public function createFtpDriver(array $config)
{
$ftpConfig = Arr::only($config, [
'host', 'username', 'password', 'port', 'root', 'passive', 'ssl', 'timeout',
]);
return $this->adapt($this->createFlysystem(
new FtpAdapter($ftpConfig), $config
));
}
/**
* Create an instance of the Amazon S3 driver.
*
* @param array $config
* @return \Illuminate\Contracts\Filesystem\Cloud
*/
public function createS3Driver(array $config)
{
$s3Config = $this->formatS3Config($config);
$root = isset($s3Config['root']) ? $s3Config['root'] : null;
return $this->adapt($this->createFlysystem(
new S3Adapter(new S3Client($s3Config), $s3Config['bucket'], $root), $config
));
}
/**
* Format the given S3 configuration with the default options.
*
* @param array $config
* @return array
*/
protected function formatS3Config(array $config)
{
$config += ['version' => 'latest'];
if ($config['key'] && $config['secret']) {
$config['credentials'] = Arr::only($config, ['key', 'secret']);
}
return $config;
}
/**
* Create an instance of the Rackspace driver.
*
* @param array $config
* @return \Illuminate\Contracts\Filesystem\Cloud
*/
public function createRackspaceDriver(array $config)
{
$client = new Rackspace($config['endpoint'], [
'username' => $config['username'], 'apiKey' => $config['key'],
]);
$root = isset($config['root']) ? $config['root'] : null;
return $this->adapt($this->createFlysystem(
new RackspaceAdapter($this->getRackspaceContainer($client, $config), $root), $config
));
}
/**
* Get the Rackspace Cloud Files container.
*
* @param \OpenCloud\Rackspace $client
* @param array $config
* @return \OpenCloud\ObjectStore\Resource\Container
*/
protected function getRackspaceContainer(Rackspace $client, array $config)
{
$urlType = Arr::get($config, 'url_type');
$store = $client->objectStoreService('cloudFiles', $config['region'], $urlType);
return $store->getContainer($config['container']);
}
/**
* Create a Flysystem instance with the given adapter.
*
* @param \League\Flysystem\AdapterInterface $adapter
* @param array $config
* @return \League\Flysystem\FlysystemInterface
*/
protected function createFlysystem(AdapterInterface $adapter, array $config)
{
$config = Arr::only($config, ['visibility']);
return new Flysystem($adapter, count($config) > 0 ? $config : null);
}
/**
* Adapt the filesystem implementation.
*
* @param \League\Flysystem\FilesystemInterface $filesystem
* @return \Illuminate\Contracts\Filesystem\Filesystem
*/
protected function adapt(FilesystemInterface $filesystem)
{
return new FilesystemAdapter($filesystem);
}
/**
* Get the filesystem connection configuration.
*
* @param string $name
* @return array
*/
protected function getConfig($name)
{
return $this->app['config']["filesystems.disks.{$name}"];
}
/**
* Get the default driver name.
*
* @return string
*/
public function getDefaultDriver()
{
return $this->app['config']['filesystems.default'];
}
/**
* Get the default cloud driver name.
*
* @return string
*/
public function getDefaultCloudDriver()
{
return $this->app['config']['filesystems.cloud'];
}
/**
* Register a custom driver creator Closure.
*
* @param string $driver
* @param \Closure $callback
* @return $this
*/
public function extend($driver, Closure $callback)
{
$this->customCreators[$driver] = $callback;
return $this;
}
/**
* Dynamically call the default driver instance.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
return call_user_func_array([$this->disk(), $method], $parameters);
}
}
<?php
namespace Illuminate\Filesystem;
use Illuminate\Support\ServiceProvider;
class FilesystemServiceProvider extends ServiceProvider
{
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->registerNativeFilesystem();
$this->registerFlysystem();
}
/**
* Register the native filesystem implementation.
*
* @return void
*/
protected function registerNativeFilesystem()
{
$this->app->singleton('files', function () {
return new Filesystem;
});
}
/**
* Register the driver based filesystem.
*
* @return void
*/
protected function registerFlysystem()
{
$this->registerManager();
$this->app->singleton('filesystem.disk', function () {
return $this->app['filesystem']->disk($this->getDefaultDriver());
});
$this->app->singleton('filesystem.cloud', function () {
return $this->app['filesystem']->disk($this->getCloudDriver());
});
}
/**
* Register the filesystem manager.
*
* @return void
*/
protected function registerManager()
{
$this->app->singleton('filesystem', function () {
return new FilesystemManager($this->app);
});
}
/**
* Get the default file driver.
*
* @return string
*/
protected function getDefaultDriver()
{
return $this->app['config']['filesystems.default'];
}
/**
* Get the default cloud based file driver.
*
* @return string
*/
protected function getCloudDriver()
{
return $this->app['config']['filesystems.cloud'];
}
}
<?php
namespace Illuminate\Support;
class AggregateServiceProvider extends ServiceProvider
{
/**
* The provider class names.
*
* @var array
*/
protected $providers = [];
/**
* An array of the service provider instances.
*
* @var array
*/
protected $instances = [];
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->instances = [];
foreach ($this->providers as $provider) {
$this->instances[] = $this->app->register($provider);
}
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
$provides = [];
foreach ($this->providers as $provider) {
$instance = $this->app->resolveProviderClass($provider);
$provides = array_merge($provides, $instance->provides());
}
return $provides;
}
}
<?php
namespace Illuminate\Support;
use ArrayAccess;
use Illuminate\Support\Traits\Macroable;
class Arr
{
use Macroable;
/**
* Determine whether the given value is array accessible.
*
* @param mixed $value
* @return bool
*/
public static function accessible($value)
{
return is_array($value) || $value instanceof ArrayAccess;
}
/**
* Add an element to an array using "dot" notation if it doesn't exist.
*
* @param array $array
* @param string $key
* @param mixed $value
* @return array
*/
public static function add($array, $key, $value)
{
if (is_null(static::get($array, $key))) {
static::set($array, $key, $value);
}
return $array;
}
/**
* Build a new array using a callback.
*
* @param array $array
* @param callable $callback
* @return array
*
* @deprecated since version 5.2.
*/
public static function build($array, callable $callback)
{
$results = [];
foreach ($array as $key => $value) {
list($innerKey, $innerValue) = call_user_func($callback, $key, $value);
$results[$innerKey] = $innerValue;
}
return $results;
}
/**
* Collapse an array of arrays into a single array.
*
* @param array $array
* @return array
*/
public static function collapse($array)
{
$results = [];
foreach ($array as $values) {
if ($values instanceof Collection) {
$values = $values->all();
} elseif (! is_array($values)) {
continue;
}
$results = array_merge($results, $values);
}
return $results;
}
/**
* Divide an array into two arrays. One with keys and the other with values.
*
* @param array $array
* @return array
*/
public static function divide($array)
{
return [array_keys($array), array_values($array)];
}
/**
* Flatten a multi-dimensional associative array with dots.
*
* @param array $array
* @param string $prepend
* @return array
*/
public static function dot($array, $prepend = '')
{
$results = [];
foreach ($array as $key => $value) {
if (is_array($value)) {
$results = array_merge($results, static::dot($value, $prepend.$key.'.'));
} else {
$results[$prepend.$key] = $value;
}
}
return $results;
}
/**
* Get all of the given array except for a specified array of items.
*
* @param array $array
* @param array|string $keys
* @return array
*/
public static function except($array, $keys)
{
static::forget($array, $keys);
return $array;
}
/**
* Determine if the given key exists in the provided array.
*
* @param \ArrayAccess|array $array
* @param string|int $key
* @return bool
*/
public static function exists($array, $key)
{
if ($array instanceof ArrayAccess) {
return $array->offsetExists($key);
}
return array_key_exists($key, $array);
}
/**
* Return the first element in an array passing a given truth test.
*
* @param array $array
* @param callable|null $callback
* @param mixed $default
* @return mixed
*/
public static function first($array, callable $callback = null, $default = null)
{
if (is_null($callback)) {
return empty($array) ? value($default) : reset($array);
}
foreach ($array as $key => $value) {
if (call_user_func($callback, $key, $value)) {
return $value;
}
}
return value($default);
}
/**
* Return the last element in an array passing a given truth test.
*
* @param array $array
* @param callable|null $callback
* @param mixed $default
* @return mixed
*/
public static function last($array, callable $callback = null, $default = null)
{
if (is_null($callback)) {
return empty($array) ? value($default) : end($array);
}
return static::first(array_reverse($array), $callback, $default);
}
/**
* Flatten a multi-dimensional array into a single level.
*
* @param array $array
* @param int $depth
* @return array
*/
public static function flatten($array, $depth = INF)
{
$result = [];
foreach ($array as $item) {
$item = $item instanceof Collection ? $item->all() : $item;
if (is_array($item)) {
if ($depth === 1) {
$result = array_merge($result, $item);
continue;
}
$result = array_merge($result, static::flatten($item, $depth - 1));
continue;
}
$result[] = $item;
}
return $result;
}
/**
* Remove one or many array items from a given array using "dot" notation.
*
* @param array $array
* @param array|string $keys
* @return void
*/
public static function forget(&$array, $keys)
{
$original = &$array;
$keys = (array) $keys;
if (count($keys) === 0) {
return;
}
foreach ($keys as $key) {
$parts = explode('.', $key);
// clean up before each pass
$array = &$original;
while (count($parts) > 1) {
$part = array_shift($parts);
if (isset($array[$part]) && is_array($array[$part])) {
$array = &$array[$part];
} else {
continue 2;
}
}
unset($array[array_shift($parts)]);
}
}
/**
* Get an item from an array using "dot" notation.
*
* @param \ArrayAccess|array $array
* @param string $key
* @param mixed $default
* @return mixed
*/
public static function get($array, $key, $default = null)
{
if (! $array) {
return value($default);
}
if (is_null($key)) {
return $array;
}
if (static::exists($array, $key)) {
return $array[$key];
}
foreach (explode('.', $key) as $segment) {
if (static::accessible($array) && static::exists($array, $segment)) {
$array = $array[$segment];
} else {
return value($default);
}
}
return $array;
}
/**
* Check if an item exists in an array using "dot" notation.
*
* @param \ArrayAccess|array $array
* @param string $key
* @return bool
*/
public static function has($array, $key)
{
if (! $array) {
return false;
}
if (is_null($key)) {
return false;
}
if (static::exists($array, $key)) {
return true;
}
foreach (explode('.', $key) as $segment) {
if (static::accessible($array) && static::exists($array, $segment)) {
$array = $array[$segment];
} else {
return false;
}
}
return true;
}
/**
* Determines if an array is associative.
*
* An array is "associative" if it doesn't have sequential numerical keys beginning with zero.
*
* @param array $array
* @return bool
*/
public static function isAssoc(array $array)
{
$keys = array_keys($array);
return array_keys($keys) !== $keys;
}
/**
* Get a subset of the items from the given array.
*
* @param array $array
* @param array|string $keys
* @return array
*/
public static function only($array, $keys)
{
return array_intersect_key($array, array_flip((array) $keys));
}
/**
* Pluck an array of values from an array.
*
* @param array $array
* @param string|array $value
* @param string|array|null $key
* @return array
*/
public static function pluck($array, $value, $key = null)
{
$results = [];
list($value, $key) = static::explodePluckParameters($value, $key);
foreach ($array as $item) {
$itemValue = data_get($item, $value);
// If the key is "null", we will just append the value to the array and keep
// looping. Otherwise we will key the array using the value of the key we
// received from the developer. Then we'll return the final array form.
if (is_null($key)) {
$results[] = $itemValue;
} else {
$itemKey = data_get($item, $key);
$results[$itemKey] = $itemValue;
}
}
return $results;
}
/**
* Explode the "value" and "key" arguments passed to "pluck".
*
* @param string|array $value
* @param string|array|null $key
* @return array
*/
protected static function explodePluckParameters($value, $key)
{
$value = is_string($value) ? explode('.', $value) : $value;
$key = is_null($key) || is_array($key) ? $key : explode('.', $key);
return [$value, $key];
}
/**
* Push an item onto the beginning of an array.
*
* @param array $array
* @param mixed $value
* @param mixed $key
* @return array
*/
public static function prepend($array, $value, $key = null)
{
if (is_null($key)) {
array_unshift($array, $value);
} else {
$array = [$key => $value] + $array;
}
return $array;
}
/**
* Get a value from the array, and remove it.
*
* @param array $array
* @param string $key
* @param mixed $default
* @return mixed
*/
public static function pull(&$array, $key, $default = null)
{
$value = static::get($array, $key, $default);
static::forget($array, $key);
return $value;
}
/**
* Set an array item to a given value using "dot" notation.
*
* If no key is given to the method, the entire array will be replaced.
*
* @param array $array
* @param string $key
* @param mixed $value
* @return array
*/
public static function set(&$array, $key, $value)
{
if (is_null($key)) {
return $array = $value;
}
$keys = explode('.', $key);
while (count($keys) > 1) {
$key = array_shift($keys);
// If the key doesn't exist at this depth, we will just create an empty array
// to hold the next value, allowing us to create the arrays to hold final
// values at the correct depth. Then we'll keep digging into the array.
if (! isset($array[$key]) || ! is_array($array[$key])) {
$array[$key] = [];
}
$array = &$array[$key];
}
$array[array_shift($keys)] = $value;
return $array;
}
/**
* Sort the array using the given callback.
*
* @param array $array
* @param callable $callback
* @return array
*/
public static function sort($array, callable $callback)
{
return Collection::make($array)->sortBy($callback)->all();
}
/**
* Recursively sort an array by keys and values.
*
* @param array $array
* @return array
*/
public static function sortRecursive($array)
{
foreach ($array as &$value) {
if (is_array($value)) {
$value = static::sortRecursive($value);
}
}
if (static::isAssoc($array)) {
ksort($array);
} else {
sort($array);
}
return $array;
}
/**
* Filter the array using the given callback.
*
* @param array $array
* @param callable $callback
* @return array
*/
public static function where($array, callable $callback)
{
$filtered = [];
foreach ($array as $key => $value) {
if (call_user_func($callback, $key, $value)) {
$filtered[$key] = $value;
}
}
return $filtered;
}
}
<?php
namespace Illuminate\Support;
class ClassLoader
{
/**
* The registered directories.
*
* @var array
*/
protected static $directories = [];
/**
* Indicates if a ClassLoader has been registered.
*
* @var bool
*/
protected static $registered = false;
/**
* Load the given class file.
*
* @param string $class
* @return bool
*/
public static function load($class)
{
$class = static::normalizeClass($class);
foreach (static::$directories as $directory) {
if (file_exists($path = $directory.DIRECTORY_SEPARATOR.$class)) {
require_once $path;
return true;
}
}
return false;
}
/**
* Get the normal file name for a class.
*
* @param string $class
* @return string
*/
public static function normalizeClass($class)
{
if ($class[0] == '\\') {
$class = substr($class, 1);
}
return str_replace(['\\', '_'], DIRECTORY_SEPARATOR, $class).'.php';
}
/**
* Register the given class loader on the auto-loader stack.
*
* @return void
*/
public static function register()
{
if (! static::$registered) {
static::$registered = spl_autoload_register([static::class, 'load']);
}
}
/**
* Add directories to the class loader.
*
* @param string|array $directories
* @return void
*/
public static function addDirectories($directories)
{
static::$directories = array_unique(array_merge(static::$directories, (array) $directories));
}
/**
* Remove directories from the class loader.
*
* @param string|array $directories
* @return void
*/
public static function removeDirectories($directories = null)
{
if (is_null($directories)) {
static::$directories = [];
} else {
static::$directories = array_diff(static::$directories, (array) $directories);
}
}
/**
* Gets all the directories registered with the loader.
*
* @return array
*/
public static function getDirectories()
{
return static::$directories;
}
}
<?php
namespace Illuminate\Support;
use Countable;
use ArrayAccess;
use ArrayIterator;
use CachingIterator;
use JsonSerializable;
use IteratorAggregate;
use InvalidArgumentException;
use Illuminate\Support\Traits\Macroable;
use Illuminate\Contracts\Support\Jsonable;
use Illuminate\Contracts\Support\Arrayable;
class Collection implements ArrayAccess, Arrayable, Countable, IteratorAggregate, Jsonable, JsonSerializable
{
use Macroable;
/**
* The items contained in the collection.
*
* @var array
*/
protected $items = [];
/**
* Create a new collection.
*
* @param mixed $items
* @return void
*/
public function __construct($items = [])
{
$this->items = $this->getArrayableItems($items);
}
/**
* Create a new collection instance if the value isn't one already.
*
* @param mixed $items
* @return static
*/
public static function make($items = [])
{
return new static($items);
}
/**
* Get all of the items in the collection.
*
* @return array
*/
public function all()
{
return $this->items;
}
/**
* Get the average value of a given key.
*
* @param string|null $key
* @return mixed
*/
public function avg($key = null)
{
if ($count = $this->count()) {
return $this->sum($key) / $count;
}
}
/**
* Alias for the "avg" method.
*
* @param string|null $key
* @return mixed
*/
public function average($key = null)
{
return $this->avg($key);
}
/**
* Collapse the collection of items into a single array.
*
* @return static
*/
public function collapse()
{
return new static(Arr::collapse($this->items));
}
/**
* Determine if an item exists in the collection.
*
* @param mixed $key
* @param mixed $value
* @return bool
*/
public function contains($key, $value = null)
{
if (func_num_args() == 2) {
return $this->contains(function ($k, $item) use ($key, $value) {
return data_get($item, $key) == $value;
});
}
if ($this->useAsCallable($key)) {
return ! is_null($this->first($key));
}
return in_array($key, $this->items);
}
/**
* Get the items in the collection that are not present in the given items.
*
* @param mixed $items
* @return static
*/
public function diff($items)
{
return new static(array_diff($this->items, $this->getArrayableItems($items)));
}
/**
* Get the items in the collection whose keys are not present in the given items.
*
* @param mixed $items
* @return static
*/
public function diffKeys($items)
{
return new static(array_diff_key($this->items, $this->getArrayableItems($items)));
}
/**
* Execute a callback over each item.
*
* @param callable $callback
* @return $this
*/
public function each(callable $callback)
{
foreach ($this->items as $key => $item) {
if ($callback($item, $key) === false) {
break;
}
}
return $this;
}
/**
* Create a new collection consisting of every n-th element.
*
* @param int $step
* @param int $offset
* @return static
*/
public function every($step, $offset = 0)
{
$new = [];
$position = 0;
foreach ($this->items as $item) {
if ($position % $step === $offset) {
$new[] = $item;
}
$position++;
}
return new static($new);
}
/**
* Get all items except for those with the specified keys.
*
* @param mixed $keys
* @return static
*/
public function except($keys)
{
$keys = is_array($keys) ? $keys : func_get_args();
return new static(Arr::except($this->items, $keys));
}
/**
* Run a filter over each of the items.
*
* @param callable|null $callback
* @return static
*/
public function filter(callable $callback = null)
{
if ($callback) {
$return = [];
foreach ($this->items as $key => $value) {
if ($callback($value, $key)) {
$return[$key] = $value;
}
}
return new static($return);
}
return new static(array_filter($this->items));
}
/**
* Filter items by the given key value pair.
*
* @param string $key
* @param mixed $value
* @param bool $strict
* @return static
*/
public function where($key, $value, $strict = true)
{
return $this->filter(function ($item) use ($key, $value, $strict) {
return $strict ? data_get($item, $key) === $value
: data_get($item, $key) == $value;
});
}
/**
* Filter items by the given key value pair using loose comparison.
*
* @param string $key
* @param mixed $value
* @return static
*/
public function whereLoose($key, $value)
{
return $this->where($key, $value, false);
}
/**
* Filter items by the given key value pair.
*
* @param string $key
* @param array $values
* @param bool $strict
* @return static
*/
public function whereIn($key, array $values, $strict = true)
{
return $this->filter(function ($item) use ($key, $values, $strict) {
return in_array(data_get($item, $key), $values, $strict);
});
}
/**
* Filter items by the given key value pair using loose comparison.
*
* @param string $key
* @param array $values
* @return static
*/
public function whereInLoose($key, array $values)
{
return $this->whereIn($key, $values, false);
}
/**
* Get the first item from the collection.
*
* @param callable|null $callback
* @param mixed $default
* @return mixed
*/
public function first(callable $callback = null, $default = null)
{
return Arr::first($this->items, $callback, $default);
}
/**
* Get a flattened array of the items in the collection.
*
* @param int $depth
* @return static
*/
public function flatten($depth = INF)
{
return new static(Arr::flatten($this->items, $depth));
}
/**
* Flip the items in the collection.
*
* @return static
*/
public function flip()
{
return new static(array_flip($this->items));
}
/**
* Remove an item from the collection by key.
*
* @param string|array $keys
* @return $this
*/
public function forget($keys)
{
foreach ((array) $keys as $key) {
$this->offsetUnset($key);
}
return $this;
}
/**
* Get an item from the collection by key.
*
* @param mixed $key
* @param mixed $default
* @return mixed
*/
public function get($key, $default = null)
{
if ($this->offsetExists($key)) {
return $this->items[$key];
}
return value($default);
}
/**
* Group an associative array by a field or using a callback.
*
* @param callable|string $groupBy
* @param bool $preserveKeys
* @return static
*/
public function groupBy($groupBy, $preserveKeys = false)
{
$groupBy = $this->valueRetriever($groupBy);
$results = [];
foreach ($this->items as $key => $value) {
$groupKeys = $groupBy($value, $key);
if (! is_array($groupKeys)) {
$groupKeys = [$groupKeys];
}
foreach ($groupKeys as $groupKey) {
if (! array_key_exists($groupKey, $results)) {
$results[$groupKey] = new static;
}
$results[$groupKey]->offsetSet($preserveKeys ? $key : null, $value);
}
}
return new static($results);
}
/**
* Key an associative array by a field or using a callback.
*
* @param callable|string $keyBy
* @return static
*/
public function keyBy($keyBy)
{
$keyBy = $this->valueRetriever($keyBy);
$results = [];
foreach ($this->items as $item) {
$results[$keyBy($item)] = $item;
}
return new static($results);
}
/**
* Determine if an item exists in the collection by key.
*
* @param mixed $key
* @return bool
*/
public function has($key)
{
return $this->offsetExists($key);
}
/**
* Concatenate values of a given key as a string.
*
* @param string $value
* @param string $glue
* @return string
*/
public function implode($value, $glue = null)
{
$first = $this->first();
if (is_array($first) || is_object($first)) {
return implode($glue, $this->pluck($value)->all());
}
return implode($value, $this->items);
}
/**
* Intersect the collection with the given items.
*
* @param mixed $items
* @return static
*/
public function intersect($items)
{
return new static(array_intersect($this->items, $this->getArrayableItems($items)));
}
/**
* Determine if the collection is empty or not.
*
* @return bool
*/
public function isEmpty()
{
return empty($this->items);
}
/**
* Determine if the given value is callable, but not a string.
*
* @param mixed $value
* @return bool
*/
protected function useAsCallable($value)
{
return ! is_string($value) && is_callable($value);
}
/**
* Get the keys of the collection items.
*
* @return static
*/
public function keys()
{
return new static(array_keys($this->items));
}
/**
* Get the last item from the collection.
*
* @param callable|null $callback
* @param mixed $default
* @return mixed
*/
public function last(callable $callback = null, $default = null)
{
return Arr::last($this->items, $callback, $default);
}
/**
* Get the values of a given key.
*
* @param string $value
* @param string|null $key
* @return static
*/
public function pluck($value, $key = null)
{
return new static(Arr::pluck($this->items, $value, $key));
}
/**
* Alias for the "pluck" method.
*
* @param string $value
* @param string|null $key
* @return static
*
* @deprecated since version 5.2. Use the "pluck" method directly.
*/
public function lists($value, $key = null)
{
return $this->pluck($value, $key);
}
/**
* Run a map over each of the items.
*
* @param callable $callback
* @return static
*/
public function map(callable $callback)
{
$keys = array_keys($this->items);
$items = array_map($callback, $this->items, $keys);
return new static(array_combine($keys, $items));
}
/**
* Map a collection and flatten the result by a single level.
*
* @param callable $callback
* @return static
*/
public function flatMap(callable $callback)
{
return $this->map($callback)->collapse();
}
/**
* Get the max value of a given key.
*
* @param string|null $key
* @return mixed
*/
public function max($key = null)
{
return $this->reduce(function ($result, $item) use ($key) {
$value = data_get($item, $key);
return is_null($result) || $value > $result ? $value : $result;
});
}
/**
* Merge the collection with the given items.
*
* @param mixed $items
* @return static
*/
public function merge($items)
{
return new static(array_merge($this->items, $this->getArrayableItems($items)));
}
/**
* Create a collection by using this collection for keys and another for its values.
*
* @param mixed $values
* @return static
*/
public function combine($values)
{
return new static(array_combine($this->all(), $this->getArrayableItems($values)));
}
/**
* Union the collection with the given items.
*
* @param mixed $items
* @return void
*/
public function union($items)
{
return new static($this->items + $this->getArrayableItems($items));
}
/**
* Get the min value of a given key.
*
* @param string|null $key
* @return mixed
*/
public function min($key = null)
{
return $this->reduce(function ($result, $item) use ($key) {
$value = data_get($item, $key);
return is_null($result) || $value < $result ? $value : $result;
});
}
/**
* Get the items with the specified keys.
*
* @param mixed $keys
* @return static
*/
public function only($keys)
{
$keys = is_array($keys) ? $keys : func_get_args();
return new static(Arr::only($this->items, $keys));
}
/**
* "Paginate" the collection by slicing it into a smaller collection.
*
* @param int $page
* @param int $perPage
* @return static
*/
public function forPage($page, $perPage)
{
return $this->slice(($page - 1) * $perPage, $perPage);
}
/**
* Get and remove the last item from the collection.
*
* @return mixed
*/
public function pop()
{
return array_pop($this->items);
}
/**
* Push an item onto the beginning of the collection.
*
* @param mixed $value
* @param mixed $key
* @return $this
*/
public function prepend($value, $key = null)
{
$this->items = Arr::prepend($this->items, $value, $key);
return $this;
}
/**
* Push an item onto the end of the collection.
*
* @param mixed $value
* @return $this
*/
public function push($value)
{
$this->offsetSet(null, $value);
return $this;
}
/**
* Get and remove an item from the collection.
*
* @param mixed $key
* @param mixed $default
* @return mixed
*/
public function pull($key, $default = null)
{
return Arr::pull($this->items, $key, $default);
}
/**
* Put an item in the collection by key.
*
* @param mixed $key
* @param mixed $value
* @return $this
*/
public function put($key, $value)
{
$this->offsetSet($key, $value);
return $this;
}
/**
* Get one or more items randomly from the collection.
*
* @param int $amount
* @return mixed
*
* @throws \InvalidArgumentException
*/
public function random($amount = 1)
{
if ($amount > ($count = $this->count())) {
throw new InvalidArgumentException("You requested {$amount} items, but there are only {$count} items in the collection");
}
$keys = array_rand($this->items, $amount);
if ($amount == 1) {
return $this->items[$keys];
}
return new static(array_intersect_key($this->items, array_flip($keys)));
}
/**
* Reduce the collection to a single value.
*
* @param callable $callback
* @param mixed $initial
* @return mixed
*/
public function reduce(callable $callback, $initial = null)
{
return array_reduce($this->items, $callback, $initial);
}
/**
* Create a collection of all elements that do not pass a given truth test.
*
* @param callable|mixed $callback
* @return static
*/
public function reject($callback)
{
if ($this->useAsCallable($callback)) {
return $this->filter(function ($value, $key) use ($callback) {
return ! $callback($value, $key);
});
}
return $this->filter(function ($item) use ($callback) {
return $item != $callback;
});
}
/**
* Reverse items order.
*
* @return static
*/
public function reverse()
{
return new static(array_reverse($this->items, true));
}
/**
* Search the collection for a given value and return the corresponding key if successful.
*
* @param mixed $value
* @param bool $strict
* @return mixed
*/
public function search($value, $strict = false)
{
if (! $this->useAsCallable($value)) {
return array_search($value, $this->items, $strict);
}
foreach ($this->items as $key => $item) {
if (call_user_func($value, $item, $key)) {
return $key;
}
}
return false;
}
/**
* Get and remove the first item from the collection.
*
* @return mixed
*/
public function shift()
{
return array_shift($this->items);
}
/**
* Shuffle the items in the collection.
*
* @return static
*/
public function shuffle()
{
$items = $this->items;
shuffle($items);
return new static($items);
}
/**
* Slice the underlying collection array.
*
* @param int $offset
* @param int $length
* @return static
*/
public function slice($offset, $length = null)
{
return new static(array_slice($this->items, $offset, $length, true));
}
/**
* Chunk the underlying collection array.
*
* @param int $size
* @return static
*/
public function chunk($size)
{
$chunks = [];
foreach (array_chunk($this->items, $size, true) as $chunk) {
$chunks[] = new static($chunk);
}
return new static($chunks);
}
/**
* Sort through each item with a callback.
*
* @param callable|null $callback
* @return static
*/
public function sort(callable $callback = null)
{
$items = $this->items;
$callback ? uasort($items, $callback) : uasort($items, function ($a, $b) {
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
});
return new static($items);
}
/**
* Sort the collection using the given callback.
*
* @param callable|string $callback
* @param int $options
* @param bool $descending
* @return static
*/
public function sortBy($callback, $options = SORT_REGULAR, $descending = false)
{
$results = [];
$callback = $this->valueRetriever($callback);
// First we will loop through the items and get the comparator from a callback
// function which we were given. Then, we will sort the returned values and
// and grab the corresponding values for the sorted keys from this array.
foreach ($this->items as $key => $value) {
$results[$key] = $callback($value, $key);
}
$descending ? arsort($results, $options)
: asort($results, $options);
// Once we have sorted all of the keys in the array, we will loop through them
// and grab the corresponding model so we can set the underlying items list
// to the sorted version. Then we'll just return the collection instance.
foreach (array_keys($results) as $key) {
$results[$key] = $this->items[$key];
}
return new static($results);
}
/**
* Sort the collection in descending order using the given callback.
*
* @param callable|string $callback
* @param int $options
* @return static
*/
public function sortByDesc($callback, $options = SORT_REGULAR)
{
return $this->sortBy($callback, $options, true);
}
/**
* Splice a portion of the underlying collection array.
*
* @param int $offset
* @param int|null $length
* @param mixed $replacement
* @return static
*/
public function splice($offset, $length = null, $replacement = [])
{
if (func_num_args() == 1) {
return new static(array_splice($this->items, $offset));
}
return new static(array_splice($this->items, $offset, $length, $replacement));
}
/**
* Get the sum of the given values.
*
* @param callable|string|null $callback
* @return mixed
*/
public function sum($callback = null)
{
if (is_null($callback)) {
return array_sum($this->items);
}
$callback = $this->valueRetriever($callback);
return $this->reduce(function ($result, $item) use ($callback) {
return $result += $callback($item);
}, 0);
}
/**
* Take the first or last {$limit} items.
*
* @param int $limit
* @return static
*/
public function take($limit)
{
if ($limit < 0) {
return $this->slice($limit, abs($limit));
}
return $this->slice(0, $limit);
}
/**
* Transform each item in the collection using a callback.
*
* @param callable $callback
* @return $this
*/
public function transform(callable $callback)
{
$this->items = $this->map($callback)->all();
return $this;
}
/**
* Return only unique items from the collection array.
*
* @param string|callable|null $key
* @return static
*/
public function unique($key = null)
{
if (is_null($key)) {
return new static(array_unique($this->items, SORT_REGULAR));
}
$key = $this->valueRetriever($key);
$exists = [];
return $this->reject(function ($item) use ($key, &$exists) {
if (in_array($id = $key($item), $exists)) {
return true;
}
$exists[] = $id;
});
}
/**
* Reset the keys on the underlying array.
*
* @return static
*/
public function values()
{
return new static(array_values($this->items));
}
/**
* Get a value retrieving callback.
*
* @param string $value
* @return callable
*/
protected function valueRetriever($value)
{
if ($this->useAsCallable($value)) {
return $value;
}
return function ($item) use ($value) {
return data_get($item, $value);
};
}
/**
* Zip the collection together with one or more arrays.
*
* e.g. new Collection([1, 2, 3])->zip([4, 5, 6]);
* => [[1, 4], [2, 5], [3, 6]]
*
* @param mixed ...$items
* @return static
*/
public function zip($items)
{
$arrayableItems = array_map(function ($items) {
return $this->getArrayableItems($items);
}, func_get_args());
$params = array_merge([function () {
return new static(func_get_args());
}, $this->items], $arrayableItems);
return new static(call_user_func_array('array_map', $params));
}
/**
* Get the collection of items as a plain array.
*
* @return array
*/
public function toArray()
{
return array_map(function ($value) {
return $value instanceof Arrayable ? $value->toArray() : $value;
}, $this->items);
}
/**
* Convert the object into something JSON serializable.
*
* @return array
*/
public function jsonSerialize()
{
return array_map(function ($value) {
if ($value instanceof JsonSerializable) {
return $value->jsonSerialize();
} elseif ($value instanceof Jsonable) {
return json_decode($value->toJson(), true);
} elseif ($value instanceof Arrayable) {
return $value->toArray();
} else {
return $value;
}
}, $this->items);
}
/**
* Get the collection of items as JSON.
*
* @param int $options
* @return string
*/
public function toJson($options = 0)
{
return json_encode($this->jsonSerialize(), $options);
}
/**
* Get an iterator for the items.
*
* @return \ArrayIterator
*/
public function getIterator()
{
return new ArrayIterator($this->items);
}
/**
* Get a CachingIterator instance.
*
* @param int $flags
* @return \CachingIterator
*/
public function getCachingIterator($flags = CachingIterator::CALL_TOSTRING)
{
return new CachingIterator($this->getIterator(), $flags);
}
/**
* Count the number of items in the collection.
*
* @return int
*/
public function count()
{
return count($this->items);
}
/**
* Determine if an item exists at an offset.
*
* @param mixed $key
* @return bool
*/
public function offsetExists($key)
{
return array_key_exists($key, $this->items);
}
/**
* Get an item at a given offset.
*
* @param mixed $key
* @return mixed
*/
public function offsetGet($key)
{
return $this->items[$key];
}
/**
* Set the item at a given offset.
*
* @param mixed $key
* @param mixed $value
* @return void
*/
public function offsetSet($key, $value)
{
if (is_null($key)) {
$this->items[] = $value;
} else {
$this->items[$key] = $value;
}
}
/**
* Unset the item at a given offset.
*
* @param string $key
* @return void
*/
public function offsetUnset($key)
{
unset($this->items[$key]);
}
/**
* Convert the collection to its string representation.
*
* @return string
*/
public function __toString()
{
return $this->toJson();
}
/**
* Results array of items from Collection or Arrayable.
*
* @param mixed $items
* @return array
*/
protected function getArrayableItems($items)
{
if (is_array($items)) {
return $items;
} elseif ($items instanceof self) {
return $items->all();
} elseif ($items instanceof Arrayable) {
return $items->toArray();
} elseif ($items instanceof Jsonable) {
return json_decode($items->toJson(), true);
} elseif ($items instanceof JsonSerializable) {
return $items->jsonSerialize();
}
return (array) $items;
}
}
{
"name": "illuminate/support",
"description": "The Illuminate Support package.",
"license": "MIT",
"homepage": "http://laravel.com",
"support": {
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"authors": [
{
"name": "Taylor Otwell",
"email": "taylorotwell@gmail.com"
}
],
"require": {
"php": ">=5.5.9",
"ext-mbstring": "*",
"doctrine/inflector": "~1.0",
"illuminate/contracts": "5.2.*",
"paragonie/random_compat": "~1.4"
},
"autoload": {
"psr-4": {
"Illuminate\\Support\\": ""
},
"files": [
"helpers.php"
]
},
"extra": {
"branch-alias": {
"dev-master": "5.2-dev"
}
},
"suggest": {
"illuminate/filesystem": "Required to use the composer class (5.2.*).",
"jeremeamia/superclosure": "Required to be able to serialize closures (~2.2).",
"symfony/polyfill-php56": "Required to use the hash_equals function on PHP 5.5 (~1.0).",
"symfony/process": "Required to use the composer class (2.8.*|3.0.*).",
"symfony/var-dumper": "Improves the dd function (2.8.*|3.0.*)."
},
"minimum-stability": "dev"
}
<?php
namespace Illuminate\Support;
use Illuminate\Filesystem\Filesystem;
use Symfony\Component\Process\Process;
use Symfony\Component\Process\ProcessUtils;
use Symfony\Component\Process\PhpExecutableFinder;
class Composer
{
/**
* The filesystem instance.
*
* @var \Illuminate\Filesystem\Filesystem
*/
protected $files;
/**
* The working path to regenerate from.
*
* @var string
*/
protected $workingPath;
/**
* Create a new Composer manager instance.
*
* @param \Illuminate\Filesystem\Filesystem $files
* @param string|null $workingPath
* @return void
*/
public function __construct(Filesystem $files, $workingPath = null)
{
$this->files = $files;
$this->workingPath = $workingPath;
}
/**
* Regenerate the Composer autoloader files.
*
* @param string $extra
* @return void
*/
public function dumpAutoloads($extra = '')
{
$process = $this->getProcess();
$process->setCommandLine(trim($this->findComposer().' dump-autoload '.$extra));
$process->run();
}
/**
* Regenerate the optimized Composer autoloader files.
*
* @return void
*/
public function dumpOptimized()
{
$this->dumpAutoloads('--optimize');
}
/**
* Get the composer command for the environment.
*
* @return string
*/
protected function findComposer()
{
if (! $this->files->exists($this->workingPath.'/composer.phar')) {
return 'composer';
}
$binary = ProcessUtils::escapeArgument((new PhpExecutableFinder)->find(false));
if (defined('HHVM_VERSION')) {
$binary .= ' --php';
}
return "{$binary} composer.phar";
}
/**
* Get a new Symfony process instance.
*
* @return \Symfony\Component\Process\Process
*/
protected function getProcess()
{
return (new Process('', $this->workingPath))->setTimeout(null);
}
/**
* Set the working path used by the class.
*
* @param string $path
* @return $this
*/
public function setWorkingPath($path)
{
$this->workingPath = realpath($path);
return $this;
}
}
<?php
namespace Illuminate\Support\Debug;
use Symfony\Component\VarDumper\Dumper\CliDumper;
use Symfony\Component\VarDumper\Cloner\VarCloner;
class Dumper
{
/**
* Dump a value with elegance.
*
* @param mixed $value
* @return void
*/
public function dump($value)
{
if (class_exists(CliDumper::class)) {
$dumper = 'cli' === PHP_SAPI ? new CliDumper : new HtmlDumper;
$dumper->dump((new VarCloner)->cloneVar($value));
} else {
var_dump($value);
}
}
}
<?php
namespace Illuminate\Support\Debug;
use Symfony\Component\VarDumper\Dumper\HtmlDumper as SymfonyHtmlDumper;
class HtmlDumper extends SymfonyHtmlDumper
{
/**
* Colour definitions for output.
*
* @var array
*/
protected $styles = [
'default' => 'background-color:#fff; color:#222; line-height:1.2em; font-weight:normal; font:12px Monaco, Consolas, monospace; word-wrap: break-word; white-space: pre-wrap; position:relative; z-index:100000',
'num' => 'color:#a71d5d',
'const' => 'color:#795da3',
'str' => 'color:#df5000',
'cchr' => 'color:#222',
'note' => 'color:#a71d5d',
'ref' => 'color:#a0a0a0',
'public' => 'color:#795da3',
'protected' => 'color:#795da3',
'private' => 'color:#795da3',
'meta' => 'color:#b729d9',
'key' => 'color:#df5000',
'index' => 'color:#a71d5d',
];
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Foundation\Application
*/
class App extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'app';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Contracts\Console\Kernel
*/
class Artisan extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'Illuminate\Contracts\Console\Kernel';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Auth\AuthManager
* @see \Illuminate\Contracts\Auth\Factory
* @see \Illuminate\Contracts\Auth\Guard
* @see \Illuminate\Contracts\Auth\StatefulGuard
*/
class Auth extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'auth';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\View\Compilers\BladeCompiler
*/
class Blade extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return static::$app['view']->getEngineResolver()->resolve('blade')->getCompiler();
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Contracts\Bus\Dispatcher
*/
class Bus extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'Illuminate\Contracts\Bus\Dispatcher';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Cache\CacheManager
* @see \Illuminate\Cache\Repository
*/
class Cache extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'cache';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Config\Repository
*/
class Config extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'config';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Encryption\Encrypter
*/
class Crypt extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'encrypter';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Database\DatabaseManager
* @see \Illuminate\Database\Connection
*/
class DB extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'db';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Events\Dispatcher
*/
class Event extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'events';
}
}
<?php
namespace Illuminate\Support\Facades;
use Mockery;
use RuntimeException;
use Mockery\MockInterface;
abstract class Facade
{
/**
* The application instance being facaded.
*
* @var \Illuminate\Contracts\Foundation\Application
*/
protected static $app;
/**
* The resolved object instances.
*
* @var array
*/
protected static $resolvedInstance;
/**
* Hotswap the underlying instance behind the facade.
*
* @param mixed $instance
* @return void
*/
public static function swap($instance)
{
static::$resolvedInstance[static::getFacadeAccessor()] = $instance;
static::$app->instance(static::getFacadeAccessor(), $instance);
}
/**
* Initiate a mock expectation on the facade.
*
* @param mixed
* @return \Mockery\Expectation
*/
public static function shouldReceive()
{
$name = static::getFacadeAccessor();
if (static::isMock()) {
$mock = static::$resolvedInstance[$name];
} else {
$mock = static::createFreshMockInstance($name);
}
return call_user_func_array([$mock, 'shouldReceive'], func_get_args());
}
/**
* Create a fresh mock instance for the given class.
*
* @param string $name
* @return \Mockery\Expectation
*/
protected static function createFreshMockInstance($name)
{
static::$resolvedInstance[$name] = $mock = static::createMockByName($name);
$mock->shouldAllowMockingProtectedMethods();
if (isset(static::$app)) {
static::$app->instance($name, $mock);
}
return $mock;
}
/**
* Create a fresh mock instance for the given class.
*
* @param string $name
* @return \Mockery\Expectation
*/
protected static function createMockByName($name)
{
$class = static::getMockableClass($name);
return $class ? Mockery::mock($class) : Mockery::mock();
}
/**
* Determines whether a mock is set as the instance of the facade.
*
* @return bool
*/
protected static function isMock()
{
$name = static::getFacadeAccessor();
return isset(static::$resolvedInstance[$name]) && static::$resolvedInstance[$name] instanceof MockInterface;
}
/**
* Get the mockable class for the bound instance.
*
* @return string|null
*/
protected static function getMockableClass()
{
if ($root = static::getFacadeRoot()) {
return get_class($root);
}
}
/**
* Get the root object behind the facade.
*
* @return mixed
*/
public static function getFacadeRoot()
{
return static::resolveFacadeInstance(static::getFacadeAccessor());
}
/**
* Get the registered name of the component.
*
* @return string
*
* @throws \RuntimeException
*/
protected static function getFacadeAccessor()
{
throw new RuntimeException('Facade does not implement getFacadeAccessor method.');
}
/**
* Resolve the facade root instance from the container.
*
* @param string|object $name
* @return mixed
*/
protected static function resolveFacadeInstance($name)
{
if (is_object($name)) {
return $name;
}
if (isset(static::$resolvedInstance[$name])) {
return static::$resolvedInstance[$name];
}
return static::$resolvedInstance[$name] = static::$app[$name];
}
/**
* Clear a resolved facade instance.
*
* @param string $name
* @return void
*/
public static function clearResolvedInstance($name)
{
unset(static::$resolvedInstance[$name]);
}
/**
* Clear all of the resolved instances.
*
* @return void
*/
public static function clearResolvedInstances()
{
static::$resolvedInstance = [];
}
/**
* Get the application instance behind the facade.
*
* @return \Illuminate\Contracts\Foundation\Application
*/
public static function getFacadeApplication()
{
return static::$app;
}
/**
* Set the application instance.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @return void
*/
public static function setFacadeApplication($app)
{
static::$app = $app;
}
/**
* Handle dynamic, static calls to the object.
*
* @param string $method
* @param array $args
* @return mixed
*
* @throws \RuntimeException
*/
public static function __callStatic($method, $args)
{
$instance = static::getFacadeRoot();
if (! $instance) {
throw new RuntimeException('A facade root has not been set.');
}
switch (count($args)) {
case 0:
return $instance->$method();
case 1:
return $instance->$method($args[0]);
case 2:
return $instance->$method($args[0], $args[1]);
case 3:
return $instance->$method($args[0], $args[1], $args[2]);
case 4:
return $instance->$method($args[0], $args[1], $args[2], $args[3]);
default:
return call_user_func_array([$instance, $method], $args);
}
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Filesystem\Filesystem
*/
class File extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'files';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Contracts\Auth\Access\Gate
*/
class Gate extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'Illuminate\Contracts\Auth\Access\Gate';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Hashing\BcryptHasher
*/
class Hash extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'hash';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Http\Request
*/
class Input extends Facade
{
/**
* Get an item from the input data.
*
* This method is used for all request verbs (GET, POST, PUT, and DELETE)
*
* @param string $key
* @param mixed $default
* @return mixed
*/
public static function get($key = null, $default = null)
{
return static::$app['request']->input($key, $default);
}
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'request';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Translation\Translator
*/
class Lang extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'translator';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Log\Writer
*/
class Log extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'log';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Mail\Mailer
*/
class Mail extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'mailer';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Auth\Passwords\PasswordBroker
*/
class Password extends Facade
{
/**
* Constant representing a successfully sent reminder.
*
* @var string
*/
const RESET_LINK_SENT = 'passwords.sent';
/**
* Constant representing a successfully reset password.
*
* @var string
*/
const PASSWORD_RESET = 'passwords.reset';
/**
* Constant representing the user not found response.
*
* @var string
*/
const INVALID_USER = 'passwords.user';
/**
* Constant representing an invalid password.
*
* @var string
*/
const INVALID_PASSWORD = 'passwords.password';
/**
* Constant representing an invalid token.
*
* @var string
*/
const INVALID_TOKEN = 'passwords.token';
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'auth.password';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Queue\QueueManager
* @see \Illuminate\Queue\Queue
*/
class Queue extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'queue';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Routing\Redirector
*/
class Redirect extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'redirect';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Redis\Database
*/
class Redis extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'redis';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Http\Request
*/
class Request extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'request';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Contracts\Routing\ResponseFactory
*/
class Response extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'Illuminate\Contracts\Routing\ResponseFactory';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Routing\Router
*/
class Route extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'router';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Database\Schema\Builder
*/
class Schema extends Facade
{
/**
* Get a schema builder instance for a connection.
*
* @param string $name
* @return \Illuminate\Database\Schema\Builder
*/
public static function connection($name)
{
return static::$app['db']->connection($name)->getSchemaBuilder();
}
/**
* Get a schema builder instance for the default connection.
*
* @return \Illuminate\Database\Schema\Builder
*/
protected static function getFacadeAccessor()
{
return static::$app['db']->connection()->getSchemaBuilder();
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Session\SessionManager
* @see \Illuminate\Session\Store
*/
class Session extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'session';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Filesystem\FilesystemManager
*/
class Storage extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'filesystem';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Routing\UrlGenerator
*/
class URL extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'url';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\Validation\Factory
*/
class Validator extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'validator';
}
}
<?php
namespace Illuminate\Support\Facades;
/**
* @see \Illuminate\View\Factory
*/
class View extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'view';
}
}
<?php
namespace Illuminate\Support;
use ArrayAccess;
use JsonSerializable;
use Illuminate\Contracts\Support\Jsonable;
use Illuminate\Contracts\Support\Arrayable;
class Fluent implements ArrayAccess, Arrayable, Jsonable, JsonSerializable
{
/**
* All of the attributes set on the container.
*
* @var array
*/
protected $attributes = [];
/**
* Create a new fluent container instance.
*
* @param array|object $attributes
* @return void
*/
public function __construct($attributes = [])
{
foreach ($attributes as $key => $value) {
$this->attributes[$key] = $value;
}
}
/**
* Get an attribute from the container.
*
* @param string $key
* @param mixed $default
* @return mixed
*/
public function get($key, $default = null)
{
if (array_key_exists($key, $this->attributes)) {
return $this->attributes[$key];
}
return value($default);
}
/**
* Get the attributes from the container.
*
* @return array
*/
public function getAttributes()
{
return $this->attributes;
}
/**
* Convert the Fluent instance to an array.
*
* @return array
*/
public function toArray()
{
return $this->attributes;
}
/**
* Convert the object into something JSON serializable.
*
* @return array
*/
public function jsonSerialize()
{
return $this->toArray();
}
/**
* Convert the Fluent instance to JSON.
*
* @param int $options
* @return string
*/
public function toJson($options = 0)
{
return json_encode($this->jsonSerialize(), $options);
}
/**
* Determine if the given offset exists.
*
* @param string $offset
* @return bool
*/
public function offsetExists($offset)
{
return isset($this->{$offset});
}
/**
* Get the value for a given offset.
*
* @param string $offset
* @return mixed
*/
public function offsetGet($offset)
{
return $this->{$offset};
}
/**
* Set the value at the given offset.
*
* @param string $offset
* @param mixed $value
* @return void
*/
public function offsetSet($offset, $value)
{
$this->{$offset} = $value;
}
/**
* Unset the value at the given offset.
*
* @param string $offset
* @return void
*/
public function offsetUnset($offset)
{
unset($this->{$offset});
}
/**
* Handle dynamic calls to the container to set attributes.
*
* @param string $method
* @param array $parameters
* @return $this
*/
public function __call($method, $parameters)
{
$this->attributes[$method] = count($parameters) > 0 ? $parameters[0] : true;
return $this;
}
/**
* Dynamically retrieve the value of an attribute.
*
* @param string $key
* @return mixed
*/
public function __get($key)
{
return $this->get($key);
}
/**
* Dynamically set the value of an attribute.
*
* @param string $key
* @param mixed $value
* @return void
*/
public function __set($key, $value)
{
$this->attributes[$key] = $value;
}
/**
* Dynamically check if an attribute is set.
*
* @param string $key
* @return bool
*/
public function __isset($key)
{
return isset($this->attributes[$key]);
}
/**
* Dynamically unset an attribute.
*
* @param string $key
* @return void
*/
public function __unset($key)
{
unset($this->attributes[$key]);
}
}
<?php
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use Illuminate\Support\Collection;
use Illuminate\Support\Debug\Dumper;
use Illuminate\Contracts\Support\Htmlable;
if (! function_exists('append_config')) {
/**
* Assign high numeric IDs to a config item to force appending.
*
* @param array $array
* @return array
*/
function append_config(array $array)
{
$start = 9999;
foreach ($array as $key => $value) {
if (is_numeric($key)) {
$start++;
$array[$start] = Arr::pull($array, $key);
}
}
return $array;
}
}
if (! function_exists('array_add')) {
/**
* Add an element to an array using "dot" notation if it doesn't exist.
*
* @param array $array
* @param string $key
* @param mixed $value
* @return array
*/
function array_add($array, $key, $value)
{
return Arr::add($array, $key, $value);
}
}
if (! function_exists('array_build')) {
/**
* Build a new array using a callback.
*
* @param array $array
* @param callable $callback
* @return array
*
* @deprecated since version 5.2.
*/
function array_build($array, callable $callback)
{
return Arr::build($array, $callback);
}
}
if (! function_exists('array_collapse')) {
/**
* Collapse an array of arrays into a single array.
*
* @param array $array
* @return array
*/
function array_collapse($array)
{
return Arr::collapse($array);
}
}
if (! function_exists('array_divide')) {
/**
* Divide an array into two arrays. One with keys and the other with values.
*
* @param array $array
* @return array
*/
function array_divide($array)
{
return Arr::divide($array);
}
}
if (! function_exists('array_dot')) {
/**
* Flatten a multi-dimensional associative array with dots.
*
* @param array $array
* @param string $prepend
* @return array
*/
function array_dot($array, $prepend = '')
{
return Arr::dot($array, $prepend);
}
}
if (! function_exists('array_except')) {
/**
* Get all of the given array except for a specified array of items.
*
* @param array $array
* @param array|string $keys
* @return array
*/
function array_except($array, $keys)
{
return Arr::except($array, $keys);
}
}
if (! function_exists('array_first')) {
/**
* Return the first element in an array passing a given truth test.
*
* @param array $array
* @param callable|null $callback
* @param mixed $default
* @return mixed
*/
function array_first($array, callable $callback = null, $default = null)
{
return Arr::first($array, $callback, $default);
}
}
if (! function_exists('array_flatten')) {
/**
* Flatten a multi-dimensional array into a single level.
*
* @param array $array
* @param int $depth
* @return array
*/
function array_flatten($array, $depth = INF)
{
return Arr::flatten($array, $depth);
}
}
if (! function_exists('array_forget')) {
/**
* Remove one or many array items from a given array using "dot" notation.
*
* @param array $array
* @param array|string $keys
* @return void
*/
function array_forget(&$array, $keys)
{
return Arr::forget($array, $keys);
}
}
if (! function_exists('array_get')) {
/**
* Get an item from an array using "dot" notation.
*
* @param \ArrayAccess|array $array
* @param string $key
* @param mixed $default
* @return mixed
*/
function array_get($array, $key, $default = null)
{
return Arr::get($array, $key, $default);
}
}
if (! function_exists('array_has')) {
/**
* Check if an item exists in an array using "dot" notation.
*
* @param \ArrayAccess|array $array
* @param string $key
* @return bool
*/
function array_has($array, $key)
{
return Arr::has($array, $key);
}
}
if (! function_exists('array_last')) {
/**
* Return the last element in an array passing a given truth test.
*
* @param array $array
* @param callable|null $callback
* @param mixed $default
* @return mixed
*/
function array_last($array, callable $callback = null, $default = null)
{
return Arr::last($array, $callback, $default);
}
}
if (! function_exists('array_only')) {
/**
* Get a subset of the items from the given array.
*
* @param array $array
* @param array|string $keys
* @return array
*/
function array_only($array, $keys)
{
return Arr::only($array, $keys);
}
}
if (! function_exists('array_pluck')) {
/**
* Pluck an array of values from an array.
*
* @param array $array
* @param string|array $value
* @param string|array|null $key
* @return array
*/
function array_pluck($array, $value, $key = null)
{
return Arr::pluck($array, $value, $key);
}
}
if (! function_exists('array_prepend')) {
/**
* Push an item onto the beginning of an array.
*
* @param array $array
* @param mixed $value
* @param mixed $key
* @return array
*/
function array_prepend($array, $value, $key = null)
{
return Arr::prepend($array, $value, $key);
}
}
if (! function_exists('array_pull')) {
/**
* Get a value from the array, and remove it.
*
* @param array $array
* @param string $key
* @param mixed $default
* @return mixed
*/
function array_pull(&$array, $key, $default = null)
{
return Arr::pull($array, $key, $default);
}
}
if (! function_exists('array_set')) {
/**
* Set an array item to a given value using "dot" notation.
*
* If no key is given to the method, the entire array will be replaced.
*
* @param array $array
* @param string $key
* @param mixed $value
* @return array
*/
function array_set(&$array, $key, $value)
{
return Arr::set($array, $key, $value);
}
}
if (! function_exists('array_sort')) {
/**
* Sort the array using the given callback.
*
* @param array $array
* @param callable $callback
* @return array
*/
function array_sort($array, callable $callback)
{
return Arr::sort($array, $callback);
}
}
if (! function_exists('array_sort_recursive')) {
/**
* Recursively sort an array by keys and values.
*
* @param array $array
* @return array
*/
function array_sort_recursive($array)
{
return Arr::sortRecursive($array);
}
}
if (! function_exists('array_where')) {
/**
* Filter the array using the given callback.
*
* @param array $array
* @param callable $callback
* @return array
*/
function array_where($array, callable $callback)
{
return Arr::where($array, $callback);
}
}
if (! function_exists('camel_case')) {
/**
* Convert a value to camel case.
*
* @param string $value
* @return string
*/
function camel_case($value)
{
return Str::camel($value);
}
}
if (! function_exists('class_basename')) {
/**
* Get the class "basename" of the given object / class.
*
* @param string|object $class
* @return string
*/
function class_basename($class)
{
$class = is_object($class) ? get_class($class) : $class;
return basename(str_replace('\\', '/', $class));
}
}
if (! function_exists('class_uses_recursive')) {
/**
* Returns all traits used by a class, its subclasses and trait of their traits.
*
* @param string $class
* @return array
*/
function class_uses_recursive($class)
{
$results = [];
foreach (array_merge([$class => $class], class_parents($class)) as $class) {
$results += trait_uses_recursive($class);
}
return array_unique($results);
}
}
if (! function_exists('collect')) {
/**
* Create a collection from the given value.
*
* @param mixed $value
* @return \Illuminate\Support\Collection
*/
function collect($value = null)
{
return new Collection($value);
}
}
if (! function_exists('data_fill')) {
/**
* Fill in data where it's missing.
*
* @param mixed $target
* @param string|array $key
* @param mixed $value
* @return mixed
*/
function data_fill(&$target, $key, $value)
{
return data_set($target, $key, $value, false);
}
}
if (! function_exists('data_get')) {
/**
* Get an item from an array or object using "dot" notation.
*
* @param mixed $target
* @param string|array $key
* @param mixed $default
* @return mixed
*/
function data_get($target, $key, $default = null)
{
if (is_null($key)) {
return $target;
}
$key = is_array($key) ? $key : explode('.', $key);
while (($segment = array_shift($key)) !== null) {
if ($segment === '*') {
if ($target instanceof Collection) {
$target = $target->all();
} elseif (! is_array($target)) {
return value($default);
}
$result = Arr::pluck($target, $key);
return in_array('*', $key) ? Arr::collapse($result) : $result;
}
if (Arr::accessible($target) && Arr::exists($target, $segment)) {
$target = $target[$segment];
} elseif (is_object($target) && isset($target->{$segment})) {
$target = $target->{$segment};
} else {
return value($default);
}
}
return $target;
}
}
if (! function_exists('data_set')) {
/**
* Set an item on an array or object using dot notation.
*
* @param mixed $target
* @param string|array $key
* @param mixed $value
* @param bool $overwrite
* @return mixed
*/
function data_set(&$target, $key, $value, $overwrite = true)
{
$segments = is_array($key) ? $key : explode('.', $key);
if (($segment = array_shift($segments)) === '*') {
if (! Arr::accessible($target)) {
$target = [];
}
if ($segments) {
foreach ($target as &$inner) {
data_set($inner, $segments, $value, $overwrite);
}
} elseif ($overwrite) {
foreach ($target as &$inner) {
$inner = $value;
}
}
} elseif (Arr::accessible($target)) {
if ($segments) {
if (! Arr::exists($target, $segment)) {
$target[$segment] = [];
}
data_set($target[$segment], $segments, $value, $overwrite);
} elseif ($overwrite || ! Arr::exists($target, $segment)) {
$target[$segment] = $value;
}
} elseif (is_object($target)) {
if ($segments) {
if (! isset($target->{$segment})) {
$target->{$segment} = [];
}
data_set($target->{$segment}, $segments, $value, $overwrite);
} elseif ($overwrite || ! isset($target->{$segment})) {
$target->{$segment} = $value;
}
}
return $target;
}
}
if (! function_exists('dd')) {
/**
* Dump the passed variables and end the script.
*
* @param mixed
* @return void
*/
function dd()
{
array_map(function ($x) {
(new Dumper)->dump($x);
}, func_get_args());
die(1);
}
}
if (! function_exists('e')) {
/**
* Escape HTML entities in a string.
*
* @param \Illuminate\Contracts\Support\Htmlable|string $value
* @return string
*/
function e($value)
{
if ($value instanceof Htmlable) {
return $value->toHtml();
}
return htmlentities($value, ENT_QUOTES, 'UTF-8', false);
}
}
if (! function_exists('ends_with')) {
/**
* Determine if a given string ends with a given substring.
*
* @param string $haystack
* @param string|array $needles
* @return bool
*/
function ends_with($haystack, $needles)
{
return Str::endsWith($haystack, $needles);
}
}
if (! function_exists('head')) {
/**
* Get the first element of an array. Useful for method chaining.
*
* @param array $array
* @return mixed
*/
function head($array)
{
return reset($array);
}
}
if (! function_exists('last')) {
/**
* Get the last element from an array.
*
* @param array $array
* @return mixed
*/
function last($array)
{
return end($array);
}
}
if (! function_exists('object_get')) {
/**
* Get an item from an object using "dot" notation.
*
* @param object $object
* @param string $key
* @param mixed $default
* @return mixed
*/
function object_get($object, $key, $default = null)
{
if (is_null($key) || trim($key) == '') {
return $object;
}
foreach (explode('.', $key) as $segment) {
if (! is_object($object) || ! isset($object->{$segment})) {
return value($default);
}
$object = $object->{$segment};
}
return $object;
}
}
if (! function_exists('preg_replace_sub')) {
/**
* Replace a given pattern with each value in the array in sequentially.
*
* @param string $pattern
* @param array $replacements
* @param string $subject
* @return string
*/
function preg_replace_sub($pattern, &$replacements, $subject)
{
return preg_replace_callback($pattern, function ($match) use (&$replacements) {
foreach ($replacements as $key => $value) {
return array_shift($replacements);
}
}, $subject);
}
}
if (! function_exists('snake_case')) {
/**
* Convert a string to snake case.
*
* @param string $value
* @param string $delimiter
* @return string
*/
function snake_case($value, $delimiter = '_')
{
return Str::snake($value, $delimiter);
}
}
if (! function_exists('starts_with')) {
/**
* Determine if a given string starts with a given substring.
*
* @param string $haystack
* @param string|array $needles
* @return bool
*/
function starts_with($haystack, $needles)
{
return Str::startsWith($haystack, $needles);
}
}
if (! function_exists('str_contains')) {
/**
* Determine if a given string contains a given substring.
*
* @param string $haystack
* @param string|array $needles
* @return bool
*/
function str_contains($haystack, $needles)
{
return Str::contains($haystack, $needles);
}
}
if (! function_exists('str_finish')) {
/**
* Cap a string with a single instance of a given value.
*
* @param string $value
* @param string $cap
* @return string
*/
function str_finish($value, $cap)
{
return Str::finish($value, $cap);
}
}
if (! function_exists('str_is')) {
/**
* Determine if a given string matches a given pattern.
*
* @param string $pattern
* @param string $value
* @return bool
*/
function str_is($pattern, $value)
{
return Str::is($pattern, $value);
}
}
if (! function_exists('str_limit')) {
/**
* Limit the number of characters in a string.
*
* @param string $value
* @param int $limit
* @param string $end
* @return string
*/
function str_limit($value, $limit = 100, $end = '...')
{
return Str::limit($value, $limit, $end);
}
}
if (! function_exists('str_plural')) {
/**
* Get the plural form of an English word.
*
* @param string $value
* @param int $count
* @return string
*/
function str_plural($value, $count = 2)
{
return Str::plural($value, $count);
}
}
if (! function_exists('str_random')) {
/**
* Generate a more truly "random" alpha-numeric string.
*
* @param int $length
* @return string
*
* @throws \RuntimeException
*/
function str_random($length = 16)
{
return Str::random($length);
}
}
if (! function_exists('str_replace_array')) {
/**
* Replace a given value in the string sequentially with an array.
*
* @param string $search
* @param array $replace
* @param string $subject
* @return string
*/
function str_replace_array($search, array $replace, $subject)
{
foreach ($replace as $value) {
$subject = preg_replace('/'.$search.'/', $value, $subject, 1);
}
return $subject;
}
}
if (! function_exists('str_replace_first')) {
/**
* Replace the first occurrence of a given value in the string.
*
* @param string $search
* @param string $replace
* @param string $subject
* @return string
*/
function str_replace_first($search, $replace, $subject)
{
return Str::replaceFirst($search, $replace, $subject);
}
}
if (! function_exists('str_replace_last')) {
/**
* Replace the last occurrence of a given value in the string.
*
* @param string $search
* @param string $replace
* @param string $subject
* @return string
*/
function str_replace_last($search, $replace, $subject)
{
return Str::replaceLast($search, $replace, $subject);
}
}
if (! function_exists('str_singular')) {
/**
* Get the singular form of an English word.
*
* @param string $value
* @return string
*/
function str_singular($value)
{
return Str::singular($value);
}
}
if (! function_exists('str_slug')) {
/**
* Generate a URL friendly "slug" from a given string.
*
* @param string $title
* @param string $separator
* @return string
*/
function str_slug($title, $separator = '-')
{
return Str::slug($title, $separator);
}
}
if (! function_exists('studly_case')) {
/**
* Convert a value to studly caps case.
*
* @param string $value
* @return string
*/
function studly_case($value)
{
return Str::studly($value);
}
}
if (! function_exists('title_case')) {
/**
* Convert a value to title case.
*
* @param string $value
* @return string
*/
function title_case($value)
{
return Str::title($value);
}
}
if (! function_exists('trait_uses_recursive')) {
/**
* Returns all traits used by a trait and its traits.
*
* @param string $trait
* @return array
*/
function trait_uses_recursive($trait)
{
$traits = class_uses($trait);
foreach ($traits as $trait) {
$traits += trait_uses_recursive($trait);
}
return $traits;
}
}
if (! function_exists('value')) {
/**
* Return the default value of the given value.
*
* @param mixed $value
* @return mixed
*/
function value($value)
{
return $value instanceof Closure ? $value() : $value;
}
}
if (! function_exists('windows_os')) {
/**
* Determine whether the current envrionment is Windows based.
*
* @return bool
*/
function windows_os()
{
return strtolower(substr(PHP_OS, 0, 3)) === 'win';
}
}
if (! function_exists('with')) {
/**
* Return the given object. Useful for chaining.
*
* @param mixed $object
* @return mixed
*/
function with($object)
{
return $object;
}
}
<?php
namespace Illuminate\Support;
use Illuminate\Contracts\Support\Htmlable;
class HtmlString implements Htmlable
{
/**
* The HTML string.
*
* @var string
*/
protected $html;
/**
* Create a new HTML string instance.
*
* @param string $html
* @return void
*/
public function __construct($html)
{
$this->html = $html;
}
/**
* Get the the HTML string.
*
* @return string
*/
public function toHtml()
{
return $this->html;
}
/**
* Get the the HTML string.
*
* @return string
*/
public function __toString()
{
return $this->toHtml();
}
}
<?php
namespace Illuminate\Support;
use Closure;
use InvalidArgumentException;
abstract class Manager
{
/**
* The application instance.
*
* @var \Illuminate\Foundation\Application
*/
protected $app;
/**
* The registered custom driver creators.
*
* @var array
*/
protected $customCreators = [];
/**
* The array of created "drivers".
*
* @var array
*/
protected $drivers = [];
/**
* Create a new manager instance.
*
* @param \Illuminate\Foundation\Application $app
* @return void
*/
public function __construct($app)
{
$this->app = $app;
}
/**
* Get the default driver name.
*
* @return string
*/
abstract public function getDefaultDriver();
/**
* Get a driver instance.
*
* @param string $driver
* @return mixed
*/
public function driver($driver = null)
{
$driver = $driver ?: $this->getDefaultDriver();
// If the given driver has not been created before, we will create the instances
// here and cache it so we can return it next time very quickly. If there is
// already a driver created by this name, we'll just return that instance.
if (! isset($this->drivers[$driver])) {
$this->drivers[$driver] = $this->createDriver($driver);
}
return $this->drivers[$driver];
}
/**
* Create a new driver instance.
*
* @param string $driver
* @return mixed
*
* @throws \InvalidArgumentException
*/
protected function createDriver($driver)
{
$method = 'create'.Str::studly($driver).'Driver';
// We'll check to see if a creator method exists for the given driver. If not we
// will check for a custom driver creator, which allows developers to create
// drivers using their own customized driver creator Closure to create it.
if (isset($this->customCreators[$driver])) {
return $this->callCustomCreator($driver);
} elseif (method_exists($this, $method)) {
return $this->$method();
}
throw new InvalidArgumentException("Driver [$driver] not supported.");
}
/**
* Call a custom driver creator.
*
* @param string $driver
* @return mixed
*/
protected function callCustomCreator($driver)
{
return $this->customCreators[$driver]($this->app);
}
/**
* Register a custom driver creator Closure.
*
* @param string $driver
* @param \Closure $callback
* @return $this
*/
public function extend($driver, Closure $callback)
{
$this->customCreators[$driver] = $callback;
return $this;
}
/**
* Get all of the created "drivers".
*
* @return array
*/
public function getDrivers()
{
return $this->drivers;
}
/**
* Dynamically call the default driver instance.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
return call_user_func_array([$this->driver(), $method], $parameters);
}
}
<?php
namespace Illuminate\Support;
use Countable;
use JsonSerializable;
use Illuminate\Contracts\Support\Jsonable;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\Contracts\Support\MessageProvider;
use Illuminate\Contracts\Support\MessageBag as MessageBagContract;
class MessageBag implements Arrayable, Countable, Jsonable, JsonSerializable, MessageBagContract, MessageProvider
{
/**
* All of the registered messages.
*
* @var array
*/
protected $messages = [];
/**
* Default format for message output.
*
* @var string
*/
protected $format = ':message';
/**
* Create a new message bag instance.
*
* @param array $messages
* @return void
*/
public function __construct(array $messages = [])
{
foreach ($messages as $key => $value) {
$this->messages[$key] = (array) $value;
}
}
/**
* Get the keys present in the message bag.
*
* @return array
*/
public function keys()
{
return array_keys($this->messages);
}
/**
* Add a message to the bag.
*
* @param string $key
* @param string $message
* @return $this
*/
public function add($key, $message)
{
if ($this->isUnique($key, $message)) {
$this->messages[$key][] = $message;
}
return $this;
}
/**
* Merge a new array of messages into the bag.
*
* @param \Illuminate\Contracts\Support\MessageProvider|array $messages
* @return $this
*/
public function merge($messages)
{
if ($messages instanceof MessageProvider) {
$messages = $messages->getMessageBag()->getMessages();
}
$this->messages = array_merge_recursive($this->messages, $messages);
return $this;
}
/**
* Determine if a key and message combination already exists.
*
* @param string $key
* @param string $message
* @return bool
*/
protected function isUnique($key, $message)
{
$messages = (array) $this->messages;
return ! isset($messages[$key]) || ! in_array($message, $messages[$key]);
}
/**
* Determine if messages exist for a given key.
*
* @param string $key
* @return bool
*/
public function has($key = null)
{
return $this->first($key) !== '';
}
/**
* Get the first message from the bag for a given key.
*
* @param string $key
* @param string $format
* @return string
*/
public function first($key = null, $format = null)
{
$messages = is_null($key) ? $this->all($format) : $this->get($key, $format);
return count($messages) > 0 ? $messages[0] : '';
}
/**
* Get all of the messages from the bag for a given key.
*
* @param string $key
* @param string $format
* @return array
*/
public function get($key, $format = null)
{
// If the message exists in the container, we will transform it and return
// the message. Otherwise, we'll return an empty array since the entire
// methods is to return back an array of messages in the first place.
if (array_key_exists($key, $this->messages)) {
return $this->transform($this->messages[$key], $this->checkFormat($format), $key);
}
return [];
}
/**
* Get all of the messages for every key in the bag.
*
* @param string $format
* @return array
*/
public function all($format = null)
{
$format = $this->checkFormat($format);
$all = [];
foreach ($this->messages as $key => $messages) {
$all = array_merge($all, $this->transform($messages, $format, $key));
}
return $all;
}
/**
* Get all of the unique messages for every key in the bag.
*
* @param string $format
* @return array
*/
public function unique($format = null)
{
return array_unique($this->all($format));
}
/**
* Format an array of messages.
*
* @param array $messages
* @param string $format
* @param string $messageKey
* @return array
*/
protected function transform($messages, $format, $messageKey)
{
$messages = (array) $messages;
// We will simply spin through the given messages and transform each one
// replacing the :message place holder with the real message allowing
// the messages to be easily formatted to each developer's desires.
$replace = [':message', ':key'];
foreach ($messages as &$message) {
$message = str_replace($replace, [$message, $messageKey], $format);
}
return $messages;
}
/**
* Get the appropriate format based on the given format.
*
* @param string $format
* @return string
*/
protected function checkFormat($format)
{
return $format ?: $this->format;
}
/**
* Get the raw messages in the container.
*
* @return array
*/
public function messages()
{
return $this->messages;
}
/**
* Get the raw messages in the container.
*
* @return array
*/
public function getMessages()
{
return $this->messages();
}
/**
* Get the messages for the instance.
*
* @return \Illuminate\Support\MessageBag
*/
public function getMessageBag()
{
return $this;
}
/**
* Get the default message format.
*
* @return string
*/
public function getFormat()
{
return $this->format;
}
/**
* Set the default message format.
*
* @param string $format
* @return \Illuminate\Support\MessageBag
*/
public function setFormat($format = ':message')
{
$this->format = $format;
return $this;
}
/**
* Determine if the message bag has any messages.
*
* @return bool
*/
public function isEmpty()
{
return ! $this->any();
}
/**
* Determine if the message bag has any messages.
*
* @return bool
*/
public function any()
{
return $this->count() > 0;
}
/**
* Get the number of messages in the container.
*
* @return int
*/
public function count()
{
return count($this->messages, COUNT_RECURSIVE) - count($this->messages);
}
/**
* Get the instance as an array.
*
* @return array
*/
public function toArray()
{
return $this->getMessages();
}
/**
* Convert the object into something JSON serializable.
*
* @return array
*/
public function jsonSerialize()
{
return $this->toArray();
}
/**
* Convert the object to its JSON representation.
*
* @param int $options
* @return string
*/
public function toJson($options = 0)
{
return json_encode($this->jsonSerialize(), $options);
}
/**
* Convert the message bag to its string representation.
*
* @return string
*/
public function __toString()
{
return $this->toJson();
}
}
<?php
namespace Illuminate\Support;
class NamespacedItemResolver
{
/**
* A cache of the parsed items.
*
* @var array
*/
protected $parsed = [];
/**
* Parse a key into namespace, group, and item.
*
* @param string $key
* @return array
*/
public function parseKey($key)
{
// If we've already parsed the given key, we'll return the cached version we
// already have, as this will save us some processing. We cache off every
// key we parse so we can quickly return it on all subsequent requests.
if (isset($this->parsed[$key])) {
return $this->parsed[$key];
}
// If the key does not contain a double colon, it means the key is not in a
// namespace, and is just a regular configuration item. Namespaces are a
// tool for organizing configuration items for things such as modules.
if (strpos($key, '::') === false) {
$segments = explode('.', $key);
$parsed = $this->parseBasicSegments($segments);
} else {
$parsed = $this->parseNamespacedSegments($key);
}
// Once we have the parsed array of this key's elements, such as its groups
// and namespace, we will cache each array inside a simple list that has
// the key and the parsed array for quick look-ups for later requests.
return $this->parsed[$key] = $parsed;
}
/**
* Parse an array of basic segments.
*
* @param array $segments
* @return array
*/
protected function parseBasicSegments(array $segments)
{
// The first segment in a basic array will always be the group, so we can go
// ahead and grab that segment. If there is only one total segment we are
// just pulling an entire group out of the array and not a single item.
$group = $segments[0];
if (count($segments) == 1) {
return [null, $group, null];
}
// If there is more than one segment in this group, it means we are pulling
// a specific item out of a groups and will need to return the item name
// as well as the group so we know which item to pull from the arrays.
else {
$item = implode('.', array_slice($segments, 1));
return [null, $group, $item];
}
}
/**
* Parse an array of namespaced segments.
*
* @param string $key
* @return array
*/
protected function parseNamespacedSegments($key)
{
list($namespace, $item) = explode('::', $key);
// First we'll just explode the first segment to get the namespace and group
// since the item should be in the remaining segments. Once we have these
// two pieces of data we can proceed with parsing out the item's value.
$itemSegments = explode('.', $item);
$groupAndItem = array_slice($this->parseBasicSegments($itemSegments), 1);
return array_merge([$namespace], $groupAndItem);
}
/**
* Set the parsed value of a key.
*
* @param string $key
* @param array $parsed
* @return void
*/
public function setParsedKey($key, $parsed)
{
$this->parsed[$key] = $parsed;
}
}
<?php
namespace Illuminate\Support;
use Doctrine\Common\Inflector\Inflector;
class Pluralizer
{
/**
* Uncountable word forms.
*
* @var array
*/
public static $uncountable = [
'audio',
'bison',
'chassis',
'compensation',
'coreopsis',
'data',
'deer',
'education',
'equipment',
'fish',
'gold',
'information',
'knowledge',
'love',
'rain',
'money',
'moose',
'nutrition',
'offspring',
'plankton',
'police',
'rice',
'series',
'sheep',
'species',
'swine',
'traffic',
];
/**
* Get the plural form of an English word.
*
* @param string $value
* @param int $count
* @return string
*/
public static function plural($value, $count = 2)
{
if ($count === 1 || static::uncountable($value)) {
return $value;
}
$plural = Inflector::pluralize($value);
return static::matchCase($plural, $value);
}
/**
* Get the singular form of an English word.
*
* @param string $value
* @return string
*/
public static function singular($value)
{
$singular = Inflector::singularize($value);
return static::matchCase($singular, $value);
}
/**
* Determine if the given value is uncountable.
*
* @param string $value
* @return bool
*/
protected static function uncountable($value)
{
return in_array(strtolower($value), static::$uncountable);
}
/**
* Attempt to match the case on two strings.
*
* @param string $value
* @param string $comparison
* @return string
*/
protected static function matchCase($value, $comparison)
{
$functions = ['mb_strtolower', 'mb_strtoupper', 'ucfirst', 'ucwords'];
foreach ($functions as $function) {
if (call_user_func($function, $comparison) === $comparison) {
return call_user_func($function, $value);
}
}
return $value;
}
}
<?php
namespace Illuminate\Support;
use BadMethodCallException;
use Illuminate\Console\Events\ArtisanStarting;
abstract class ServiceProvider
{
/**
* The application instance.
*
* @var \Illuminate\Contracts\Foundation\Application
*/
protected $app;
/**
* Indicates if loading of the provider is deferred.
*
* @var bool
*/
protected $defer = false;
/**
* The paths that should be published.
*
* @var array
*/
protected static $publishes = [];
/**
* The paths that should be published by group.
*
* @var array
*/
protected static $publishGroups = [];
/**
* Create a new service provider instance.
*
* @param \Illuminate\Contracts\Foundation\Application $app
* @return void
*/
public function __construct($app)
{
$this->app = $app;
}
/**
* Register the service provider.
*
* @return void
*/
abstract public function register();
/**
* Merge the given configuration with the existing configuration.
*
* @param string $path
* @param string $key
* @return void
*/
protected function mergeConfigFrom($path, $key)
{
$config = $this->app['config']->get($key, []);
$this->app['config']->set($key, array_merge(require $path, $config));
}
/**
* Register a view file namespace.
*
* @param string $path
* @param string $namespace
* @return void
*/
protected function loadViewsFrom($path, $namespace)
{
if (is_dir($appPath = $this->app->basePath().'/resources/views/vendor/'.$namespace)) {
$this->app['view']->addNamespace($namespace, $appPath);
}
$this->app['view']->addNamespace($namespace, $path);
}
/**
* Register a translation file namespace.
*
* @param string $path
* @param string $namespace
* @return void
*/
protected function loadTranslationsFrom($path, $namespace)
{
$this->app['translator']->addNamespace($namespace, $path);
}
/**
* Register paths to be published by the publish command.
*
* @param array $paths
* @param string $group
* @return void
*/
protected function publishes(array $paths, $group = null)
{
$class = static::class;
if (! array_key_exists($class, static::$publishes)) {
static::$publishes[$class] = [];
}
static::$publishes[$class] = array_merge(static::$publishes[$class], $paths);
if ($group) {
if (! array_key_exists($group, static::$publishGroups)) {
static::$publishGroups[$group] = [];
}
static::$publishGroups[$group] = array_merge(static::$publishGroups[$group], $paths);
}
}
/**
* Get the paths to publish.
*
* @param string $provider
* @param string $group
* @return array
*/
public static function pathsToPublish($provider = null, $group = null)
{
if ($provider && $group) {
if (empty(static::$publishes[$provider]) || empty(static::$publishGroups[$group])) {
return [];
}
return array_intersect_key(static::$publishes[$provider], static::$publishGroups[$group]);
}
if ($group && array_key_exists($group, static::$publishGroups)) {
return static::$publishGroups[$group];
}
if ($provider && array_key_exists($provider, static::$publishes)) {
return static::$publishes[$provider];
}
if ($group || $provider) {
return [];
}
$paths = [];
foreach (static::$publishes as $class => $publish) {
$paths = array_merge($paths, $publish);
}
return $paths;
}
/**
* Register the package's custom Artisan commands.
*
* @param array|mixed $commands
* @return void
*/
public function commands($commands)
{
$commands = is_array($commands) ? $commands : func_get_args();
// To register the commands with Artisan, we will grab each of the arguments
// passed into the method and listen for Artisan "start" event which will
// give us the Artisan console instance which we will give commands to.
$events = $this->app['events'];
$events->listen(ArtisanStarting::class, function ($event) use ($commands) {
$event->artisan->resolveCommands($commands);
});
}
/**
* Get the services provided by the provider.
*
* @return array
*/
public function provides()
{
return [];
}
/**
* Get the events that trigger this service provider to register.
*
* @return array
*/
public function when()
{
return [];
}
/**
* Determine if the provider is deferred.
*
* @return bool
*/
public function isDeferred()
{
return $this->defer;
}
/**
* Get a list of files that should be compiled for the package.
*
* @return array
*/
public static function compiles()
{
return [];
}
/**
* Dynamically handle missing method calls.
*
* @param string $method
* @param array $parameters
* @return mixed
*
* @throws \BadMethodCallException
*/
public function __call($method, $parameters)
{
if ($method == 'boot') {
return;
}
throw new BadMethodCallException("Call to undefined method [{$method}]");
}
}
<?php
namespace Illuminate\Support;
use Illuminate\Support\Traits\Macroable;
class Str
{
use Macroable;
/**
* The cache of snake-cased words.
*
* @var array
*/
protected static $snakeCache = [];
/**
* The cache of camel-cased words.
*
* @var array
*/
protected static $camelCache = [];
/**
* The cache of studly-cased words.
*
* @var array
*/
protected static $studlyCache = [];
/**
* Transliterate a UTF-8 value to ASCII.
*
* @param string $value
* @return string
*/
public static function ascii($value)
{
foreach (static::charsArray() as $key => $val) {
$value = str_replace($val, $key, $value);
}
return preg_replace('/[^\x20-\x7E]/u', '', $value);
}
/**
* Convert a value to camel case.
*
* @param string $value
* @return string
*/
public static function camel($value)
{
if (isset(static::$camelCache[$value])) {
return static::$camelCache[$value];
}
return static::$camelCache[$value] = lcfirst(static::studly($value));
}
/**
* Determine if a given string contains a given substring.
*
* @param string $haystack
* @param string|array $needles
* @return bool
*/
public static function contains($haystack, $needles)
{
foreach ((array) $needles as $needle) {
if ($needle != '' && strpos($haystack, $needle) !== false) {
return true;
}
}
return false;
}
/**
* Determine if a given string ends with a given substring.
*
* @param string $haystack
* @param string|array $needles
* @return bool
*/
public static function endsWith($haystack, $needles)
{
foreach ((array) $needles as $needle) {
if ((string) $needle === substr($haystack, -strlen($needle))) {
return true;
}
}
return false;
}
/**
* Cap a string with a single instance of a given value.
*
* @param string $value
* @param string $cap
* @return string
*/
public static function finish($value, $cap)
{
$quoted = preg_quote($cap, '/');
return preg_replace('/(?:'.$quoted.')+$/', '', $value).$cap;
}
/**
* Determine if a given string matches a given pattern.
*
* @param string $pattern
* @param string $value
* @return bool
*/
public static function is($pattern, $value)
{
if ($pattern == $value) {
return true;
}
$pattern = preg_quote($pattern, '#');
// Asterisks are translated into zero-or-more regular expression wildcards
// to make it convenient to check if the strings starts with the given
// pattern such as "library/*", making any string check convenient.
$pattern = str_replace('\*', '.*', $pattern);
return (bool) preg_match('#^'.$pattern.'\z#', $value);
}
/**
* Return the length of the given string.
*
* @param string $value
* @return int
*/
public static function length($value)
{
return mb_strlen($value);
}
/**
* Limit the number of characters in a string.
*
* @param string $value
* @param int $limit
* @param string $end
* @return string
*/
public static function limit($value, $limit = 100, $end = '...')
{
if (mb_strwidth($value, 'UTF-8') <= $limit) {
return $value;
}
return rtrim(mb_strimwidth($value, 0, $limit, '', 'UTF-8')).$end;
}
/**
* Convert the given string to lower-case.
*
* @param string $value
* @return string
*/
public static function lower($value)
{
return mb_strtolower($value, 'UTF-8');
}
/**
* Limit the number of words in a string.
*
* @param string $value
* @param int $words
* @param string $end
* @return string
*/
public static function words($value, $words = 100, $end = '...')
{
preg_match('/^\s*+(?:\S++\s*+){1,'.$words.'}/u', $value, $matches);
if (! isset($matches[0]) || strlen($value) === strlen($matches[0])) {
return $value;
}
return rtrim($matches[0]).$end;
}
/**
* Parse a Class@method style callback into class and method.
*
* @param string $callback
* @param string $default
* @return array
*/
public static function parseCallback($callback, $default)
{
return static::contains($callback, '@') ? explode('@', $callback, 2) : [$callback, $default];
}
/**
* Get the plural form of an English word.
*
* @param string $value
* @param int $count
* @return string
*/
public static function plural($value, $count = 2)
{
return Pluralizer::plural($value, $count);
}
/**
* Generate a more truly "random" alpha-numeric string.
*
* @param int $length
* @return string
*/
public static function random($length = 16)
{
$string = '';
while (($len = strlen($string)) < $length) {
$size = $length - $len;
$bytes = random_bytes($size);
$string .= substr(str_replace(['/', '+', '='], '', base64_encode($bytes)), 0, $size);
}
return $string;
}
/**
* Generate a more truly "random" bytes.
*
* @param int $length
* @return string
*
* @deprecated since version 5.2. Use random_bytes instead.
*/
public static function randomBytes($length = 16)
{
return random_bytes($length);
}
/**
* Generate a "random" alpha-numeric string.
*
* Should not be considered sufficient for cryptography, etc.
*
* @param int $length
* @return string
*/
public static function quickRandom($length = 16)
{
$pool = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
return substr(str_shuffle(str_repeat($pool, $length)), 0, $length);
}
/**
* Compares two strings using a constant-time algorithm.
*
* Note: This method will leak length information.
*
* Note: Adapted from Symfony\Component\Security\Core\Util\StringUtils.
*
* @param string $knownString
* @param string $userInput
* @return bool
*
* @deprecated since version 5.2. Use hash_equals instead.
*/
public static function equals($knownString, $userInput)
{
return hash_equals($knownString, $userInput);
}
/**
* Replace the first occurrence of a given value in the string.
*
* @param string $search
* @param string $replace
* @param string $subject
* @return string
*/
public static function replaceFirst($search, $replace, $subject)
{
$position = strpos($subject, $search);
if ($position !== false) {
return substr_replace($subject, $replace, $position, strlen($search));
}
return $subject;
}
/**
* Replace the last occurrence of a given value in the string.
*
* @param string $search
* @param string $replace
* @param string $subject
* @return string
*/
public static function replaceLast($search, $replace, $subject)
{
$position = strrpos($subject, $search);
if ($position !== false) {
return substr_replace($subject, $replace, $position, strlen($search));
}
return $subject;
}
/**
* Convert the given string to upper-case.
*
* @param string $value
* @return string
*/
public static function upper($value)
{
return mb_strtoupper($value, 'UTF-8');
}
/**
* Convert the given string to title case.
*
* @param string $value
* @return string
*/
public static function title($value)
{
return mb_convert_case($value, MB_CASE_TITLE, 'UTF-8');
}
/**
* Get the singular form of an English word.
*
* @param string $value
* @return string
*/
public static function singular($value)
{
return Pluralizer::singular($value);
}
/**
* Generate a URL friendly "slug" from a given string.
*
* @param string $title
* @param string $separator
* @return string
*/
public static function slug($title, $separator = '-')
{
$title = static::ascii($title);
// Convert all dashes/underscores into separator
$flip = $separator == '-' ? '_' : '-';
$title = preg_replace('!['.preg_quote($flip).']+!u', $separator, $title);
// Remove all characters that are not the separator, letters, numbers, or whitespace.
$title = preg_replace('![^'.preg_quote($separator).'\pL\pN\s]+!u', '', mb_strtolower($title));
// Replace all separator characters and whitespace by a single separator
$title = preg_replace('!['.preg_quote($separator).'\s]+!u', $separator, $title);
return trim($title, $separator);
}
/**
* Convert a string to snake case.
*
* @param string $value
* @param string $delimiter
* @return string
*/
public static function snake($value, $delimiter = '_')
{
$key = $value.$delimiter;
if (isset(static::$snakeCache[$key])) {
return static::$snakeCache[$key];
}
if (! ctype_lower($value)) {
$value = preg_replace('/\s+/', '', $value);
$value = static::lower(preg_replace('/(.)(?=[A-Z])/', '$1'.$delimiter, $value));
}
return static::$snakeCache[$key] = $value;
}
/**
* Determine if a given string starts with a given substring.
*
* @param string $haystack
* @param string|array $needles
* @return bool
*/
public static function startsWith($haystack, $needles)
{
foreach ((array) $needles as $needle) {
if ($needle != '' && strpos($haystack, $needle) === 0) {
return true;
}
}
return false;
}
/**
* Convert a value to studly caps case.
*
* @param string $value
* @return string
*/
public static function studly($value)
{
$key = $value;
if (isset(static::$studlyCache[$key])) {
return static::$studlyCache[$key];
}
$value = ucwords(str_replace(['-', '_'], ' ', $value));
return static::$studlyCache[$key] = str_replace(' ', '', $value);
}
/**
* Returns the portion of string specified by the start and length parameters.
*
* @param string $string
* @param int $start
* @param int|null $length
* @return string
*/
public static function substr($string, $start, $length = null)
{
return mb_substr($string, $start, $length, 'UTF-8');
}
/**
* Make a string's first character uppercase.
*
* @param string $string
* @return string
*/
public static function ucfirst($string)
{
return static::upper(static::substr($string, 0, 1)).static::substr($string, 1);
}
/**
* Returns the replacements for the ascii method.
*
* Note: Adapted from Stringy\Stringy.
*
* @see https://github.com/danielstjules/Stringy/blob/2.2.0/LICENSE.txt
*
* @return array
*/
protected static function charsArray()
{
static $charsArray;
if (isset($charsArray)) {
return $charsArray;
}
return $charsArray = [
'0' => ['°', '₀'],
'1' => ['¹', '₁'],
'2' => ['²', '₂'],
'3' => ['³', '₃'],
'4' => ['⁴', '₄'],
'5' => ['⁵', '₅'],
'6' => ['⁶', '₆'],
'7' => ['⁷', '₇'],
'8' => ['⁸', '₈'],
'9' => ['⁹', '₉'],
'a' => ['à', 'á', 'ả', 'ã', 'ạ', 'ă', 'ắ', 'ằ', 'ẳ', 'ẵ', 'ặ', 'â', 'ấ', 'ầ', 'ẩ', 'ẫ', 'ậ', 'ā', 'ą', 'å', 'α', 'ά', 'ἀ', 'ἁ', 'ἂ', 'ἃ', 'ἄ', 'ἅ', 'ἆ', 'ἇ', 'ᾀ', 'ᾁ', 'ᾂ', 'ᾃ', 'ᾄ', 'ᾅ', 'ᾆ', 'ᾇ', 'ὰ', 'ά', 'ᾰ', 'ᾱ', 'ᾲ', 'ᾳ', 'ᾴ', 'ᾶ', 'ᾷ', 'а', 'أ', 'အ', 'ာ', 'ါ', 'ǻ', 'ǎ', 'ª', 'ა', 'अ'],
'b' => ['б', 'β', 'Ъ', 'Ь', 'ب', 'ဗ', 'ბ'],
'c' => ['ç', 'ć', 'č', 'ĉ', 'ċ'],
'd' => ['ď', 'ð', 'đ', 'ƌ', 'ȡ', 'ɖ', 'ɗ', 'ᵭ', 'ᶁ', 'ᶑ', 'д', 'δ', 'د', 'ض', 'ဍ', 'ဒ', 'დ'],
'e' => ['é', 'è', 'ẻ', 'ẽ', 'ẹ', 'ê', 'ế', 'ề', 'ể', 'ễ', 'ệ', 'ë', 'ē', 'ę', 'ě', 'ĕ', 'ė', 'ε', 'έ', 'ἐ', 'ἑ', 'ἒ', 'ἓ', 'ἔ', 'ἕ', 'ὲ', 'έ', 'е', 'ё', 'э', 'є', 'ə', 'ဧ', 'ေ', 'ဲ', 'ე', 'ए'],
'f' => ['ф', 'φ', 'ف', 'ƒ', 'ფ'],
'g' => ['ĝ', 'ğ', 'ġ', 'ģ', 'г', 'ґ', 'γ', 'ج', 'ဂ', 'გ'],
'h' => ['ĥ', 'ħ', 'η', 'ή', 'ح', 'ه', 'ဟ', 'ှ', 'ჰ'],
'i' => ['í', 'ì', 'ỉ', 'ĩ', 'ị', 'î', 'ï', 'ī', 'ĭ', 'į', 'ı', 'ι', 'ί', 'ϊ', 'ΐ', 'ἰ', 'ἱ', 'ἲ', 'ἳ', 'ἴ', 'ἵ', 'ἶ', 'ἷ', 'ὶ', 'ί', 'ῐ', 'ῑ', 'ῒ', 'ΐ', 'ῖ', 'ῗ', 'і', 'ї', 'и', 'ဣ', 'ိ', 'ီ', 'ည်', 'ǐ', 'ი', 'इ'],
'j' => ['ĵ', 'ј', 'Ј', 'ჯ'],
'k' => ['ķ', 'ĸ', 'к', 'κ', 'Ķ', 'ق', 'ك', 'က', 'კ', 'ქ'],
'l' => ['ł', 'ľ', 'ĺ', 'ļ', 'ŀ', 'л', 'λ', 'ل', 'လ', 'ლ'],
'm' => ['м', 'μ', 'م', 'မ', 'მ'],
'n' => ['ñ', 'ń', 'ň', 'ņ', 'ʼn', 'ŋ', 'ν', 'н', 'ن', 'န', 'ნ'],
'o' => ['ó', 'ò', 'ỏ', 'õ', 'ọ', 'ô', 'ố', 'ồ', 'ổ', 'ỗ', 'ộ', 'ơ', 'ớ', 'ờ', 'ở', 'ỡ', 'ợ', 'ø', 'ō', 'ő', 'ŏ', 'ο', 'ὀ', 'ὁ', 'ὂ', 'ὃ', 'ὄ', 'ὅ', 'ὸ', 'ό', 'о', 'و', 'θ', 'ို', 'ǒ', 'ǿ', 'º', 'ო', 'ओ'],
'p' => ['п', 'π', 'ပ', 'პ'],
'q' => ['ყ'],
'r' => ['ŕ', 'ř', 'ŗ', 'р', 'ρ', 'ر', 'რ'],
's' => ['ś', 'š', 'ş', 'с', 'σ', 'ș', 'ς', 'س', 'ص', 'စ', 'ſ', 'ს'],
't' => ['ť', 'ţ', 'т', 'τ', 'ț', 'ت', 'ط', 'ဋ', 'တ', 'ŧ', 'თ', 'ტ'],
'u' => ['ú', 'ù', 'ủ', 'ũ', 'ụ', 'ư', 'ứ', 'ừ', 'ử', 'ữ', 'ự', 'û', 'ū', 'ů', 'ű', 'ŭ', 'ų', 'µ', 'у', 'ဉ', 'ု', 'ူ', 'ǔ', 'ǖ', 'ǘ', 'ǚ', 'ǜ', 'უ', 'उ'],
'v' => ['в', 'ვ', 'ϐ'],
'w' => ['ŵ', 'ω', 'ώ', 'ဝ', 'ွ'],
'x' => ['χ', 'ξ'],
'y' => ['ý', 'ỳ', 'ỷ', 'ỹ', 'ỵ', 'ÿ', 'ŷ', 'й', 'ы', 'υ', 'ϋ', 'ύ', 'ΰ', 'ي', 'ယ'],
'z' => ['ź', 'ž', 'ż', 'з', 'ζ', 'ز', 'ဇ', 'ზ'],
'aa' => ['ع', 'आ'],
'ae' => ['ä', 'æ', 'ǽ'],
'ai' => ['ऐ'],
'at' => ['@'],
'ch' => ['ч', 'ჩ', 'ჭ'],
'dj' => ['ђ', 'đ'],
'dz' => ['џ', 'ძ'],
'ei' => ['ऍ'],
'gh' => ['غ', 'ღ'],
'ii' => ['ई'],
'ij' => ['ij'],
'kh' => ['х', 'خ', 'ხ'],
'lj' => ['љ'],
'nj' => ['њ'],
'oe' => ['ö', 'œ'],
'oi' => ['ऑ'],
'oii' => ['ऒ'],
'ps' => ['ψ'],
'sh' => ['ш', 'შ'],
'shch' => ['щ'],
'ss' => ['ß'],
'sx' => ['ŝ'],
'th' => ['þ', 'ϑ', 'ث', 'ذ', 'ظ'],
'ts' => ['ц', 'ც', 'წ'],
'ue' => ['ü'],
'uu' => ['ऊ'],
'ya' => ['я'],
'yu' => ['ю'],
'zh' => ['ж', 'ჟ'],
'(c)' => ['©'],
'A' => ['Á', 'À', 'Ả', 'Ã', 'Ạ', 'Ă', 'Ắ', 'Ằ', 'Ẳ', 'Ẵ', 'Ặ', 'Â', 'Ấ', 'Ầ', 'Ẩ', 'Ẫ', 'Ậ', 'Å', 'Ā', 'Ą', 'Α', 'Ά', 'Ἀ', 'Ἁ', 'Ἂ', 'Ἃ', 'Ἄ', 'Ἅ', 'Ἆ', 'Ἇ', 'ᾈ', 'ᾉ', 'ᾊ', 'ᾋ', 'ᾌ', 'ᾍ', 'ᾎ', 'ᾏ', 'Ᾰ', 'Ᾱ', 'Ὰ', 'Ά', 'ᾼ', 'А', 'Ǻ', 'Ǎ'],
'B' => ['Б', 'Β', 'ब'],
'C' => ['Ç', 'Ć', 'Č', 'Ĉ', 'Ċ'],
'D' => ['Ď', 'Ð', 'Đ', 'Ɖ', 'Ɗ', 'Ƌ', 'ᴅ', 'ᴆ', 'Д', 'Δ'],
'E' => ['É', 'È', 'Ẻ', 'Ẽ', 'Ẹ', 'Ê', 'Ế', 'Ề', 'Ể', 'Ễ', 'Ệ', 'Ë', 'Ē', 'Ę', 'Ě', 'Ĕ', 'Ė', 'Ε', 'Έ', 'Ἐ', 'Ἑ', 'Ἒ', 'Ἓ', 'Ἔ', 'Ἕ', 'Έ', 'Ὲ', 'Е', 'Ё', 'Э', 'Є', 'Ə'],
'F' => ['Ф', 'Φ'],
'G' => ['Ğ', 'Ġ', 'Ģ', 'Г', 'Ґ', 'Γ'],
'H' => ['Η', 'Ή', 'Ħ'],
'I' => ['Í', 'Ì', 'Ỉ', 'Ĩ', 'Ị', 'Î', 'Ï', 'Ī', 'Ĭ', 'Į', 'İ', 'Ι', 'Ί', 'Ϊ', 'Ἰ', 'Ἱ', 'Ἳ', 'Ἴ', 'Ἵ', 'Ἶ', 'Ἷ', 'Ῐ', 'Ῑ', 'Ὶ', 'Ί', 'И', 'І', 'Ї', 'Ǐ', 'ϒ'],
'K' => ['К', 'Κ'],
'L' => ['Ĺ', 'Ł', 'Л', 'Λ', 'Ļ', 'Ľ', 'Ŀ', 'ल'],
'M' => ['М', 'Μ'],
'N' => ['Ń', 'Ñ', 'Ň', 'Ņ', 'Ŋ', 'Н', 'Ν'],
'O' => ['Ó', 'Ò', 'Ỏ', 'Õ', 'Ọ', 'Ô', 'Ố', 'Ồ', 'Ổ', 'Ỗ', 'Ộ', 'Ơ', 'Ớ', 'Ờ', 'Ở', 'Ỡ', 'Ợ', 'Ø', 'Ō', 'Ő', 'Ŏ', 'Ο', 'Ό', 'Ὀ', 'Ὁ', 'Ὂ', 'Ὃ', 'Ὄ', 'Ὅ', 'Ὸ', 'Ό', 'О', 'Θ', 'Ө', 'Ǒ', 'Ǿ'],
'P' => ['П', 'Π'],
'R' => ['Ř', 'Ŕ', 'Р', 'Ρ', 'Ŗ'],
'S' => ['Ş', 'Ŝ', 'Ș', 'Š', 'Ś', 'С', 'Σ'],
'T' => ['Ť', 'Ţ', 'Ŧ', 'Ț', 'Т', 'Τ'],
'U' => ['Ú', 'Ù', 'Ủ', 'Ũ', 'Ụ', 'Ư', 'Ứ', 'Ừ', 'Ử', 'Ữ', 'Ự', 'Û', 'Ū', 'Ů', 'Ű', 'Ŭ', 'Ų', 'У', 'Ǔ', 'Ǖ', 'Ǘ', 'Ǚ', 'Ǜ'],
'V' => ['В'],
'W' => ['Ω', 'Ώ', 'Ŵ'],
'X' => ['Χ', 'Ξ'],
'Y' => ['Ý', 'Ỳ', 'Ỷ', 'Ỹ', 'Ỵ', 'Ÿ', 'Ῠ', 'Ῡ', 'Ὺ', 'Ύ', 'Ы', 'Й', 'Υ', 'Ϋ', 'Ŷ'],
'Z' => ['Ź', 'Ž', 'Ż', 'З', 'Ζ'],
'AE' => ['Ä', 'Æ', 'Ǽ'],
'CH' => ['Ч'],
'DJ' => ['Ђ'],
'DZ' => ['Џ'],
'GX' => ['Ĝ'],
'HX' => ['Ĥ'],
'IJ' => ['IJ'],
'JX' => ['Ĵ'],
'KH' => ['Х'],
'LJ' => ['Љ'],
'NJ' => ['Њ'],
'OE' => ['Ö', 'Œ'],
'PS' => ['Ψ'],
'SH' => ['Ш'],
'SHCH' => ['Щ'],
'SS' => ['ẞ'],
'TH' => ['Þ'],
'TS' => ['Ц'],
'UE' => ['Ü'],
'YA' => ['Я'],
'YU' => ['Ю'],
'ZH' => ['Ж'],
' ' => ["\xC2\xA0", "\xE2\x80\x80", "\xE2\x80\x81", "\xE2\x80\x82", "\xE2\x80\x83", "\xE2\x80\x84", "\xE2\x80\x85", "\xE2\x80\x86", "\xE2\x80\x87", "\xE2\x80\x88", "\xE2\x80\x89", "\xE2\x80\x8A", "\xE2\x80\xAF", "\xE2\x81\x9F", "\xE3\x80\x80"],
];
}
}
<?php
namespace Illuminate\Support\Traits;
use Illuminate\Support\Fluent;
use Illuminate\Contracts\Container\Container;
trait CapsuleManagerTrait
{
/**
* The current globally used instance.
*
* @var object
*/
protected static $instance;
/**
* The container instance.
*
* @var \Illuminate\Contracts\Container\Container
*/
protected $container;
/**
* Setup the IoC container instance.
*
* @param \Illuminate\Contracts\Container\Container $container
* @return void
*/
protected function setupContainer(Container $container)
{
$this->container = $container;
if (! $this->container->bound('config')) {
$this->container->instance('config', new Fluent);
}
}
/**
* Make this capsule instance available globally.
*
* @return void
*/
public function setAsGlobal()
{
static::$instance = $this;
}
/**
* Get the IoC container instance.
*
* @return \Illuminate\Contracts\Container\Container
*/
public function getContainer()
{
return $this->container;
}
/**
* Set the IoC container instance.
*
* @param \Illuminate\Contracts\Container\Container $container
* @return void
*/
public function setContainer(Container $container)
{
$this->container = $container;
}
}
<?php
namespace Illuminate\Support\Traits;
use Closure;
use BadMethodCallException;
trait Macroable
{
/**
* The registered string macros.
*
* @var array
*/
protected static $macros = [];
/**
* Register a custom macro.
*
* @param string $name
* @param callable $macro
* @return void
*/
public static function macro($name, callable $macro)
{
static::$macros[$name] = $macro;
}
/**
* Checks if macro is registered.
*
* @param string $name
* @return bool
*/
public static function hasMacro($name)
{
return isset(static::$macros[$name]);
}
/**
* Dynamically handle calls to the class.
*
* @param string $method
* @param array $parameters
* @return mixed
*
* @throws \BadMethodCallException
*/
public static function __callStatic($method, $parameters)
{
if (static::hasMacro($method)) {
if (static::$macros[$method] instanceof Closure) {
return call_user_func_array(Closure::bind(static::$macros[$method], null, static::class), $parameters);
} else {
return call_user_func_array(static::$macros[$method], $parameters);
}
}
throw new BadMethodCallException("Method {$method} does not exist.");
}
/**
* Dynamically handle calls to the class.
*
* @param string $method
* @param array $parameters
* @return mixed
*
* @throws \BadMethodCallException
*/
public function __call($method, $parameters)
{
if (static::hasMacro($method)) {
if (static::$macros[$method] instanceof Closure) {
return call_user_func_array(static::$macros[$method]->bindTo($this, static::class), $parameters);
} else {
return call_user_func_array(static::$macros[$method], $parameters);
}
}
throw new BadMethodCallException("Method {$method} does not exist.");
}
}
<?php
namespace Illuminate\Support;
use Countable;
use Illuminate\Contracts\Support\MessageBag as MessageBagContract;
class ViewErrorBag implements Countable
{
/**
* The array of the view error bags.
*
* @var array
*/
protected $bags = [];
/**
* Checks if a named MessageBag exists in the bags.
*
* @param string $key
* @return bool
*/
public function hasBag($key = 'default')
{
return isset($this->bags[$key]);
}
/**
* Get a MessageBag instance from the bags.
*
* @param string $key
* @return \Illuminate\Contracts\Support\MessageBag
*/
public function getBag($key)
{
return Arr::get($this->bags, $key) ?: new MessageBag;
}
/**
* Get all the bags.
*
* @return array
*/
public function getBags()
{
return $this->bags;
}
/**
* Add a new MessageBag instance to the bags.
*
* @param string $key
* @param \Illuminate\Contracts\Support\MessageBag $bag
* @return $this
*/
public function put($key, MessageBagContract $bag)
{
$this->bags[$key] = $bag;
return $this;
}
/**
* Get the number of messages in the default bag.
*
* @return int
*/
public function count()
{
return $this->default->count();
}
/**
* Dynamically call methods on the default bag.
*
* @param string $method
* @param array $parameters
* @return mixed
*/
public function __call($method, $parameters)
{
return call_user_func_array([$this->default, $method], $parameters);
}
/**
* Dynamically access a view error bag.
*
* @param string $key
* @return \Illuminate\Contracts\Support\MessageBag
*/
public function __get($key)
{
return $this->getBag($key);
}
/**
* Dynamically set a view error bag.
*
* @param string $key
* @param \Illuminate\Contracts\Support\MessageBag $value
* @return void
*/
public function __set($key, $value)
{
$this->put($key, $value);
}
}
<?php
namespace Illuminate\View\Compilers;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
class BladeCompiler extends Compiler implements CompilerInterface
{
/**
* All of the registered extensions.
*
* @var array
*/
protected $extensions = [];
/**
* All custom "directive" handlers.
*
* This was implemented as a more usable "extend" in 5.1.
*
* @var array
*/
protected $customDirectives = [];
/**
* The file currently being compiled.
*
* @var string
*/
protected $path;
/**
* All of the available compiler functions.
*
* @var array
*/
protected $compilers = [
'Extensions',
'Statements',
'Comments',
'Echos',
];
/**
* Array of opening and closing tags for raw echos.
*
* @var array
*/
protected $rawTags = ['{!!', '!!}'];
/**
* Array of opening and closing tags for regular echos.
*
* @var array
*/
protected $contentTags = ['{{', '}}'];
/**
* Array of opening and closing tags for escaped echos.
*
* @var array
*/
protected $escapedTags = ['{{{', '}}}'];
/**
* The "regular" / legacy echo string format.
*
* @var string
*/
protected $echoFormat = 'e(%s)';
/**
* Array of footer lines to be added to template.
*
* @var array
*/
protected $footer = [];
/**
* Placeholder to temporary mark the position of verbatim blocks.
*
* @var string
*/
protected $verbatimPlaceholder = '@__verbatim__@';
/**
* Array to temporary store the verbatim blocks found in the template.
*
* @var array
*/
protected $verbatimBlocks = [];
/**
* Counter to keep track of nested forelse statements.
*
* @var int
*/
protected $forelseCounter = 0;
/**
* Compile the view at the given path.
*
* @param string $path
* @return void
*/
public function compile($path = null)
{
if ($path) {
$this->setPath($path);
}
if (! is_null($this->cachePath)) {
$contents = $this->compileString($this->files->get($this->getPath()));
$this->files->put($this->getCompiledPath($this->getPath()), $contents);
}
}
/**
* Get the path currently being compiled.
*
* @return string
*/
public function getPath()
{
return $this->path;
}
/**
* Set the path currently being compiled.
*
* @param string $path
* @return void
*/
public function setPath($path)
{
$this->path = $path;
}
/**
* Compile the given Blade template contents.
*
* @param string $value
* @return string
*/
public function compileString($value)
{
$result = '';
if (strpos($value, '@verbatim') !== false) {
$value = $this->storeVerbatimBlocks($value);
}
$this->footer = [];
// Here we will loop through all of the tokens returned by the Zend lexer and
// parse each one into the corresponding valid PHP. We will then have this
// template as the correctly rendered PHP that can be rendered natively.
foreach (token_get_all($value) as $token) {
$result .= is_array($token) ? $this->parseToken($token) : $token;
}
if (! empty($this->verbatimBlocks)) {
$result = $this->restoreVerbatimBlocks($result);
}
// If there are any footer lines that need to get added to a template we will
// add them here at the end of the template. This gets used mainly for the
// template inheritance via the extends keyword that should be appended.
if (count($this->footer) > 0) {
$result = ltrim($result, PHP_EOL)
.PHP_EOL.implode(PHP_EOL, array_reverse($this->footer));
}
return $result;
}
/**
* Store the verbatim blocks and replace them with a temporary placeholder.
*
* @param string $value
* @return string
*/
protected function storeVerbatimBlocks($value)
{
return preg_replace_callback('/(?<!@)@verbatim(.*?)@endverbatim/s', function ($matches) {
$this->verbatimBlocks[] = $matches[1];
return $this->verbatimPlaceholder;
}, $value);
}
/**
* Replace the raw placeholders with the original code stored in the raw blocks.
*
* @param string $result
* @return string
*/
protected function restoreVerbatimBlocks($result)
{
$result = preg_replace_callback('/'.preg_quote($this->verbatimPlaceholder).'/', function () {
return array_shift($this->verbatimBlocks);
}, $result);
$this->verbatimBlocks = [];
return $result;
}
/**
* Parse the tokens from the template.
*
* @param array $token
* @return string
*/
protected function parseToken($token)
{
list($id, $content) = $token;
if ($id == T_INLINE_HTML) {
foreach ($this->compilers as $type) {
$content = $this->{"compile{$type}"}($content);
}
}
return $content;
}
/**
* Execute the user defined extensions.
*
* @param string $value
* @return string
*/
protected function compileExtensions($value)
{
foreach ($this->extensions as $compiler) {
$value = call_user_func($compiler, $value, $this);
}
return $value;
}
/**
* Compile Blade comments into valid PHP.
*
* @param string $value
* @return string
*/
protected function compileComments($value)
{
$pattern = sprintf('/%s--(.*?)--%s/s', $this->contentTags[0], $this->contentTags[1]);
return preg_replace($pattern, '<?php /*$1*/ ?>', $value);
}
/**
* Compile Blade echos into valid PHP.
*
* @param string $value
* @return string
*/
protected function compileEchos($value)
{
foreach ($this->getEchoMethods() as $method => $length) {
$value = $this->$method($value);
}
return $value;
}
/**
* Get the echo methods in the proper order for compilation.
*
* @return array
*/
protected function getEchoMethods()
{
$methods = [
'compileRawEchos' => strlen(stripcslashes($this->rawTags[0])),
'compileEscapedEchos' => strlen(stripcslashes($this->escapedTags[0])),
'compileRegularEchos' => strlen(stripcslashes($this->contentTags[0])),
];
uksort($methods, function ($method1, $method2) use ($methods) {
// Ensure the longest tags are processed first
if ($methods[$method1] > $methods[$method2]) {
return -1;
}
if ($methods[$method1] < $methods[$method2]) {
return 1;
}
// Otherwise give preference to raw tags (assuming they've overridden)
if ($method1 === 'compileRawEchos') {
return -1;
}
if ($method2 === 'compileRawEchos') {
return 1;
}
if ($method1 === 'compileEscapedEchos') {
return -1;
}
if ($method2 === 'compileEscapedEchos') {
return 1;
}
});
return $methods;
}
/**
* Compile Blade statements that start with "@".
*
* @param string $value
* @return mixed
*/
protected function compileStatements($value)
{
$callback = function ($match) {
if (Str::contains($match[1], '@')) {
$match[0] = isset($match[3]) ? $match[1].$match[3] : $match[1];
} elseif (isset($this->customDirectives[$match[1]])) {
$match[0] = call_user_func($this->customDirectives[$match[1]], Arr::get($match, 3));
} elseif (method_exists($this, $method = 'compile'.ucfirst($match[1]))) {
$match[0] = $this->$method(Arr::get($match, 3));
}
return isset($match[3]) ? $match[0] : $match[0].$match[2];
};
return preg_replace_callback('/\B@(@?\w+)([ \t]*)(\( ( (?>[^()]+) | (?3) )* \))?/x', $callback, $value);
}
/**
* Compile the "raw" echo statements.
*
* @param string $value
* @return string
*/
protected function compileRawEchos($value)
{
$pattern = sprintf('/(@)?%s\s*(.+?)\s*%s(\r?\n)?/s', $this->rawTags[0], $this->rawTags[1]);
$callback = function ($matches) {
$whitespace = empty($matches[3]) ? '' : $matches[3].$matches[3];
return $matches[1] ? substr($matches[0], 1) : '<?php echo '.$this->compileEchoDefaults($matches[2]).'; ?>'.$whitespace;
};
return preg_replace_callback($pattern, $callback, $value);
}
/**
* Compile the "regular" echo statements.
*
* @param string $value
* @return string
*/
protected function compileRegularEchos($value)
{
$pattern = sprintf('/(@)?%s\s*(.+?)\s*%s(\r?\n)?/s', $this->contentTags[0], $this->contentTags[1]);
$callback = function ($matches) {
$whitespace = empty($matches[3]) ? '' : $matches[3].$matches[3];
$wrapped = sprintf($this->echoFormat, $this->compileEchoDefaults($matches[2]));
return $matches[1] ? substr($matches[0], 1) : '<?php echo '.$wrapped.'; ?>'.$whitespace;
};
return preg_replace_callback($pattern, $callback, $value);
}
/**
* Compile the escaped echo statements.
*
* @param string $value
* @return string
*/
protected function compileEscapedEchos($value)
{
$pattern = sprintf('/(@)?%s\s*(.+?)\s*%s(\r?\n)?/s', $this->escapedTags[0], $this->escapedTags[1]);
$callback = function ($matches) {
$whitespace = empty($matches[3]) ? '' : $matches[3].$matches[3];
return $matches[1] ? $matches[0] : '<?php echo e('.$this->compileEchoDefaults($matches[2]).'); ?>'.$whitespace;
};
return preg_replace_callback($pattern, $callback, $value);
}
/**
* Compile the default values for the echo statement.
*
* @param string $value
* @return string
*/
public function compileEchoDefaults($value)
{
return preg_replace('/^(?=\$)(.+?)(?:\s+or\s+)(.+?)$/s', 'isset($1) ? $1 : $2', $value);
}
/**
* Compile the each statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileEach($expression)
{
return "<?php echo \$__env->renderEach{$expression}; ?>";
}
/**
* Compile the inject statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileInject($expression)
{
$segments = explode(',', preg_replace("/[\(\)\\\"\']/", '', $expression));
return '<?php $'.trim($segments[0])." = app('".trim($segments[1])."'); ?>";
}
/**
* Compile the yield statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileYield($expression)
{
return "<?php echo \$__env->yieldContent{$expression}; ?>";
}
/**
* Compile the show statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileShow($expression)
{
return '<?php echo $__env->yieldSection(); ?>';
}
/**
* Compile the section statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileSection($expression)
{
return "<?php \$__env->startSection{$expression}; ?>";
}
/**
* Compile the append statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileAppend($expression)
{
return '<?php $__env->appendSection(); ?>';
}
/**
* Compile the end-section statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileEndsection($expression)
{
return '<?php $__env->stopSection(); ?>';
}
/**
* Compile the stop statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileStop($expression)
{
return '<?php $__env->stopSection(); ?>';
}
/**
* Compile the overwrite statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileOverwrite($expression)
{
return '<?php $__env->stopSection(true); ?>';
}
/**
* Compile the unless statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileUnless($expression)
{
return "<?php if ( ! $expression): ?>";
}
/**
* Compile the end unless statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileEndunless($expression)
{
return '<?php endif; ?>';
}
/**
* Compile the lang statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileLang($expression)
{
return "<?php echo app('translator')->get$expression; ?>";
}
/**
* Compile the choice statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileChoice($expression)
{
return "<?php echo app('translator')->choice$expression; ?>";
}
/**
* Compile the else statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileElse($expression)
{
return '<?php else: ?>';
}
/**
* Compile the for statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileFor($expression)
{
return "<?php for{$expression}: ?>";
}
/**
* Compile the foreach statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileForeach($expression)
{
return "<?php foreach{$expression}: ?>";
}
/**
* Compile the break statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileBreak($expression)
{
return $expression ? "<?php if{$expression} break; ?>" : '<?php break; ?>';
}
/**
* Compile the continue statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileContinue($expression)
{
return $expression ? "<?php if{$expression} continue; ?>" : '<?php continue; ?>';
}
/**
* Compile the forelse statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileForelse($expression)
{
$empty = '$__empty_'.++$this->forelseCounter;
return "<?php {$empty} = true; foreach{$expression}: {$empty} = false; ?>";
}
/**
* Compile the can statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileCan($expression)
{
return "<?php if (Gate::check{$expression}): ?>";
}
/**
* Compile the cannot statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileCannot($expression)
{
return "<?php if (Gate::denies{$expression}): ?>";
}
/**
* Compile the if statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileIf($expression)
{
return "<?php if{$expression}: ?>";
}
/**
* Compile the else-if statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileElseif($expression)
{
return "<?php elseif{$expression}: ?>";
}
/**
* Compile the forelse statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileEmpty($expression)
{
$empty = '$__empty_'.$this->forelseCounter--;
return "<?php endforeach; if ({$empty}): ?>";
}
/**
* Compile the has section statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileHasSection($expression)
{
return "<?php if (! empty(trim(\$__env->yieldContent{$expression}))): ?>";
}
/**
* Compile the while statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileWhile($expression)
{
return "<?php while{$expression}: ?>";
}
/**
* Compile the end-while statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileEndwhile($expression)
{
return '<?php endwhile; ?>';
}
/**
* Compile the end-for statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileEndfor($expression)
{
return '<?php endfor; ?>';
}
/**
* Compile the end-for-each statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileEndforeach($expression)
{
return '<?php endforeach; ?>';
}
/**
* Compile the end-can statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileEndcan($expression)
{
return '<?php endif; ?>';
}
/**
* Compile the end-cannot statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileEndcannot($expression)
{
return '<?php endif; ?>';
}
/**
* Compile the end-if statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileEndif($expression)
{
return '<?php endif; ?>';
}
/**
* Compile the end-for-else statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileEndforelse($expression)
{
return '<?php endif; ?>';
}
/**
* Compile the raw PHP statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compilePhp($expression)
{
return $expression ? "<?php {$expression}; ?>" : '<?php ';
}
/**
* Compile end-php statement into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileEndphp($expression)
{
return ' ?>';
}
/**
* Compile the unset statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileUnset($expression)
{
return "<?php unset{$expression}; ?>";
}
/**
* Compile the extends statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileExtends($expression)
{
$expression = $this->stripParentheses($expression);
$data = "<?php echo \$__env->make($expression, array_except(get_defined_vars(), array('__data', '__path')))->render(); ?>";
$this->footer[] = $data;
return '';
}
/**
* Compile the include statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileInclude($expression)
{
$expression = $this->stripParentheses($expression);
return "<?php echo \$__env->make($expression, array_except(get_defined_vars(), array('__data', '__path')))->render(); ?>";
}
/**
* Compile the include statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileIncludeIf($expression)
{
$expression = $this->stripParentheses($expression);
return "<?php if (\$__env->exists($expression)) echo \$__env->make($expression, array_except(get_defined_vars(), array('__data', '__path')))->render(); ?>";
}
/**
* Compile the stack statements into the content.
*
* @param string $expression
* @return string
*/
protected function compileStack($expression)
{
return "<?php echo \$__env->yieldPushContent{$expression}; ?>";
}
/**
* Compile the push statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compilePush($expression)
{
return "<?php \$__env->startPush{$expression}; ?>";
}
/**
* Compile the endpush statements into valid PHP.
*
* @param string $expression
* @return string
*/
protected function compileEndpush($expression)
{
return '<?php $__env->stopPush(); ?>';
}
/**
* Strip the parentheses from the given expression.
*
* @param string $expression
* @return string
*/
protected function stripParentheses($expression)
{
if (Str::startsWith($expression, '(')) {
$expression = substr($expression, 1, -1);
}
return $expression;
}
/**
* Get the extensions used by the compiler.
*
* @return array
*/
public function getExtensions()
{
return $this->extensions;
}
/**
* Register a custom Blade compiler.
*
* @param callable $compiler
* @return void
*/
public function extend(callable $compiler)
{
$this->extensions[] = $compiler;
}
/**
* Register a handler for custom directives.
*
* @param string $name
* @param callable $handler
* @return void
*/
public function directive($name, callable $handler)
{
$this->customDirectives[$name] = $handler;
}
/**
* Get the list of custom directives.
*
* @return array
*/
public function getCustomDirectives()
{
return $this->customDirectives;
}
/**
* Gets the raw tags used by the compiler.
*
* @return array
*/
public function getRawTags()
{
return $this->rawTags;
}
/**
* Sets the raw tags used for the compiler.
*
* @param string $openTag
* @param string $closeTag
* @return void
*/
public function setRawTags($openTag, $closeTag)
{
$this->rawTags = [preg_quote($openTag), preg_quote($closeTag)];
}
/**
* Sets the content tags used for the compiler.
*
* @param string $openTag
* @param string $closeTag
* @param bool $escaped
* @return void
*/
public function setContentTags($openTag, $closeTag, $escaped = false)
{
$property = ($escaped === true) ? 'escapedTags' : 'contentTags';
$this->{$property} = [preg_quote($openTag), preg_quote($closeTag)];
}
/**
* Sets the escaped content tags used for the compiler.
*
* @param string $openTag
* @param string $closeTag
* @return void
*/
public function setEscapedContentTags($openTag, $closeTag)
{
$this->setContentTags($openTag, $closeTag, true);
}
/**
* Gets the content tags used for the compiler.
*
* @return string
*/
public function getContentTags()
{
return $this->getTags();
}
/**
* Gets the escaped content tags used for the compiler.
*
* @return string
*/
public function getEscapedContentTags()
{
return $this->getTags(true);
}
/**
* Gets the tags used for the compiler.
*
* @param bool $escaped
* @return array
*/
protected function getTags($escaped = false)
{
$tags = $escaped ? $this->escapedTags : $this->contentTags;
return array_map('stripcslashes', $tags);
}
/**
* Set the echo format to be used by the compiler.
*
* @param string $format
* @return void
*/
public function setEchoFormat($format)
{
$this->echoFormat = $format;
}
}
<?php
namespace Illuminate\View\Compilers;
use Illuminate\Filesystem\Filesystem;
abstract class Compiler
{
/**
* The Filesystem instance.
*
* @var \Illuminate\Filesystem\Filesystem
*/
protected $files;
/**
* Get the cache path for the compiled views.
*
* @var string
*/
protected $cachePath;
/**
* Create a new compiler instance.
*
* @param \Illuminate\Filesystem\Filesystem $files
* @param string $cachePath
* @return void
*/
public function __construct(Filesystem $files, $cachePath)
{
$this->files = $files;
$this->cachePath = $cachePath;
}
/**
* Get the path to the compiled version of a view.
*
* @param string $path
* @return string
*/
public function getCompiledPath($path)
{
return $this->cachePath.'/'.sha1($path).'.php';
}
/**
* Determine if the view at the given path is expired.
*
* @param string $path
* @return bool
*/
public function isExpired($path)
{
$compiled = $this->getCompiledPath($path);
// If the compiled file doesn't exist we will indicate that the view is expired
// so that it can be re-compiled. Else, we will verify the last modification
// of the views is less than the modification times of the compiled views.
if (! $this->cachePath || ! $this->files->exists($compiled)) {
return true;
}
$lastModified = $this->files->lastModified($path);
return $lastModified >= $this->files->lastModified($compiled);
}
}
<?php
namespace Illuminate\View\Compilers;
interface CompilerInterface
{
/**
* Get the path to the compiled version of a view.
*
* @param string $path
* @return string
*/
public function getCompiledPath($path);
/**
* Determine if the given view is expired.
*
* @param string $path
* @return bool
*/
public function isExpired($path);
/**
* Compile the view at the given path.
*
* @param string $path
* @return void
*/
public function compile($path);
}
{
"name": "illuminate/view",
"description": "The Illuminate View package.",
"license": "MIT",
"homepage": "http://laravel.com",
"support": {
"issues": "https://github.com/laravel/framework/issues",
"source": "https://github.com/laravel/framework"
},
"authors": [
{
"name": "Taylor Otwell",
"email": "taylorotwell@gmail.com"
}
],
"require": {
"php": ">=5.5.9",
"illuminate/container": "5.2.*",
"illuminate/contracts": "5.2.*",
"illuminate/events": "5.2.*",
"illuminate/filesystem": "5.2.*",
"illuminate/support": "5.2.*"
},
"autoload": {
"psr-4": {
"Illuminate\\View\\": ""
}
},
"extra": {
"branch-alias": {
"dev-master": "5.2-dev"
}
},
"minimum-stability": "dev"
}
<?php
namespace Illuminate\View\Engines;
use Exception;
use ErrorException;
use Illuminate\View\Compilers\CompilerInterface;
class CompilerEngine extends PhpEngine
{
/**
* The Blade compiler instance.
*
* @var \Illuminate\View\Compilers\CompilerInterface
*/
protected $compiler;
/**
* A stack of the last compiled templates.
*
* @var array
*/
protected $lastCompiled = [];
/**
* Create a new Blade view engine instance.
*
* @param \Illuminate\View\Compilers\CompilerInterface $compiler
* @return void
*/
public function __construct(CompilerInterface $compiler)
{
$this->compiler = $compiler;
}
/**
* Get the evaluated contents of the view.
*
* @param string $path
* @param array $data
* @return string
*/
public function get($path, array $data = [])
{
$this->lastCompiled[] = $path;
// If this given view has expired, which means it has simply been edited since
// it was last compiled, we will re-compile the views so we can evaluate a
// fresh copy of the view. We'll pass the compiler the path of the view.
if ($this->compiler->isExpired($path)) {
$this->compiler->compile($path);
}
$compiled = $this->compiler->getCompiledPath($path);
// Once we have the path to the compiled file, we will evaluate the paths with
// typical PHP just like any other templates. We also keep a stack of views
// which have been rendered for right exception messages to be generated.
$results = $this->evaluatePath($compiled, $data);
array_pop($this->lastCompiled);
return $results;
}
/**
* Handle a view exception.
*
* @param \Exception $e
* @param int $obLevel
* @return void
*
* @throws $e
*/
protected function handleViewException(Exception $e, $obLevel)
{
$e = new ErrorException($this->getMessage($e), 0, 1, $e->getFile(), $e->getLine(), $e);
parent::handleViewException($e, $obLevel);
}
/**
* Get the exception message for an exception.
*
* @param \Exception $e
* @return string
*/
protected function getMessage(Exception $e)
{
return $e->getMessage().' (View: '.realpath(last($this->lastCompiled)).')';
}
/**
* Get the compiler implementation.
*
* @return \Illuminate\View\Compilers\CompilerInterface
*/
public function getCompiler()
{
return $this->compiler;
}
}
<?php
namespace Illuminate\View\Engines;
abstract class Engine
{
/**
* The view that was last to be rendered.
*
* @var string
*/
protected $lastRendered;
/**
* Get the last view that was rendered.
*
* @return string
*/
public function getLastRendered()
{
return $this->lastRendered;
}
}
<?php
namespace Illuminate\View\Engines;
interface EngineInterface
{
/**
* Get the evaluated contents of the view.
*
* @param string $path
* @param array $data
* @return string
*/
public function get($path, array $data = []);
}
<?php
namespace Illuminate\View\Engines;
use Closure;
use InvalidArgumentException;
class EngineResolver
{
/**
* The array of engine resolvers.
*
* @var array
*/
protected $resolvers = [];
/**
* The resolved engine instances.
*
* @var array
*/
protected $resolved = [];
/**
* Register a new engine resolver.
*
* The engine string typically corresponds to a file extension.
*
* @param string $engine
* @param \Closure $resolver
* @return void
*/
public function register($engine, Closure $resolver)
{
unset($this->resolved[$engine]);
$this->resolvers[$engine] = $resolver;
}
/**
* Resolver an engine instance by name.
*
* @param string $engine
* @return \Illuminate\View\Engines\EngineInterface
* @throws \InvalidArgumentException
*/
public function resolve($engine)
{
if (isset($this->resolved[$engine])) {
return $this->resolved[$engine];
}
if (isset($this->resolvers[$engine])) {
return $this->resolved[$engine] = call_user_func($this->resolvers[$engine]);
}
throw new InvalidArgumentException("Engine $engine not found.");
}
}
<?php
namespace Illuminate\View\Engines;
use Exception;
use Throwable;
use Symfony\Component\Debug\Exception\FatalThrowableError;
class PhpEngine implements EngineInterface
{
/**
* Get the evaluated contents of the view.
*
* @param string $path
* @param array $data
* @return string
*/
public function get($path, array $data = [])
{
return $this->evaluatePath($path, $data);
}
/**
* Get the evaluated contents of the view at the given path.
*
* @param string $__path
* @param array $__data
* @return string
*/
protected function evaluatePath($__path, $__data)
{
$obLevel = ob_get_level();
ob_start();
extract($__data, EXTR_SKIP);
// We'll evaluate the contents of the view inside a try/catch block so we can
// flush out any stray output that might get out before an error occurs or
// an exception is thrown. This prevents any partial views from leaking.
try {
include $__path;
} catch (Exception $e) {
$this->handleViewException($e, $obLevel);
} catch (Throwable $e) {
$this->handleViewException(new FatalThrowableError($e), $obLevel);
}
return ltrim(ob_get_clean());
}
/**
* Handle a view exception.
*
* @param \Exception $e
* @param int $obLevel
* @return void
*
* @throws $e
*/
protected function handleViewException(Exception $e, $obLevel)
{
while (ob_get_level() > $obLevel) {
ob_end_clean();
}
throw $e;
}
}
<?php
namespace Illuminate\View;
use Illuminate\Support\HtmlString;
/**
* @deprecated since version 5.2. Use Illuminate\Support\HtmlString.
*/
class Expression extends HtmlString
{
}
<?php
namespace Illuminate\View;
use Closure;
use Illuminate\Support\Arr;
use Illuminate\Support\Str;
use InvalidArgumentException;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\View\Engines\EngineResolver;
use Illuminate\Contracts\Events\Dispatcher;
use Illuminate\Contracts\Container\Container;
use Illuminate\Contracts\View\Factory as FactoryContract;
class Factory implements FactoryContract
{
/**
* The engine implementation.
*
* @var \Illuminate\View\Engines\EngineResolver
*/
protected $engines;
/**
* The view finder implementation.
*
* @var \Illuminate\View\ViewFinderInterface
*/
protected $finder;
/**
* The event dispatcher instance.
*
* @var \Illuminate\Contracts\Events\Dispatcher
*/
protected $events;
/**
* The IoC container instance.
*
* @var \Illuminate\Contracts\Container\Container
*/
protected $container;
/**
* Data that should be available to all templates.
*
* @var array
*/
protected $shared = [];
/**
* Array of registered view name aliases.
*
* @var array
*/
protected $aliases = [];
/**
* All of the registered view names.
*
* @var array
*/
protected $names = [];
/**
* The extension to engine bindings.
*
* @var array
*/
protected $extensions = ['blade.php' => 'blade', 'php' => 'php'];
/**
* The view composer events.
*
* @var array
*/
protected $composers = [];
/**
* All of the finished, captured sections.
*
* @var array
*/
protected $sections = [];
/**
* The stack of in-progress sections.
*
* @var array
*/
protected $sectionStack = [];
/**
* All of the finished, captured push sections.
*
* @var array
*/
protected $pushes = [];
/**
* The stack of in-progress push sections.
*
* @var array
*/
protected $pushStack = [];
/**
* The number of active rendering operations.
*
* @var int
*/
protected $renderCount = 0;
/**
* Create a new view factory instance.
*
* @param \Illuminate\View\Engines\EngineResolver $engines
* @param \Illuminate\View\ViewFinderInterface $finder
* @param \Illuminate\Contracts\Events\Dispatcher $events
* @return void
*/
public function __construct(EngineResolver $engines, ViewFinderInterface $finder, Dispatcher $events)
{
$this->finder = $finder;
$this->events = $events;
$this->engines = $engines;
$this->share('__env', $this);
}
/**
* Get the evaluated view contents for the given view.
*
* @param string $path
* @param array $data
* @param array $mergeData
* @return \Illuminate\Contracts\View\View
*/
public function file($path, $data = [], $mergeData = [])
{
$data = array_merge($mergeData, $this->parseData($data));
$this->callCreator($view = new View($this, $this->getEngineFromPath($path), $path, $path, $data));
return $view;
}
/**
* Get the evaluated view contents for the given view.
*
* @param string $view
* @param array $data
* @param array $mergeData
* @return \Illuminate\Contracts\View\View
*/
public function make($view, $data = [], $mergeData = [])
{
if (isset($this->aliases[$view])) {
$view = $this->aliases[$view];
}
$view = $this->normalizeName($view);
$path = $this->finder->find($view);
$data = array_merge($mergeData, $this->parseData($data));
$this->callCreator($view = new View($this, $this->getEngineFromPath($path), $view, $path, $data));
return $view;
}
/**
* Normalize a view name.
*
* @param string $name
* @return string
*/
protected function normalizeName($name)
{
$delimiter = ViewFinderInterface::HINT_PATH_DELIMITER;
if (strpos($name, $delimiter) === false) {
return str_replace('/', '.', $name);
}
list($namespace, $name) = explode($delimiter, $name);
return $namespace.$delimiter.str_replace('/', '.', $name);
}
/**
* Parse the given data into a raw array.
*
* @param mixed $data
* @return array
*/
protected function parseData($data)
{
return $data instanceof Arrayable ? $data->toArray() : $data;
}
/**
* Get the evaluated view contents for a named view.
*
* @param string $view
* @param mixed $data
* @return \Illuminate\Contracts\View\View
*/
public function of($view, $data = [])
{
return $this->make($this->names[$view], $data);
}
/**
* Register a named view.
*
* @param string $view
* @param string $name
* @return void
*/
public function name($view, $name)
{
$this->names[$name] = $view;
}
/**
* Add an alias for a view.
*
* @param string $view
* @param string $alias
* @return void
*/
public function alias($view, $alias)
{
$this->aliases[$alias] = $view;
}
/**
* Determine if a given view exists.
*
* @param string $view
* @return bool
*/
public function exists($view)
{
try {
$this->finder->find($view);
} catch (InvalidArgumentException $e) {
return false;
}
return true;
}
/**
* Get the rendered contents of a partial from a loop.
*
* @param string $view
* @param array $data
* @param string $iterator
* @param string $empty
* @return string
*/
public function renderEach($view, $data, $iterator, $empty = 'raw|')
{
$result = '';
// If is actually data in the array, we will loop through the data and append
// an instance of the partial view to the final result HTML passing in the
// iterated value of this data array, allowing the views to access them.
if (count($data) > 0) {
foreach ($data as $key => $value) {
$data = ['key' => $key, $iterator => $value];
$result .= $this->make($view, $data)->render();
}
}
// If there is no data in the array, we will render the contents of the empty
// view. Alternatively, the "empty view" could be a raw string that begins
// with "raw|" for convenience and to let this know that it is a string.
else {
if (Str::startsWith($empty, 'raw|')) {
$result = substr($empty, 4);
} else {
$result = $this->make($empty)->render();
}
}
return $result;
}
/**
* Get the appropriate view engine for the given path.
*
* @param string $path
* @return \Illuminate\View\Engines\EngineInterface
*
* @throws \InvalidArgumentException
*/
public function getEngineFromPath($path)
{
if (! $extension = $this->getExtension($path)) {
throw new InvalidArgumentException("Unrecognized extension in file: $path");
}
$engine = $this->extensions[$extension];
return $this->engines->resolve($engine);
}
/**
* Get the extension used by the view file.
*
* @param string $path
* @return string
*/
protected function getExtension($path)
{
$extensions = array_keys($this->extensions);
return Arr::first($extensions, function ($key, $value) use ($path) {
return Str::endsWith($path, '.'.$value);
});
}
/**
* Add a piece of shared data to the environment.
*
* @param array|string $key
* @param mixed $value
* @return mixed
*/
public function share($key, $value = null)
{
if (! is_array($key)) {
return $this->shared[$key] = $value;
}
foreach ($key as $innerKey => $innerValue) {
$this->share($innerKey, $innerValue);
}
}
/**
* Register a view creator event.
*
* @param array|string $views
* @param \Closure|string $callback
* @return array
*/
public function creator($views, $callback)
{
$creators = [];
foreach ((array) $views as $view) {
$creators[] = $this->addViewEvent($view, $callback, 'creating: ');
}
return $creators;
}
/**
* Register multiple view composers via an array.
*
* @param array $composers
* @return array
*/
public function composers(array $composers)
{
$registered = [];
foreach ($composers as $callback => $views) {
$registered = array_merge($registered, $this->composer($views, $callback));
}
return $registered;
}
/**
* Register a view composer event.
*
* @param array|string $views
* @param \Closure|string $callback
* @param int|null $priority
* @return array
*/
public function composer($views, $callback, $priority = null)
{
$composers = [];
foreach ((array) $views as $view) {
$composers[] = $this->addViewEvent($view, $callback, 'composing: ', $priority);
}
return $composers;
}
/**
* Add an event for a given view.
*
* @param string $view
* @param \Closure|string $callback
* @param string $prefix
* @param int|null $priority
* @return \Closure|null
*/
protected function addViewEvent($view, $callback, $prefix = 'composing: ', $priority = null)
{
$view = $this->normalizeName($view);
if ($callback instanceof Closure) {
$this->addEventListener($prefix.$view, $callback, $priority);
return $callback;
} elseif (is_string($callback)) {
return $this->addClassEvent($view, $callback, $prefix, $priority);
}
}
/**
* Register a class based view composer.
*
* @param string $view
* @param string $class
* @param string $prefix
* @param int|null $priority
* @return \Closure
*/
protected function addClassEvent($view, $class, $prefix, $priority = null)
{
$name = $prefix.$view;
// When registering a class based view "composer", we will simply resolve the
// classes from the application IoC container then call the compose method
// on the instance. This allows for convenient, testable view composers.
$callback = $this->buildClassEventCallback($class, $prefix);
$this->addEventListener($name, $callback, $priority);
return $callback;
}
/**
* Add a listener to the event dispatcher.
*
* @param string $name
* @param \Closure $callback
* @param int|null $priority
* @return void
*/
protected function addEventListener($name, $callback, $priority = null)
{
if (is_null($priority)) {
$this->events->listen($name, $callback);
} else {
$this->events->listen($name, $callback, $priority);
}
}
/**
* Build a class based container callback Closure.
*
* @param string $class
* @param string $prefix
* @return \Closure
*/
protected function buildClassEventCallback($class, $prefix)
{
list($class, $method) = $this->parseClassEvent($class, $prefix);
// Once we have the class and method name, we can build the Closure to resolve
// the instance out of the IoC container and call the method on it with the
// given arguments that are passed to the Closure as the composer's data.
return function () use ($class, $method) {
$callable = [$this->container->make($class), $method];
return call_user_func_array($callable, func_get_args());
};
}
/**
* Parse a class based composer name.
*
* @param string $class
* @param string $prefix
* @return array
*/
protected function parseClassEvent($class, $prefix)
{
if (Str::contains($class, '@')) {
return explode('@', $class);
}
$method = Str::contains($prefix, 'composing') ? 'compose' : 'create';
return [$class, $method];
}
/**
* Call the composer for a given view.
*
* @param \Illuminate\Contracts\View\View $view
* @return void
*/
public function callComposer(View $view)
{
$this->events->fire('composing: '.$view->getName(), [$view]);
}
/**
* Call the creator for a given view.
*
* @param \Illuminate\Contracts\View\View $view
* @return void
*/
public function callCreator(View $view)
{
$this->events->fire('creating: '.$view->getName(), [$view]);
}
/**
* Start injecting content into a section.
*
* @param string $section
* @param string $content
* @return void
*/
public function startSection($section, $content = '')
{
if ($content === '') {
if (ob_start()) {
$this->sectionStack[] = $section;
}
} else {
$this->extendSection($section, $content);
}
}
/**
* Inject inline content into a section.
*
* @param string $section
* @param string $content
* @return void
*/
public function inject($section, $content)
{
return $this->startSection($section, $content);
}
/**
* Stop injecting content into a section and return its contents.
*
* @return string
*/
public function yieldSection()
{
if (empty($this->sectionStack)) {
return '';
}
return $this->yieldContent($this->stopSection());
}
/**
* Stop injecting content into a section.
*
* @param bool $overwrite
* @return string
* @throws \InvalidArgumentException
*/
public function stopSection($overwrite = false)
{
if (empty($this->sectionStack)) {
throw new InvalidArgumentException('Cannot end a section without first starting one.');
}
$last = array_pop($this->sectionStack);
if ($overwrite) {
$this->sections[$last] = ob_get_clean();
} else {
$this->extendSection($last, ob_get_clean());
}
return $last;
}
/**
* Stop injecting content into a section and append it.
*
* @return string
* @throws \InvalidArgumentException
*/
public function appendSection()
{
if (empty($this->sectionStack)) {
throw new InvalidArgumentException('Cannot end a section without first starting one.');
}
$last = array_pop($this->sectionStack);
if (isset($this->sections[$last])) {
$this->sections[$last] .= ob_get_clean();
} else {
$this->sections[$last] = ob_get_clean();
}
return $last;
}
/**
* Append content to a given section.
*
* @param string $section
* @param string $content
* @return void
*/
protected function extendSection($section, $content)
{
if (isset($this->sections[$section])) {
$content = str_replace('@parent', $content, $this->sections[$section]);
}
$this->sections[$section] = $content;
}
/**
* Get the string contents of a section.
*
* @param string $section
* @param string $default
* @return string
*/
public function yieldContent($section, $default = '')
{
$sectionContent = $default;
if (isset($this->sections[$section])) {
$sectionContent = $this->sections[$section];
}
$sectionContent = str_replace('@@parent', '--parent--holder--', $sectionContent);
return str_replace(
'--parent--holder--', '@parent', str_replace('@parent', '', $sectionContent)
);
}
/**
* Start injecting content into a push section.
*
* @param string $section
* @param string $content
* @return void
*/
public function startPush($section, $content = '')
{
if ($content === '') {
if (ob_start()) {
$this->pushStack[] = $section;
}
} else {
$this->extendPush($section, $content);
}
}
/**
* Stop injecting content into a push section.
*
* @return string
* @throws \InvalidArgumentException
*/
public function stopPush()
{
if (empty($this->pushStack)) {
throw new InvalidArgumentException('Cannot end a section without first starting one.');
}
$last = array_pop($this->pushStack);
$this->extendPush($last, ob_get_clean());
return $last;
}
/**
* Append content to a given push section.
*
* @param string $section
* @param string $content
* @return void
*/
protected function extendPush($section, $content)
{
if (! isset($this->pushes[$section])) {
$this->pushes[$section] = [];
}
if (! isset($this->pushes[$section][$this->renderCount])) {
$this->pushes[$section][$this->renderCount] = $content;
} else {
$this->pushes[$section][$this->renderCount] .= $content;
}
}
/**
* Get the string contents of a push section.
*
* @param string $section
* @param string $default
* @return string
*/
public function yieldPushContent($section, $default = '')
{
if (! isset($this->pushes[$section])) {
return $default;
}
return implode(array_reverse($this->pushes[$section]));
}
/**
* Flush all of the section contents.
*
* @return void
*/
public function flushSections()
{
$this->renderCount = 0;
$this->sections = [];
$this->sectionStack = [];
$this->pushes = [];
$this->pushStack = [];
}
/**
* Flush all of the section contents if done rendering.
*
* @return void
*/
public function flushSectionsIfDoneRendering()
{
if ($this->doneRendering()) {
$this->flushSections();
}
}
/**
* Increment the rendering counter.
*
* @return void
*/
public function incrementRender()
{
$this->renderCount++;
}
/**
* Decrement the rendering counter.
*
* @return void
*/
public function decrementRender()
{
$this->renderCount--;
}
/**
* Check if there are no active render operations.
*
* @return bool
*/
public function doneRendering()
{
return $this->renderCount == 0;
}
/**
* Add a location to the array of view locations.
*
* @param string $location
* @return void
*/
public function addLocation($location)
{
$this->finder->addLocation($location);
}
/**
* Add a new namespace to the loader.
*
* @param string $namespace
* @param string|array $hints
* @return void
*/
public function addNamespace($namespace, $hints)
{
$this->finder->addNamespace($namespace, $hints);
}
/**
* Prepend a new namespace to the loader.
*
* @param string $namespace
* @param string|array $hints
* @return void
*/
public function prependNamespace($namespace, $hints)
{
$this->finder->prependNamespace($namespace, $hints);
}
/**
* Register a valid view extension and its engine.
*
* @param string $extension
* @param string $engine
* @param \Closure $resolver
* @return void
*/
public function addExtension($extension, $engine, $resolver = null)
{
$this->finder->addExtension($extension);
if (isset($resolver)) {
$this->engines->register($engine, $resolver);
}
unset($this->extensions[$extension]);
$this->extensions = array_merge([$extension => $engine], $this->extensions);
}
/**
* Get the extension to engine bindings.
*
* @return array
*/
public function getExtensions()
{
return $this->extensions;
}
/**
* Get the engine resolver instance.
*
* @return \Illuminate\View\Engines\EngineResolver
*/
public function getEngineResolver()
{
return $this->engines;
}
/**
* Get the view finder instance.
*
* @return \Illuminate\View\ViewFinderInterface
*/
public function getFinder()
{
return $this->finder;
}
/**
* Set the view finder instance.
*
* @param \Illuminate\View\ViewFinderInterface $finder
* @return void
*/
public function setFinder(ViewFinderInterface $finder)
{
$this->finder = $finder;
}
/**
* Get the event dispatcher instance.
*
* @return \Illuminate\Contracts\Events\Dispatcher
*/
public function getDispatcher()
{
return $this->events;
}
/**
* Set the event dispatcher instance.
*
* @param \Illuminate\Contracts\Events\Dispatcher $events
* @return void
*/
public function setDispatcher(Dispatcher $events)
{
$this->events = $events;
}
/**
* Get the IoC container instance.
*
* @return \Illuminate\Contracts\Container\Container
*/
public function getContainer()
{
return $this->container;
}
/**
* Set the IoC container instance.
*
* @param \Illuminate\Contracts\Container\Container $container
* @return void
*/
public function setContainer(Container $container)
{
$this->container = $container;
}
/**
* Get an item from the shared data.
*
* @param string $key
* @param mixed $default
* @return mixed
*/
public function shared($key, $default = null)
{
return Arr::get($this->shared, $key, $default);
}
/**
* Get all of the shared data for the environment.
*
* @return array
*/
public function getShared()
{
return $this->shared;
}
/**
* Check if section exists.
*
* @param string $name
* @return bool
*/
public function hasSection($name)
{
return array_key_exists($name, $this->sections);
}
/**
* Get the entire array of sections.
*
* @return array
*/
public function getSections()
{
return $this->sections;
}
/**
* Get all of the registered named views in environment.
*
* @return array
*/
public function getNames()
{
return $this->names;
}
}
<?php
namespace Illuminate\View;
use InvalidArgumentException;
use Illuminate\Filesystem\Filesystem;
class FileViewFinder implements ViewFinderInterface
{
/**
* The filesystem instance.
*
* @var \Illuminate\Filesystem\Filesystem
*/
protected $files;
/**
* The array of active view paths.
*
* @var array
*/
protected $paths;
/**
* The array of views that have been located.
*
* @var array
*/
protected $views = [];
/**
* The namespace to file path hints.
*
* @var array
*/
protected $hints = [];
/**
* Register a view extension with the finder.
*
* @var array
*/
protected $extensions = ['blade.php', 'php'];
/**
* Create a new file view loader instance.
*
* @param \Illuminate\Filesystem\Filesystem $files
* @param array $paths
* @param array $extensions
* @return void
*/
public function __construct(Filesystem $files, array $paths, array $extensions = null)
{
$this->files = $files;
$this->paths = $paths;
if (isset($extensions)) {
$this->extensions = $extensions;
}
}
/**
* Get the fully qualified location of the view.
*
* @param string $name
* @return string
*/
public function find($name)
{
if (isset($this->views[$name])) {
return $this->views[$name];
}
if ($this->hasHintInformation($name = trim($name))) {
return $this->views[$name] = $this->findNamedPathView($name);
}
return $this->views[$name] = $this->findInPaths($name, $this->paths);
}
/**
* Get the path to a template with a named path.
*
* @param string $name
* @return string
*/
protected function findNamedPathView($name)
{
list($namespace, $view) = $this->getNamespaceSegments($name);
return $this->findInPaths($view, $this->hints[$namespace]);
}
/**
* Get the segments of a template with a named path.
*
* @param string $name
* @return array
*
* @throws \InvalidArgumentException
*/
protected function getNamespaceSegments($name)
{
$segments = explode(static::HINT_PATH_DELIMITER, $name);
if (count($segments) != 2) {
throw new InvalidArgumentException("View [$name] has an invalid name.");
}
if (! isset($this->hints[$segments[0]])) {
throw new InvalidArgumentException("No hint path defined for [{$segments[0]}].");
}
return $segments;
}
/**
* Find the given view in the list of paths.
*
* @param string $name
* @param array $paths
* @return string
*
* @throws \InvalidArgumentException
*/
protected function findInPaths($name, $paths)
{
foreach ((array) $paths as $path) {
foreach ($this->getPossibleViewFiles($name) as $file) {
if ($this->files->exists($viewPath = $path.'/'.$file)) {
return $viewPath;
}
}
}
throw new InvalidArgumentException("View [$name] not found.");
}
/**
* Get an array of possible view files.
*
* @param string $name
* @return array
*/
protected function getPossibleViewFiles($name)
{
return array_map(function ($extension) use ($name) {
return str_replace('.', '/', $name).'.'.$extension;
}, $this->extensions);
}
/**
* Add a location to the finder.
*
* @param string $location
* @return void
*/
public function addLocation($location)
{
$this->paths[] = $location;
}
/**
* Add a namespace hint to the finder.
*
* @param string $namespace
* @param string|array $hints
* @return void
*/
public function addNamespace($namespace, $hints)
{
$hints = (array) $hints;
if (isset($this->hints[$namespace])) {
$hints = array_merge($this->hints[$namespace], $hints);
}
$this->hints[$namespace] = $hints;
}
/**
* Prepend a namespace hint to the finder.
*
* @param string $namespace
* @param string|array $hints
* @return void
*/
public function prependNamespace($namespace, $hints)
{
$hints = (array) $hints;
if (isset($this->hints[$namespace])) {
$hints = array_merge($hints, $this->hints[$namespace]);
}
$this->hints[$namespace] = $hints;
}
/**
* Register an extension with the view finder.
*
* @param string $extension
* @return void
*/
public function addExtension($extension)
{
if (($index = array_search($extension, $this->extensions)) !== false) {
unset($this->extensions[$index]);
}
array_unshift($this->extensions, $extension);
}
/**
* Returns whether or not the view specify a hint information.
*
* @param string $name
* @return bool
*/
public function hasHintInformation($name)
{
return strpos($name, static::HINT_PATH_DELIMITER) > 0;
}
/**
* Get the filesystem instance.
*
* @return \Illuminate\Filesystem\Filesystem
*/
public function getFilesystem()
{
return $this->files;
}
/**
* Get the active view paths.
*
* @return array
*/
public function getPaths()
{
return $this->paths;
}
/**
* Get the namespace to file path hints.
*
* @return array
*/
public function getHints()
{
return $this->hints;
}
/**
* Get registered extensions.
*
* @return array
*/
public function getExtensions()
{
return $this->extensions;
}
}
<?php
namespace Illuminate\View\Middleware;
use Closure;
use Illuminate\Support\ViewErrorBag;
use Illuminate\Contracts\View\Factory as ViewFactory;
class ShareErrorsFromSession
{
/**
* The view factory implementation.
*
* @var \Illuminate\Contracts\View\Factory
*/
protected $view;
/**
* Create a new error binder instance.
*
* @param \Illuminate\Contracts\View\Factory $view
* @return void
*/
public function __construct(ViewFactory $view)
{
$this->view = $view;
}
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next)
{
// If the current session has an "errors" variable bound to it, we will share
// its value with all view instances so the views can easily access errors
// without having to bind. An empty bag is set when there aren't errors.
$this->view->share(
'errors', $request->session()->get('errors') ?: new ViewErrorBag
);
// Putting the errors in the view for every view allows the developer to just
// assume that some errors are always available, which is convenient since
// they don't have to continually run checks for the presence of errors.
return $next($request);
}
}
<?php
namespace Illuminate\View;
use Exception;
use Throwable;
use ArrayAccess;
use BadMethodCallException;
use Illuminate\Support\Str;
use Illuminate\Support\MessageBag;
use Illuminate\Contracts\Support\Arrayable;
use Illuminate\View\Engines\EngineInterface;
use Illuminate\Contracts\Support\Renderable;
use Illuminate\Contracts\Support\MessageProvider;
use Illuminate\Contracts\View\View as ViewContract;
class View implements ArrayAccess, ViewContract
{
/**
* The view factory instance.
*
* @var \Illuminate\View\Factory
*/
protected $factory;
/**
* The engine implementation.
*
* @var \Illuminate\View\Engines\EngineInterface
*/
protected $engine;
/**
* The name of the view.
*
* @var string
*/
protected $view;
/**
* The array of view data.
*
* @var array
*/
protected $data;
/**
* The path to the view file.
*
* @var string
*/
protected $path;
/**
* Create a new view instance.
*
* @param \Illuminate\View\Factory $factory
* @param \Illuminate\View\Engines\EngineInterface $engine
* @param string $view
* @param string $path
* @param mixed $data
* @return void
*/
public function __construct(Factory $factory, EngineInterface $engine, $view, $path, $data = [])
{
$this->view = $view;
$this->path = $path;
$this->engine = $engine;
$this->factory = $factory;
$this->data = $data instanceof Arrayable ? $data->toArray() : (array) $data;
}
/**
* Get the string contents of the view.
*
* @param callable|null $callback
* @return string
*/
public function render(callable $callback = null)
{
try {
$contents = $this->renderContents();
$response = isset($callback) ? call_user_func($callback, $this, $contents) : null;
// Once we have the contents of the view, we will flush the sections if we are
// done rendering all views so that there is nothing left hanging over when
// another view gets rendered in the future by the application developer.
$this->factory->flushSectionsIfDoneRendering();
return ! is_null($response) ? $response : $contents;
} catch (Exception $e) {
$this->factory->flushSections();
throw $e;
} catch (Throwable $e) {
$this->factory->flushSections();
throw $e;
}
}
/**
* Get the contents of the view instance.
*
* @return string
*/
protected function renderContents()
{
// We will keep track of the amount of views being rendered so we can flush
// the section after the complete rendering operation is done. This will
// clear out the sections for any separate views that may be rendered.
$this->factory->incrementRender();
$this->factory->callComposer($this);
$contents = $this->getContents();
// Once we've finished rendering the view, we'll decrement the render count
// so that each sections get flushed out next time a view is created and
// no old sections are staying around in the memory of an environment.
$this->factory->decrementRender();
return $contents;
}
/**
* Get the sections of the rendered view.
*
* @return array
*/
public function renderSections()
{
return $this->render(function () {
return $this->factory->getSections();
});
}
/**
* Get the evaluated contents of the view.
*
* @return string
*/
protected function getContents()
{
return $this->engine->get($this->path, $this->gatherData());
}
/**
* Get the data bound to the view instance.
*
* @return array
*/
protected function gatherData()
{
$data = array_merge($this->factory->getShared(), $this->data);
foreach ($data as $key => $value) {
if ($value instanceof Renderable) {
$data[$key] = $value->render();
}
}
return $data;
}
/**
* Add a piece of data to the view.
*
* @param string|array $key
* @param mixed $value
* @return $this
*/
public function with($key, $value = null)
{
if (is_array($key)) {
$this->data = array_merge($this->data, $key);
} else {
$this->data[$key] = $value;
}
return $this;
}
/**
* Add a view instance to the view data.
*
* @param string $key
* @param string $view
* @param array $data
* @return $this
*/
public function nest($key, $view, array $data = [])
{
return $this->with($key, $this->factory->make($view, $data));
}
/**
* Add validation errors to the view.
*
* @param \Illuminate\Contracts\Support\MessageProvider|array $provider
* @return $this
*/
public function withErrors($provider)
{
if ($provider instanceof MessageProvider) {
$this->with('errors', $provider->getMessageBag());
} else {
$this->with('errors', new MessageBag((array) $provider));
}
return $this;
}
/**
* Get the view factory instance.
*
* @return \Illuminate\View\Factory
*/
public function getFactory()
{
return $this->factory;
}
/**
* Get the view's rendering engine.
*
* @return \Illuminate\View\Engines\EngineInterface
*/
public function getEngine()
{
return $this->engine;
}
/**
* Get the name of the view.
*
* @return string
*/
public function name()
{
return $this->getName();
}
/**
* Get the name of the view.
*
* @return string
*/
public function getName()
{
return $this->view;
}
/**
* Get the array of view data.
*
* @return array
*/
public function getData()
{
return $this->data;
}
/**
* Get the path to the view file.
*
* @return string
*/
public function getPath()
{
return $this->path;
}
/**
* Set the path to the view.
*
* @param string $path
* @return void
*/
public function setPath($path)
{
$this->path = $path;
}
/**
* Determine if a piece of data is bound.
*
* @param string $key
* @return bool
*/
public function offsetExists($key)
{
return array_key_exists($key, $this->data);
}
/**
* Get a piece of bound data to the view.
*
* @param string $key
* @return mixed
*/
public function offsetGet($key)
{
return $this->data[$key];
}
/**
* Set a piece of data on the view.
*
* @param string $key
* @param mixed $value
* @return void
*/
public function offsetSet($key, $value)
{
$this->with($key, $value);
}
/**
* Unset a piece of data from the view.
*
* @param string $key
* @return void
*/
public function offsetUnset($key)
{
unset($this->data[$key]);
}
/**
* Get a piece of data from the view.
*
* @param string $key
* @return mixed
*/
public function &__get($key)
{
return $this->data[$key];
}
/**
* Set a piece of data on the view.
*
* @param string $key
* @param mixed $value
* @return void
*/
public function __set($key, $value)
{
$this->with($key, $value);
}
/**
* Check if a piece of data is bound to the view.
*
* @param string $key
* @return bool
*/
public function __isset($key)
{
return isset($this->data[$key]);
}
/**
* Remove a piece of bound data from the view.
*
* @param string $key
* @return bool
*/
public function __unset($key)
{
unset($this->data[$key]);
}
/**
* Dynamically bind parameters to the view.
*
* @param string $method
* @param array $parameters
* @return \Illuminate\View\View
*
* @throws \BadMethodCallException
*/
public function __call($method, $parameters)
{
if (Str::startsWith($method, 'with')) {
return $this->with(Str::snake(substr($method, 4)), $parameters[0]);
}
throw new BadMethodCallException("Method [$method] does not exist on view.");
}
/**
* Get the string contents of the view.
*
* @return string
*/
public function __toString()
{
return $this->render();
}
}
<?php
namespace Illuminate\View;
interface ViewFinderInterface
{
/**
* Hint path delimiter value.
*
* @var string
*/
const HINT_PATH_DELIMITER = '::';
/**
* Get the fully qualified location of the view.
*
* @param string $view
* @return string
*/
public function find($view);
/**
* Add a location to the finder.
*
* @param string $location
* @return void
*/
public function addLocation($location);
/**
* Add a namespace hint to the finder.
*
* @param string $namespace
* @param string|array $hints
* @return void
*/
public function addNamespace($namespace, $hints);
/**
* Prepend a namespace hint to the finder.
*
* @param string $namespace
* @param string|array $hints
* @return void
*/
public function prependNamespace($namespace, $hints);
/**
* Add a valid view extension to the finder.
*
* @param string $extension
* @return void
*/
public function addExtension($extension);
}
<?php
namespace Illuminate\View;
use Illuminate\View\Engines\PhpEngine;
use Illuminate\Support\ServiceProvider;
use Illuminate\View\Engines\CompilerEngine;
use Illuminate\View\Engines\EngineResolver;
use Illuminate\View\Compilers\BladeCompiler;
class ViewServiceProvider extends ServiceProvider
{
/**
* Register the service provider.
*
* @return void
*/
public function register()
{
$this->registerEngineResolver();
$this->registerViewFinder();
$this->registerFactory();
}
/**
* Register the engine resolver instance.
*
* @return void
*/
public function registerEngineResolver()
{
$this->app->singleton('view.engine.resolver', function () {
$resolver = new EngineResolver;
// Next we will register the various engines with the resolver so that the
// environment can resolve the engines it needs for various views based
// on the extension of view files. We call a method for each engines.
foreach (['php', 'blade'] as $engine) {
$this->{'register'.ucfirst($engine).'Engine'}($resolver);
}
return $resolver;
});
}
/**
* Register the PHP engine implementation.
*
* @param \Illuminate\View\Engines\EngineResolver $resolver
* @return void
*/
public function registerPhpEngine($resolver)
{
$resolver->register('php', function () {
return new PhpEngine;
});
}
/**
* Register the Blade engine implementation.
*
* @param \Illuminate\View\Engines\EngineResolver $resolver
* @return void
*/
public function registerBladeEngine($resolver)
{
$app = $this->app;
// The Compiler engine requires an instance of the CompilerInterface, which in
// this case will be the Blade compiler, so we'll first create the compiler
// instance to pass into the engine so it can compile the views properly.
$app->singleton('blade.compiler', function ($app) {
$cache = $app['config']['view.compiled'];
return new BladeCompiler($app['files'], $cache);
});
$resolver->register('blade', function () use ($app) {
return new CompilerEngine($app['blade.compiler']);
});
}
/**
* Register the view finder implementation.
*
* @return void
*/
public function registerViewFinder()
{
$this->app->bind('view.finder', function ($app) {
$paths = $app['config']['view.paths'];
return new FileViewFinder($app['files'], $paths);
});
}
/**
* Register the view environment.
*
* @return void
*/
public function registerFactory()
{
$this->app->singleton('view', function ($app) {
// Next we need to grab the engine resolver instance that will be used by the
// environment. The resolver will be used by an environment to get each of
// the various engine implementations such as plain PHP or Blade engine.
$resolver = $app['view.engine.resolver'];
$finder = $app['view.finder'];
$env = new Factory($resolver, $finder, $app['events']);
// We will also set the container instance on this view environment since the
// view composers may be classes registered in the container, which allows
// for great testable, flexible composers for the application developer.
$env->setContainer($app);
$env->share('app', $app);
return $env;
});
}
}
<?php
$finder = Symfony\CS\Finder\DefaultFinder::create()
->files()
->name('*.php')
->in(__DIR__.'/src')
->in(__DIR__.'/tests')
;
return Symfony\CS\Config\Config::create()
->fixers(array(
'psr0', 'encoding', 'short_tag', 'braces', 'elseif', 'eof_ending', 'function_declaration', 'indentation', 'line_after_namespace', 'linefeed', 'lowercase_constants', 'lowercase_keywords', 'multiple_use', 'php_closing_tag', 'trailing_spaces', 'visibility', 'duplicate_semicolon', 'extra_empty_lines', 'include', 'namespace_no_leading_whitespace', 'object_operator', 'operators_spaces', 'phpdoc_params', 'return', 'single_array_no_trailing_comma', 'spaces_cast', 'standardize_not_equal', 'ternary_spaces', 'unused_use', 'whitespacy_lines',
))
->finder($finder)
;

1.17.2 (2015-10-14)

  • Fixed ErrorHandler compatibility with non-Monolog PSR-3 loggers
  • Fixed SlackHandler handling to use slack functionalities better
  • Fixed SwiftMailerHandler bug when sending multiple emails they all had the same id
  • Fixed 5.3 compatibility regression

1.17.1 (2015-08-31)

  • Fixed RollbarHandler triggering PHP notices

1.17.0 (2015-08-30)

  • Added support for checksum and release context/extra values in RavenHandler
  • Added better support for exceptions in RollbarHandler
  • Added UidProcessor::getUid
  • Added support for showing the resource type in NormalizedFormatter
  • Fixed IntrospectionProcessor triggering PHP notices

1.16.0 (2015-08-09)

  • Added IFTTTHandler to notify ifttt.com triggers
  • Added Logger::setHandlers() to allow setting/replacing all handlers
  • Added $capSize in RedisHandler to cap the log size
  • Fixed StreamHandler creation of directory to only trigger when the first log write happens
  • Fixed bug in the handling of curl failures
  • Fixed duplicate logging of fatal errors when both error and fatal error handlers are registered in monolog's ErrorHandler
  • Fixed missing fatal errors records with handlers that need to be closed to flush log records
  • Fixed TagProcessor::addTags support for associative arrays

1.15.0 (2015-07-12)

  • Added addTags and setTags methods to change a TagProcessor
  • Added automatic creation of directories if they are missing for a StreamHandler to open a log file
  • Added retry functionality to Loggly, Cube and Mandrill handlers so they retry up to 5 times in case of network failure
  • Fixed process exit code being incorrectly reset to 0 if ErrorHandler::registerExceptionHandler was used
  • Fixed HTML/JS escaping in BrowserConsoleHandler
  • Fixed JSON encoding errors being silently suppressed (PHP 5.5+ only)

1.14.0 (2015-06-19)

  • Added PHPConsoleHandler to send record to Chrome's PHP Console extension and library
  • Added support for objects implementing __toString in the NormalizerFormatter
  • Added support for HipChat's v2 API in HipChatHandler
  • Added Logger::setTimezone() to initialize the timezone monolog should use in case date.timezone isn't correct for your app
  • Added an option to send formatted message instead of the raw record on PushoverHandler via ->useFormattedMessage(true)
  • Fixed curl errors being silently suppressed

1.13.1 (2015-03-09)

  • Fixed regression in HipChat requiring a new token to be created

1.13.0 (2015-03-05)

  • Added Registry::hasLogger to check for the presence of a logger instance
  • Added context.user support to RavenHandler
  • Added HipChat API v2 support in the HipChatHandler
  • Added NativeMailerHandler::addParameter to pass params to the mail() process
  • Added context data to SlackHandler when $includeContextAndExtra is true
  • Added ability to customize the Swift_Message per-email in SwiftMailerHandler
  • Fixed SwiftMailerHandler to lazily create message instances if a callback is provided
  • Fixed serialization of INF and NaN values in Normalizer and LineFormatter

1.12.0 (2014-12-29)

  • Break: HandlerInterface::isHandling now receives a partial record containing only a level key. This was always the intent and does not break any Monolog handler but is strictly speaking a BC break and you should check if you relied on any other field in your own handlers.
  • Added PsrHandler to forward records to another PSR-3 logger
  • Added SamplingHandler to wrap around a handler and include only every Nth record
  • Added MongoDBFormatter to support better storage with MongoDBHandler (it must be enabled manually for now)
  • Added exception codes in the output of most formatters
  • Added LineFormatter::includeStacktraces to enable exception stack traces in logs (uses more than one line)
  • Added $useShortAttachment to SlackHandler to minify attachment size and $includeExtra to append extra data
  • Added $host to HipChatHandler for users of private instances
  • Added $transactionName to NewRelicHandler and support for a transaction_name context value
  • Fixed MandrillHandler to avoid outputing API call responses
  • Fixed some non-standard behaviors in SyslogUdpHandler

1.11.0 (2014-09-30)

  • Break: The NewRelicHandler extra and context data are now prefixed with extra_ and context_ to avoid clashes. Watch out if you have scripts reading those from the API and rely on names
  • Added WhatFailureGroupHandler to suppress any exception coming from the wrapped handlers and avoid chain failures if a logging service fails
  • Added MandrillHandler to send emails via the Mandrillapp.com API
  • Added SlackHandler to log records to a Slack.com account
  • Added FleepHookHandler to log records to a Fleep.io account
  • Added LogglyHandler::addTag to allow adding tags to an existing handler
  • Added $ignoreEmptyContextAndExtra to LineFormatter to avoid empty [] at the end
  • Added $useLocking to StreamHandler and RotatingFileHandler to enable flock() while writing
  • Added support for PhpAmqpLib in the AmqpHandler
  • Added FingersCrossedHandler::clear and BufferHandler::clear to reset them between batches in long running jobs
  • Added support for adding extra fields from $_SERVER in the WebProcessor
  • Fixed support for non-string values in PrsLogMessageProcessor
  • Fixed SwiftMailer messages being sent with the wrong date in long running scripts
  • Fixed minor PHP 5.6 compatibility issues
  • Fixed BufferHandler::close being called twice

1.10.0 (2014-06-04)

  • Added Logger::getHandlers() and Logger::getProcessors() methods
  • Added $passthruLevel argument to FingersCrossedHandler to let it always pass some records through even if the trigger level is not reached
  • Added support for extra data in NewRelicHandler
  • Added $expandNewlines flag to the ErrorLogHandler to create multiple log entries when a message has multiple lines

1.9.1 (2014-04-24)

  • Fixed regression in RotatingFileHandler file permissions
  • Fixed initialization of the BufferHandler to make sure it gets flushed after receiving records
  • Fixed ChromePHPHandler and FirePHPHandler's activation strategies to be more conservative

1.9.0 (2014-04-20)

  • Added LogEntriesHandler to send logs to a LogEntries account
  • Added $filePermissions to tweak file mode on StreamHandler and RotatingFileHandler
  • Added $useFormatting flag to MemoryProcessor to make it send raw data in bytes
  • Added support for table formatting in FirePHPHandler via the table context key
  • Added a TagProcessor to add tags to records, and support for tags in RavenHandler
  • Added $appendNewline flag to the JsonFormatter to enable using it when logging to files
  • Added sound support to the PushoverHandler
  • Fixed multi-threading support in StreamHandler
  • Fixed empty headers issue when ChromePHPHandler received no records
  • Fixed default format of the ErrorLogHandler

1.8.0 (2014-03-23)

  • Break: the LineFormatter now strips newlines by default because this was a bug, set $allowInlineLineBreaks to true if you need them
  • Added BrowserConsoleHandler to send logs to any browser's console via console.log() injection in the output
  • Added FilterHandler to filter records and only allow those of a given list of levels through to the wrapped handler
  • Added FlowdockHandler to send logs to a Flowdock account
  • Added RollbarHandler to send logs to a Rollbar account
  • Added HtmlFormatter to send prettier log emails with colors for each log level
  • Added GitProcessor to add the current branch/commit to extra record data
  • Added a Monolog\Registry class to allow easier global access to pre-configured loggers
  • Added support for the new official graylog2/gelf-php lib for GelfHandler, upgrade if you can by replacing the mlehner/gelf-php requirement
  • Added support for HHVM
  • Added support for Loggly batch uploads
  • Added support for tweaking the content type and encoding in NativeMailerHandler
  • Added $skipClassesPartials to tweak the ignored classes in the IntrospectionProcessor
  • Fixed batch request support in GelfHandler

1.7.0 (2013-11-14)

  • Added ElasticSearchHandler to send logs to an Elastic Search server
  • Added DynamoDbHandler and ScalarFormatter to send logs to Amazon's Dynamo DB
  • Added SyslogUdpHandler to send logs to a remote syslogd server
  • Added LogglyHandler to send logs to a Loggly account
  • Added $level to IntrospectionProcessor so it only adds backtraces when needed
  • Added $version to LogstashFormatter to allow using the new v1 Logstash format
  • Added $appName to NewRelicHandler
  • Added configuration of Pushover notification retries/expiry
  • Added $maxColumnWidth to NativeMailerHandler to change the 70 chars default
  • Added chainability to most setters for all handlers
  • Fixed RavenHandler batch processing so it takes the message from the record with highest priority
  • Fixed HipChatHandler batch processing so it sends all messages at once
  • Fixed issues with eAccelerator
  • Fixed and improved many small things

1.6.0 (2013-07-29)

  • Added HipChatHandler to send logs to a HipChat chat room
  • Added ErrorLogHandler to send logs to PHP's error_log function
  • Added NewRelicHandler to send logs to NewRelic's service
  • Added Monolog\ErrorHandler helper class to register a Logger as exception/error/fatal handler
  • Added ChannelLevelActivationStrategy for the FingersCrossedHandler to customize levels by channel
  • Added stack traces output when normalizing exceptions (json output & co)
  • Added Monolog\Logger::API constant (currently 1)
  • Added support for ChromePHP's v4.0 extension
  • Added support for message priorities in PushoverHandler, see $highPriorityLevel and $emergencyLevel
  • Added support for sending messages to multiple users at once with the PushoverHandler
  • Fixed RavenHandler's support for batch sending of messages (when behind a Buffer or FingersCrossedHandler)
  • Fixed normalization of Traversables with very large data sets, only the first 1000 items are shown now
  • Fixed issue in RotatingFileHandler when an open_basedir restriction is active
  • Fixed minor issues in RavenHandler and bumped the API to Raven 0.5.0
  • Fixed SyslogHandler issue when many were used concurrently with different facilities

1.5.0 (2013-04-23)

  • Added ProcessIdProcessor to inject the PID in log records
  • Added UidProcessor to inject a unique identifier to all log records of one request/run
  • Added support for previous exceptions in the LineFormatter exception serialization
  • Added Monolog\Logger::getLevels() to get all available levels
  • Fixed ChromePHPHandler so it avoids sending headers larger than Chrome can handle

1.4.1 (2013-04-01)

  • Fixed exception formatting in the LineFormatter to be more minimalistic
  • Fixed RavenHandler's handling of context/extra data, requires Raven client >0.1.0
  • Fixed log rotation in RotatingFileHandler to work with long running scripts spanning multiple days
  • Fixed WebProcessor array access so it checks for data presence
  • Fixed Buffer, Group and FingersCrossed handlers to make use of their processors

1.4.0 (2013-02-13)

  • Added RedisHandler to log to Redis via the Predis library or the phpredis extension
  • Added ZendMonitorHandler to log to the Zend Server monitor
  • Added the possibility to pass arrays of handlers and processors directly in the Logger constructor
  • Added $useSSL option to the PushoverHandler which is enabled by default
  • Fixed ChromePHPHandler and FirePHPHandler issue when multiple instances are used simultaneously
  • Fixed header injection capability in the NativeMailHandler

1.3.1 (2013-01-11)

  • Fixed LogstashFormatter to be usable with stream handlers
  • Fixed GelfMessageFormatter levels on Windows

1.3.0 (2013-01-08)

  • Added PSR-3 compliance, the Monolog\Logger class is now an instance of Psr\Log\LoggerInterface
  • Added PsrLogMessageProcessor that you can selectively enable for full PSR-3 compliance
  • Added LogstashFormatter (combine with SocketHandler or StreamHandler to send logs to Logstash)
  • Added PushoverHandler to send mobile notifications
  • Added CouchDBHandler and DoctrineCouchDBHandler
  • Added RavenHandler to send data to Sentry servers
  • Added support for the new MongoClient class in MongoDBHandler
  • Added microsecond precision to log records' timestamps
  • Added $flushOnOverflow param to BufferHandler to flush by batches instead of losing the oldest entries
  • Fixed normalization of objects with cyclic references

1.2.1 (2012-08-29)

  • Added new $logopts arg to SyslogHandler to provide custom openlog options
  • Fixed fatal error in SyslogHandler

1.2.0 (2012-08-18)

  • Added AmqpHandler (for use with AMQP servers)
  • Added CubeHandler
  • Added NativeMailerHandler::addHeader() to send custom headers in mails
  • Added the possibility to specify more than one recipient in NativeMailerHandler
  • Added the possibility to specify float timeouts in SocketHandler
  • Added NOTICE and EMERGENCY levels to conform with RFC 5424
  • Fixed the log records to use the php default timezone instead of UTC
  • Fixed BufferHandler not being flushed properly on PHP fatal errors
  • Fixed normalization of exotic resource types
  • Fixed the default format of the SyslogHandler to avoid duplicating datetimes in syslog

1.1.0 (2012-04-23)

  • Added Monolog\Logger::isHandling() to check if a handler will handle the given log level
  • Added ChromePHPHandler
  • Added MongoDBHandler
  • Added GelfHandler (for use with Graylog2 servers)
  • Added SocketHandler (for use with syslog-ng for example)
  • Added NormalizerFormatter
  • Added the possibility to change the activation strategy of the FingersCrossedHandler
  • Added possibility to show microseconds in logs
  • Added server and referer to WebProcessor output

1.0.2 (2011-10-24)

  • Fixed bug in IE with large response headers and FirePHPHandler

1.0.1 (2011-08-25)

  • Added MemoryPeakUsageProcessor and MemoryUsageProcessor
  • Added Monolog\Logger::getName() to get a logger's channel name

1.0.0 (2011-07-06)

  • Added IntrospectionProcessor to get info from where the logger was called
  • Fixed WebProcessor in CLI

1.0.0-RC1 (2011-07-01)

  • Initial release
{
"name": "monolog/monolog",
"description": "Sends your logs to files, sockets, inboxes, databases and various web services",
"keywords": ["log", "logging", "psr-3"],
"homepage": "http://github.com/Seldaek/monolog",
"type": "library",
"license": "MIT",
"authors": [
{
"name": "Jordi Boggiano",
"email": "j.boggiano@seld.be",
"homepage": "http://seld.be"
}
],
"require": {
"php": ">=5.3.0",
"psr/log": "~1.0"
},
"require-dev": {
"phpunit/phpunit": "~4.5",
"graylog2/gelf-php": "~1.0",
"raven/raven": "^0.13",
"ruflin/elastica": ">=0.90 <3.0",
"doctrine/couchdb": "~1.0@dev",
"aws/aws-sdk-php": "^2.4.9",
"videlalvaro/php-amqplib": "~2.4",
"swiftmailer/swiftmailer": "~5.3",
"php-console/php-console": "^3.1.3",
"phpunit/phpunit-mock-objects": "2.3.0",
"jakub-onderka/php-parallel-lint": "0.9"
},
"_": "phpunit/phpunit-mock-objects required in 2.3.0 due to https://github.com/sebastianbergmann/phpunit-mock-objects/issues/223 - needs hhvm 3.8+ on travis",
"suggest": {
"graylog2/gelf-php": "Allow sending log messages to a GrayLog2 server",
"raven/raven": "Allow sending log messages to a Sentry server",
"doctrine/couchdb": "Allow sending log messages to a CouchDB server",
"ruflin/elastica": "Allow sending log messages to an Elastic Search server",
"videlalvaro/php-amqplib": "Allow sending log messages to an AMQP server using php-amqplib",
"ext-amqp": "Allow sending log messages to an AMQP server (1.0+ required)",
"ext-mongo": "Allow sending log messages to a MongoDB server",
"aws/aws-sdk-php": "Allow sending log messages to AWS services like DynamoDB",
"rollbar/rollbar": "Allow sending log messages to Rollbar",
"php-console/php-console": "Allow sending log messages to Google Chrome"
},
"autoload": {
"psr-4": {"Monolog\\": "src/Monolog"}
},
"autoload-dev": {
"psr-4": {"Monolog\\": "tests/Monolog"}
},
"provide": {
"psr/log-implementation": "1.0.0"
},
"extra": {
"branch-alias": {
"dev-master": "1.16.x-dev"
}
},
"scripts": {
"test": [
"parallel-lint . --exclude vendor",
"phpunit"
]
}
}

Using Monolog

Installation

Monolog is available on Packagist (monolog/monolog) and as such installable via Composer.

composer require monolog/monolog

If you do not use Composer, you can grab the code from GitHub, and use any PSR-0 compatible autoloader (e.g. the Symfony2 ClassLoader component) to load Monolog classes.

Core Concepts

Every Logger instance has a channel (name) and a stack of handlers. Whenever you add a record to the logger, it traverses the handler stack. Each handler decides whether it fully handled the record, and if so, the propagation of the record ends there.

This allows for flexible logging setups, for example having a StreamHandler at the bottom of the stack that will log anything to disk, and on top of that add a MailHandler that will send emails only when an error message is logged. Handlers also have a $bubble property which defines whether they block the record or not if they handled it. In this example, setting the MailHandler's $bubble argument to false means that records handled by the MailHandler will not propagate to the StreamHandler anymore.

You can create many Loggers, each defining a channel (e.g.: db, request, router, ..) and each of them combining various handlers, which can be shared or not. The channel is reflected in the logs and allows you to easily see or filter records.

Each Handler also has a Formatter, a default one with settings that make sense will be created if you don't set one. The formatters normalize and format incoming records so that they can be used by the handlers to output useful information.

Custom severity levels are not available. Only the eight RFC 5424 levels (debug, info, notice, warning, error, critical, alert, emergency) are present for basic filtering purposes, but for sorting and other use cases that would require flexibility, you should add Processors to the Logger that can add extra information (tags, user ip, ..) to the records before they are handled.

Log Levels

Monolog supports the logging levels described by RFC 5424.

  • DEBUG (100): Detailed debug information.

  • INFO (200): Interesting events. Examples: User logs in, SQL logs.

  • NOTICE (250): Normal but significant events.

  • WARNING (300): Exceptional occurrences that are not errors. Examples: Use of deprecated APIs, poor use of an API, undesirable things that are not necessarily wrong.

  • ERROR (400): Runtime errors that do not require immediate action but should typically be logged and monitored.

  • CRITICAL (500): Critical conditions. Example: Application component unavailable, unexpected exception.

  • ALERT (550): Action must be taken immediately. Example: Entire website down, database unavailable, etc. This should trigger the SMS alerts and wake you up.

  • EMERGENCY (600): Emergency: system is unusable.

Configuring a logger

Here is a basic setup to log to a file and to firephp on the DEBUG level:

<?php

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\FirePHPHandler;

// Create the logger
$logger = new Logger('my_logger');
// Now add some handlers
$logger->pushHandler(new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG));
$logger->pushHandler(new FirePHPHandler());

// You can now use your logger
$logger->addInfo('My logger is now ready');

Let's explain it. The first step is to create the logger instance which will be used in your code. The argument is a channel name, which is useful when you use several loggers (see below for more details about it).

The logger itself does not know how to handle a record. It delegates it to some handlers. The code above registers two handlers in the stack to allow handling records in two different ways.

Note that the FirePHPHandler is called first as it is added on top of the stack. This allows you to temporarily add a logger with bubbling disabled if you want to override other configured loggers.

If you use Monolog standalone and are looking for an easy way to configure many handlers, the theorchard/monolog-cascade can help you build complex logging configs via PHP arrays, yaml or json configs.

Adding extra data in the records

Monolog provides two different ways to add extra informations along the simple textual message.

Using the logging context

The first way is the context, allowing to pass an array of data along the record:

<?php

$logger->addInfo('Adding a new user', array('username' => 'Seldaek'));

Simple handlers (like the StreamHandler for instance) will simply format the array to a string but richer handlers can take advantage of the context (FirePHP is able to display arrays in pretty way for instance).

Using processors

The second way is to add extra data for all records by using a processor. Processors can be any callable. They will get the record as parameter and must return it after having eventually changed the extra part of it. Let's write a processor adding some dummy data in the record:

<?php

$logger->pushProcessor(function ($record) {
    $record['extra']['dummy'] = 'Hello world!';

    return $record;
});

Monolog provides some built-in processors that can be used in your project. Look at the dedicated chapter for the list.

Tip: processors can also be registered on a specific handler instead of the logger to apply only for this handler.

Leveraging channels

Channels are a great way to identify to which part of the application a record is related. This is useful in big applications (and is leveraged by MonologBundle in Symfony2).

Picture two loggers sharing a handler that writes to a single log file. Channels would allow you to identify the logger that issued every record. You can easily grep through the log files filtering this or that channel.

<?php

use Monolog\Logger;
use Monolog\Handler\StreamHandler;
use Monolog\Handler\FirePHPHandler;

// Create some handlers
$stream = new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG);
$firephp = new FirePHPHandler();

// Create the main logger of the app
$logger = new Logger('my_logger');
$logger->pushHandler($stream);
$logger->pushHandler($firephp);

// Create a logger for the security-related stuff with a different channel
$securityLogger = new Logger('security');
$securityLogger->pushHandler($stream);
$securityLogger->pushHandler($firephp);

Customizing the log format

In Monolog it's easy to customize the format of the logs written into files, sockets, mails, databases and other handlers. Most of the handlers use the

$record['formatted']

value to be automatically put into the log device. This value depends on the formatter settings. You can choose between predefined formatter classes or write your own (e.g. a multiline text file for human-readable output).

To configure a predefined formatter class, just set it as the handler's field:

// the default date format is "Y-m-d H:i:s"
$dateFormat = "Y n j, g:i a";
// the default output format is "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n"
$output = "%datetime% > %level_name% > %message% %context% %extra%\n";
// finally, create a formatter
$formatter = new LineFormatter($output, $dateFormat);

// Create a handler
$stream = new StreamHandler(__DIR__.'/my_app.log', Logger::DEBUG);
$stream->setFormatter($formatter);
// bind it to a logger object
$securityLogger = new Logger('security');
$securityLogger->pushHandler($stream);

You may also reuse the same formatter between multiple handlers and share those handlers between multiple loggers.

Handlers, Formatters and Processors

Handlers, Formatters and Processors

Handlers

Log to files and syslog

  • StreamHandler: Logs records into any PHP stream, use this for log files.
  • RotatingFileHandler: Logs records to a file and creates one logfile per day. It will also delete files older than $maxFiles. You should use logrotate for high profile setups though, this is just meant as a quick and dirty solution.
  • SyslogHandler: Logs records to the syslog.
  • ErrorLogHandler: Logs records to PHP's error_log() function.

Send alerts and emails

  • NativeMailerHandler: Sends emails using PHP's mail() function.
  • SwiftMailerHandler: Sends emails using a Swift_Mailer instance.
  • PushoverHandler: Sends mobile notifications via the Pushover API.
  • HipChatHandler: Logs records to a HipChat chat room using its API.
  • FlowdockHandler: Logs records to a Flowdock account.
  • SlackHandler: Logs records to a Slack account.
  • MandrillHandler: Sends emails via the Mandrill API using a Swift_Message instance.
  • FleepHookHandler: Logs records to a Fleep conversation using Webhooks.
  • IFTTTHandler: Notifies an IFTTT trigger with the log channel, level name and message.

Log specific servers and networked logging

  • SocketHandler: Logs records to sockets, use this for UNIX and TCP sockets. See an example.
  • AmqpHandler: Logs records to an amqp compatible server. Requires the php-amqp extension (1.0+).
  • GelfHandler: Logs records to a Graylog2 server.
  • CubeHandler: Logs records to a Cube server.
  • RavenHandler: Logs records to a Sentry server using raven.
  • ZendMonitorHandler: Logs records to the Zend Monitor present in Zend Server.
  • NewRelicHandler: Logs records to a NewRelic application.
  • LogglyHandler: Logs records to a Loggly account.
  • RollbarHandler: Logs records to a Rollbar account.
  • SyslogUdpHandler: Logs records to a remote Syslogd server.
  • LogEntriesHandler: Logs records to a LogEntries account.

Logging in development

  • FirePHPHandler: Handler for FirePHP, providing inline console messages within FireBug.
  • ChromePHPHandler: Handler for ChromePHP, providing inline console messages within Chrome.
  • BrowserConsoleHandler: Handler to send logs to browser's Javascript console with no browser extension required. Most browsers supporting console API are supported.
  • PHPConsoleHandler: Handler for PHP Console, providing inline console and notification popup messages within Chrome.

Log to databases

  • RedisHandler: Logs records to a redis server.
  • MongoDBHandler: Handler to write records in MongoDB via a Mongo extension connection.
  • CouchDBHandler: Logs records to a CouchDB server.
  • DoctrineCouchDBHandler: Logs records to a CouchDB server via the Doctrine CouchDB ODM.
  • ElasticSearchHandler: Logs records to an Elastic Search server.
  • DynamoDbHandler: Logs records to a DynamoDB table with the AWS SDK.

Wrappers / Special Handlers

  • FingersCrossedHandler: A very interesting wrapper. It takes a logger as parameter and will accumulate log records of all levels until a record exceeds the defined severity level. At which point it delivers all records, including those of lower severity, to the handler it wraps. This means that until an error actually happens you will not see anything in your logs, but when it happens you will have the full information, including debug and info records. This provides you with all the information you need, but only when you need it.
  • WhatFailureGroupHandler: This handler extends the GroupHandler ignoring exceptions raised by each child handler. This allows you to ignore issues where a remote tcp connection may have died but you do not want your entire application to crash and may wish to continue to log to other handlers.
  • BufferHandler: This handler will buffer all the log records it receives until close() is called at which point it will call handleBatch() on the handler it wraps with all the log messages at once. This is very useful to send an email with all records at once for example instead of having one mail for every log record.
  • GroupHandler: This handler groups other handlers. Every record received is sent to all the handlers it is configured with.
  • FilterHandler: This handler only lets records of the given levels through to the wrapped handler.
  • SamplingHandler: Wraps around another handler and lets you sample records if you only want to store some of them.
  • NullHandler: Any record it can handle will be thrown away. This can be used to put on top of an existing handler stack to disable it temporarily.
  • PsrHandler: Can be used to forward log records to an existing PSR-3 logger
  • TestHandler: Used for testing, it records everything that is sent to it and has accessors to read out the information.

Formatters

  • LineFormatter: Formats a log record into a one-line string.
  • HtmlFormatter: Used to format log records into a human readable html table, mainly suitable for emails.
  • NormalizerFormatter: Normalizes objects/resources down to strings so a record can easily be serialized/encoded.
  • ScalarFormatter: Used to format log records into an associative array of scalar values.
  • JsonFormatter: Encodes a log record into json.
  • WildfireFormatter: Used to format log records into the Wildfire/FirePHP protocol, only useful for the FirePHPHandler.
  • ChromePHPFormatter: Used to format log records into the ChromePHP format, only useful for the ChromePHPHandler.
  • GelfMessageFormatter: Used to format log records into Gelf message instances, only useful for the GelfHandler.
  • LogstashFormatter: Used to format log records into logstash event json, useful for any handler listed under inputs here.
  • ElasticaFormatter: Used to format log records into an Elastica\Document object, only useful for the ElasticSearchHandler.
  • LogglyFormatter: Used to format log records into Loggly messages, only useful for the LogglyHandler.
  • FlowdockFormatter: Used to format log records into Flowdock messages, only useful for the FlowdockHandler.
  • MongoDBFormatter: Converts \DateTime instances to \MongoDate and objects recursively to arrays, only useful with the MongoDBHandler.

Processors

  • IntrospectionProcessor: Adds the line/file/class/method from which the log call originated.
  • WebProcessor: Adds the current request URI, request method and client IP to a log record.
  • MemoryUsageProcessor: Adds the current memory usage to a log record.
  • MemoryPeakUsageProcessor: Adds the peak memory usage to a log record.
  • ProcessIdProcessor: Adds the process id to a log record.
  • UidProcessor: Adds a unique identifier to a log record.
  • GitProcessor: Adds the current git branch and commit to a log record.
  • TagProcessor: Adds an array of predefined tags to a log record.

Third Party Packages

Third party handlers, formatters and processors are listed in the wiki. You can also add your own there if you publish one.

Usage | Utility classes

Utilities

  • Registry: The Monolog\Registry class lets you configure global loggers that you can then statically access from anywhere. It is not really a best practice but can help in some older codebases or for ease of use.
  • ErrorHandler: The Monolog\ErrorHandler class allows you to easily register a Logger instance as an exception handler, error handler or fatal error handler.
  • ErrorLevelActivationStrategy: Activates a FingersCrossedHandler when a certain log level is reached.
  • ChannelLevelActivationStrategy: Activates a FingersCrossedHandler when a certain log level is reached, depending on which channel received the log record.

Handlers, Formatters and Processors | Extending Monolog

Extending Monolog

Monolog is fully extensible, allowing you to adapt your logger to your needs.

Writing your own handler

Monolog provides many built-in handlers. But if the one you need does not exist, you can write it and use it in your logger. The only requirement is to implement Monolog\Handler\HandlerInterface.

Let's write a PDOHandler to log records to a database. We will extend the abstract class provided by Monolog to keep things DRY.

<?php

use Monolog\Logger;
use Monolog\Handler\AbstractProcessingHandler;

class PDOHandler extends AbstractProcessingHandler
{
    private $initialized = false;
    private $pdo;
    private $statement;

    public function __construct(PDO $pdo, $level = Logger::DEBUG, $bubble = true)
    {
        $this->pdo = $pdo;
        parent::__construct($level, $bubble);
    }

    protected function write(array $record)
    {
        if (!$this->initialized) {
            $this->initialize();
        }

        $this->statement->execute(array(
            'channel' => $record['channel'],
            'level' => $record['level'],
            'message' => $record['formatted'],
            'time' => $record['datetime']->format('U'),
        ));
    }

    private function initialize()
    {
        $this->pdo->exec(
            'CREATE TABLE IF NOT EXISTS monolog '
            .'(channel VARCHAR(255), level INTEGER, message LONGTEXT, time INTEGER UNSIGNED)'
        );
        $this->statement = $this->pdo->prepare(
            'INSERT INTO monolog (channel, level, message, time) VALUES (:channel, :level, :message, :time)'
        );

        $this->initialized = true;
    }
}

You can now use this handler in your logger:

<?php

$logger->pushHandler(new PDOHandler(new PDO('sqlite:logs.sqlite')));

// You can now use your logger
$logger->addInfo('My logger is now ready');

The Monolog\Handler\AbstractProcessingHandler class provides most of the logic needed for the handler, including the use of processors and the formatting of the record (which is why we use $record['formatted'] instead of $record['message']).

Utility classes

Sockets Handler

This handler allows you to write your logs to sockets using fsockopen or pfsockopen.

Persistent sockets are mainly useful in web environments where you gain some performance not closing/opening the connections between requests.

You can use a unix:// prefix to access unix sockets and udp:// to open UDP sockets instead of the default TCP.

Basic Example

<?php

use Monolog\Logger;
use Monolog\Handler\SocketHandler;

// Create the logger
$logger = new Logger('my_logger');

// Create the handler
$handler = new SocketHandler('unix:///var/log/httpd_app_log.socket');
$handler->setPersistent(true);

// Now add the handler
$logger->pushHandler($handler, Logger::DEBUG);

// You can now use your logger
$logger->addInfo('My logger is now ready');

In this example, using syslog-ng, you should see the log on the log server:

cweb1 [2012-02-26 00:12:03] my_logger.INFO: My logger is now ready [] []
Copyright (c) 2011-2015 Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
<?xml version="1.0" encoding="UTF-8"?>
<phpunit bootstrap="vendor/autoload.php" colors="true">
<testsuites>
<testsuite name="Monolog Test Suite">
<directory>tests/Monolog/</directory>
</testsuite>
</testsuites>
<filter>
<whitelist>
<directory suffix=".php">src/Monolog/</directory>
</whitelist>
</filter>
<php>
<ini name="date.timezone" value="UTC"/>
</php>
</phpunit>

Monolog - Logging for PHP Build Status

Total Downloads Latest Stable Version Reference Status

Monolog sends your logs to files, sockets, inboxes, databases and various web services. See the complete list of handlers below. Special handlers allow you to build advanced logging strategies.

This library implements the PSR-3 interface that you can type-hint against in your own libraries to keep a maximum of interoperability. You can also use it in your applications to make sure you can always use another compatible logger at a later time. As of 1.11.0 Monolog public APIs will also accept PSR-3 log levels. Internally Monolog still uses its own level scheme since it predates PSR-3.

Installation

Install the latest version with

$ composer require monolog/monolog

Basic Usage

<?php

use Monolog\Logger;
use Monolog\Handler\StreamHandler;

// create a log channel
$log = new Logger('name');
$log->pushHandler(new StreamHandler('path/to/your.log', Logger::WARNING));

// add records to the log
$log->addWarning('Foo');
$log->addError('Bar');

Documentation

Third Party Packages

Third party handlers, formatters and processors are listed in the wiki. You can also add your own there if you publish one.

About

Requirements

  • Monolog works with PHP 5.3 or above, and is also tested to work with HHVM.

Submitting bugs and feature requests

Bugs and feature request are tracked on GitHub

Framework Integrations

Author

Jordi Boggiano - j.boggiano@seld.be - http://twitter.com/seldaek
See also the list of contributors which participated in this project.

License

Monolog is licensed under the MIT License - see the LICENSE file for details

Acknowledgements

This library is heavily inspired by Python's Logbook library, although most concepts have been adjusted to fit to the PHP world.

<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog;
use Psr\Log\LoggerInterface;
use Psr\Log\LogLevel;
use Monolog\Handler\AbstractHandler;
/**
* Monolog error handler
*
* A facility to enable logging of runtime errors, exceptions and fatal errors.
*
* Quick setup: <code>ErrorHandler::register($logger);</code>
*
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class ErrorHandler
{
private $logger;
private $previousExceptionHandler;
private $uncaughtExceptionLevel;
private $previousErrorHandler;
private $errorLevelMap;
private $hasFatalErrorHandler;
private $fatalLevel;
private $reservedMemory;
private static $fatalErrors = array(E_ERROR, E_PARSE, E_CORE_ERROR, E_COMPILE_ERROR, E_USER_ERROR);
public function __construct(LoggerInterface $logger)
{
$this->logger = $logger;
}
/**
* Registers a new ErrorHandler for a given Logger
*
* By default it will handle errors, exceptions and fatal errors
*
* @param LoggerInterface $logger
* @param array|false $errorLevelMap an array of E_* constant to LogLevel::* constant mapping, or false to disable error handling
* @param int|false $exceptionLevel a LogLevel::* constant, or false to disable exception handling
* @param int|false $fatalLevel a LogLevel::* constant, or false to disable fatal error handling
* @return ErrorHandler
*/
public static function register(LoggerInterface $logger, $errorLevelMap = array(), $exceptionLevel = null, $fatalLevel = null)
{
$handler = new static($logger);
if ($errorLevelMap !== false) {
$handler->registerErrorHandler($errorLevelMap);
}
if ($exceptionLevel !== false) {
$handler->registerExceptionHandler($exceptionLevel);
}
if ($fatalLevel !== false) {
$handler->registerFatalHandler($fatalLevel);
}
return $handler;
}
public function registerExceptionHandler($level = null, $callPrevious = true)
{
$prev = set_exception_handler(array($this, 'handleException'));
$this->uncaughtExceptionLevel = $level;
if ($callPrevious && $prev) {
$this->previousExceptionHandler = $prev;
}
}
public function registerErrorHandler(array $levelMap = array(), $callPrevious = true, $errorTypes = -1)
{
$prev = set_error_handler(array($this, 'handleError'), $errorTypes);
$this->errorLevelMap = array_replace($this->defaultErrorLevelMap(), $levelMap);
if ($callPrevious) {
$this->previousErrorHandler = $prev ?: true;
}
}
public function registerFatalHandler($level = null, $reservedMemorySize = 20)
{
register_shutdown_function(array($this, 'handleFatalError'));
$this->reservedMemory = str_repeat(' ', 1024 * $reservedMemorySize);
$this->fatalLevel = $level;
$this->hasFatalErrorHandler = true;
}
protected function defaultErrorLevelMap()
{
return array(
E_ERROR => LogLevel::CRITICAL,
E_WARNING => LogLevel::WARNING,
E_PARSE => LogLevel::ALERT,
E_NOTICE => LogLevel::NOTICE,
E_CORE_ERROR => LogLevel::CRITICAL,
E_CORE_WARNING => LogLevel::WARNING,
E_COMPILE_ERROR => LogLevel::ALERT,
E_COMPILE_WARNING => LogLevel::WARNING,
E_USER_ERROR => LogLevel::ERROR,
E_USER_WARNING => LogLevel::WARNING,
E_USER_NOTICE => LogLevel::NOTICE,
E_STRICT => LogLevel::NOTICE,
E_RECOVERABLE_ERROR => LogLevel::ERROR,
E_DEPRECATED => LogLevel::NOTICE,
E_USER_DEPRECATED => LogLevel::NOTICE,
);
}
/**
* @private
*/
public function handleException($e)
{
$this->logger->log(
$this->uncaughtExceptionLevel === null ? LogLevel::ERROR : $this->uncaughtExceptionLevel,
sprintf('Uncaught Exception %s: "%s" at %s line %s', get_class($e), $e->getMessage(), $e->getFile(), $e->getLine()),
array('exception' => $e)
);
if ($this->previousExceptionHandler) {
call_user_func($this->previousExceptionHandler, $e);
}
exit(255);
}
/**
* @private
*/
public function handleError($code, $message, $file = '', $line = 0, $context = array())
{
if (!(error_reporting() & $code)) {
return;
}
// fatal error codes are ignored if a fatal error handler is present as well to avoid duplicate log entries
if (!$this->hasFatalErrorHandler || !in_array($code, self::$fatalErrors, true)) {
$level = isset($this->errorLevelMap[$code]) ? $this->errorLevelMap[$code] : LogLevel::CRITICAL;
$this->logger->log($level, self::codeToString($code).': '.$message, array('code' => $code, 'message' => $message, 'file' => $file, 'line' => $line));
}
if ($this->previousErrorHandler === true) {
return false;
} elseif ($this->previousErrorHandler) {
return call_user_func($this->previousErrorHandler, $code, $message, $file, $line, $context);
}
}
/**
* @private
*/
public function handleFatalError()
{
$this->reservedMemory = null;
$lastError = error_get_last();
if ($lastError && in_array($lastError['type'], self::$fatalErrors, true)) {
$this->logger->log(
$this->fatalLevel === null ? LogLevel::ALERT : $this->fatalLevel,
'Fatal Error ('.self::codeToString($lastError['type']).'): '.$lastError['message'],
array('code' => $lastError['type'], 'message' => $lastError['message'], 'file' => $lastError['file'], 'line' => $lastError['line'])
);
if ($this->logger instanceof Logger) {
foreach ($this->logger->getHandlers() as $handler) {
if ($handler instanceof AbstractHandler) {
$handler->close();
}
}
}
}
}
private static function codeToString($code)
{
switch ($code) {
case E_ERROR:
return 'E_ERROR';
case E_WARNING:
return 'E_WARNING';
case E_PARSE:
return 'E_PARSE';
case E_NOTICE:
return 'E_NOTICE';
case E_CORE_ERROR:
return 'E_CORE_ERROR';
case E_CORE_WARNING:
return 'E_CORE_WARNING';
case E_COMPILE_ERROR:
return 'E_COMPILE_ERROR';
case E_COMPILE_WARNING:
return 'E_COMPILE_WARNING';
case E_USER_ERROR:
return 'E_USER_ERROR';
case E_USER_WARNING:
return 'E_USER_WARNING';
case E_USER_NOTICE:
return 'E_USER_NOTICE';
case E_STRICT:
return 'E_STRICT';
case E_RECOVERABLE_ERROR:
return 'E_RECOVERABLE_ERROR';
case E_DEPRECATED:
return 'E_DEPRECATED';
case E_USER_DEPRECATED:
return 'E_USER_DEPRECATED';
}
return 'Unknown PHP error';
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Formatter;
use Monolog\Logger;
/**
* Formats a log message according to the ChromePHP array format
*
* @author Christophe Coevoet <stof@notk.org>
*/
class ChromePHPFormatter implements FormatterInterface
{
/**
* Translates Monolog log levels to Wildfire levels.
*/
private $logLevels = array(
Logger::DEBUG => 'log',
Logger::INFO => 'info',
Logger::NOTICE => 'info',
Logger::WARNING => 'warn',
Logger::ERROR => 'error',
Logger::CRITICAL => 'error',
Logger::ALERT => 'error',
Logger::EMERGENCY => 'error',
);
/**
* {@inheritdoc}
*/
public function format(array $record)
{
// Retrieve the line and file if set and remove them from the formatted extra
$backtrace = 'unknown';
if (isset($record['extra']['file']) && isset($record['extra']['line'])) {
$backtrace = $record['extra']['file'].' : '.$record['extra']['line'];
unset($record['extra']['file']);
unset($record['extra']['line']);
}
$message = array('message' => $record['message']);
if ($record['context']) {
$message['context'] = $record['context'];
}
if ($record['extra']) {
$message['extra'] = $record['extra'];
}
if (count($message) === 1) {
$message = reset($message);
}
return array(
$record['channel'],
$message,
$backtrace,
$this->logLevels[$record['level']],
);
}
public function formatBatch(array $records)
{
$formatted = array();
foreach ($records as $record) {
$formatted[] = $this->format($record);
}
return $formatted;
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Formatter;
use Elastica\Document;
/**
* Format a log message into an Elastica Document
*
* @author Jelle Vink <jelle.vink@gmail.com>
*/
class ElasticaFormatter extends NormalizerFormatter
{
/**
* @var string Elastic search index name
*/
protected $index;
/**
* @var string Elastic search document type
*/
protected $type;
/**
* @param string $index Elastic Search index name
* @param string $type Elastic Search document type
*/
public function __construct($index, $type)
{
parent::__construct(\DateTime::ISO8601);
$this->index = $index;
$this->type = $type;
}
/**
* {@inheritdoc}
*/
public function format(array $record)
{
$record = parent::format($record);
return $this->getDocument($record);
}
/**
* Getter index
* @return string
*/
public function getIndex()
{
return $this->index;
}
/**
* Getter type
* @return string
*/
public function getType()
{
return $this->type;
}
/**
* Convert a log message into an Elastica Document
*
* @param array $record Log message
* @return Document
*/
protected function getDocument($record)
{
$document = new Document();
$document->setData($record);
$document->setType($this->type);
$document->setIndex($this->index);
return $document;
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Formatter;
/**
* formats the record to be used in the FlowdockHandler
*
* @author Dominik Liebler <liebler.dominik@gmail.com>
*/
class FlowdockFormatter implements FormatterInterface
{
/**
* @var string
*/
private $source;
/**
* @var string
*/
private $sourceEmail;
/**
* @param string $source
* @param string $sourceEmail
*/
public function __construct($source, $sourceEmail)
{
$this->source = $source;
$this->sourceEmail = $sourceEmail;
}
/**
* {@inheritdoc}
*/
public function format(array $record)
{
$tags = array(
'#logs',
'#' . strtolower($record['level_name']),
'#' . $record['channel'],
);
foreach ($record['extra'] as $value) {
$tags[] = '#' . $value;
}
$subject = sprintf(
'in %s: %s - %s',
$this->source,
$record['level_name'],
$this->getShortMessage($record['message'])
);
$record['flowdock'] = array(
'source' => $this->source,
'from_address' => $this->sourceEmail,
'subject' => $subject,
'content' => $record['message'],
'tags' => $tags,
'project' => $this->source,
);
return $record;
}
/**
* {@inheritdoc}
*/
public function formatBatch(array $records)
{
$formatted = array();
foreach ($records as $record) {
$formatted[] = $this->format($record);
}
return $formatted;
}
/**
* @param string $message
*
* @return string
*/
public function getShortMessage($message)
{
static $hasMbString;
if (null === $hasMbString) {
$hasMbString = function_exists('mb_strlen');
}
$maxLength = 45;
if ($hasMbString) {
if (mb_strlen($message, 'UTF-8') > $maxLength) {
$message = mb_substr($message, 0, $maxLength - 4, 'UTF-8') . ' ...';
}
} else {
if (strlen($message) > $maxLength) {
$message = substr($message, 0, $maxLength - 4) . ' ...';
}
}
return $message;
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Formatter;
/**
* Interface for formatters
*
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
interface FormatterInterface
{
/**
* Formats a log record.
*
* @param array $record A record to format
* @return mixed The formatted record
*/
public function format(array $record);
/**
* Formats a set of log records.
*
* @param array $records A set of records to format
* @return mixed The formatted set of records
*/
public function formatBatch(array $records);
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Formatter;
use Monolog\Logger;
use Gelf\Message;
/**
* Serializes a log message to GELF
* @see http://www.graylog2.org/about/gelf
*
* @author Matt Lehner <mlehner@gmail.com>
*/
class GelfMessageFormatter extends NormalizerFormatter
{
/**
* @var string the name of the system for the Gelf log message
*/
protected $systemName;
/**
* @var string a prefix for 'extra' fields from the Monolog record (optional)
*/
protected $extraPrefix;
/**
* @var string a prefix for 'context' fields from the Monolog record (optional)
*/
protected $contextPrefix;
/**
* Translates Monolog log levels to Graylog2 log priorities.
*/
private $logLevels = array(
Logger::DEBUG => 7,
Logger::INFO => 6,
Logger::NOTICE => 5,
Logger::WARNING => 4,
Logger::ERROR => 3,
Logger::CRITICAL => 2,
Logger::ALERT => 1,
Logger::EMERGENCY => 0,
);
public function __construct($systemName = null, $extraPrefix = null, $contextPrefix = 'ctxt_')
{
parent::__construct('U.u');
$this->systemName = $systemName ?: gethostname();
$this->extraPrefix = $extraPrefix;
$this->contextPrefix = $contextPrefix;
}
/**
* {@inheritdoc}
*/
public function format(array $record)
{
$record = parent::format($record);
if (!isset($record['datetime'], $record['message'], $record['level'])) {
throw new \InvalidArgumentException('The record should at least contain datetime, message and level keys, '.var_export($record, true).' given');
}
$message = new Message();
$message
->setTimestamp($record['datetime'])
->setShortMessage((string) $record['message'])
->setHost($this->systemName)
->setLevel($this->logLevels[$record['level']]);
if (isset($record['channel'])) {
$message->setFacility($record['channel']);
}
if (isset($record['extra']['line'])) {
$message->setLine($record['extra']['line']);
unset($record['extra']['line']);
}
if (isset($record['extra']['file'])) {
$message->setFile($record['extra']['file']);
unset($record['extra']['file']);
}
foreach ($record['extra'] as $key => $val) {
$message->setAdditional($this->extraPrefix . $key, is_scalar($val) ? $val : $this->toJson($val));
}
foreach ($record['context'] as $key => $val) {
$message->setAdditional($this->contextPrefix . $key, is_scalar($val) ? $val : $this->toJson($val));
}
if (null === $message->getFile() && isset($record['context']['exception']['file'])) {
if (preg_match("/^(.+):([0-9]+)$/", $record['context']['exception']['file'], $matches)) {
$message->setFile($matches[1]);
$message->setLine($matches[2]);
}
}
return $message;
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Formatter;
use Monolog\Logger;
/**
* Formats incoming records into an HTML table
*
* This is especially useful for html email logging
*
* @author Tiago Brito <tlfbrito@gmail.com>
*/
class HtmlFormatter extends NormalizerFormatter
{
/**
* Translates Monolog log levels to html color priorities.
*/
private $logLevels = array(
Logger::DEBUG => '#cccccc',
Logger::INFO => '#468847',
Logger::NOTICE => '#3a87ad',
Logger::WARNING => '#c09853',
Logger::ERROR => '#f0ad4e',
Logger::CRITICAL => '#FF7708',
Logger::ALERT => '#C12A19',
Logger::EMERGENCY => '#000000',
);
/**
* @param string $dateFormat The format of the timestamp: one supported by DateTime::format
*/
public function __construct($dateFormat = null)
{
parent::__construct($dateFormat);
}
/**
* Creates an HTML table row
*
* @param string $th Row header content
* @param string $td Row standard cell content
* @param bool $escapeTd false if td content must not be html escaped
* @return string
*/
private function addRow($th, $td = ' ', $escapeTd = true)
{
$th = htmlspecialchars($th, ENT_NOQUOTES, 'UTF-8');
if ($escapeTd) {
$td = '<pre>'.htmlspecialchars($td, ENT_NOQUOTES, 'UTF-8').'</pre>';
}
return "<tr style=\"padding: 4px;spacing: 0;text-align: left;\">\n<th style=\"background: #cccccc\" width=\"100px\">$th:</th>\n<td style=\"padding: 4px;spacing: 0;text-align: left;background: #eeeeee\">".$td."</td>\n</tr>";
}
/**
* Create a HTML h1 tag
*
* @param string $title Text to be in the h1
* @param integer $level Error level
* @return string
*/
private function addTitle($title, $level)
{
$title = htmlspecialchars($title, ENT_NOQUOTES, 'UTF-8');
return '<h1 style="background: '.$this->logLevels[$level].';color: #ffffff;padding: 5px;" class="monolog-output">'.$title.'</h1>';
}
/**
* Formats a log record.
*
* @param array $record A record to format
* @return mixed The formatted record
*/
public function format(array $record)
{
$output = $this->addTitle($record['level_name'], $record['level']);
$output .= '<table cellspacing="1" width="100%" class="monolog-output">';
$output .= $this->addRow('Message', (string) $record['message']);
$output .= $this->addRow('Time', $record['datetime']->format($this->dateFormat));
$output .= $this->addRow('Channel', $record['channel']);
if ($record['context']) {
$embeddedTable = '<table cellspacing="1" width="100%">';
foreach ($record['context'] as $key => $value) {
$embeddedTable .= $this->addRow($key, $this->convertToString($value));
}
$embeddedTable .= '</table>';
$output .= $this->addRow('Context', $embeddedTable, false);
}
if ($record['extra']) {
$embeddedTable = '<table cellspacing="1" width="100%">';
foreach ($record['extra'] as $key => $value) {
$embeddedTable .= $this->addRow($key, $this->convertToString($value));
}
$embeddedTable .= '</table>';
$output .= $this->addRow('Extra', $embeddedTable, false);
}
return $output.'</table>';
}
/**
* Formats a set of log records.
*
* @param array $records A set of records to format
* @return mixed The formatted set of records
*/
public function formatBatch(array $records)
{
$message = '';
foreach ($records as $record) {
$message .= $this->format($record);
}
return $message;
}
protected function convertToString($data)
{
if (null === $data || is_scalar($data)) {
return (string) $data;
}
$data = $this->normalize($data);
if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
return json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
}
return str_replace('\\/', '/', json_encode($data));
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Formatter;
/**
* Encodes whatever record data is passed to it as json
*
* This can be useful to log to databases or remote APIs
*
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class JsonFormatter implements FormatterInterface
{
const BATCH_MODE_JSON = 1;
const BATCH_MODE_NEWLINES = 2;
protected $batchMode;
protected $appendNewline;
/**
* @param int $batchMode
*/
public function __construct($batchMode = self::BATCH_MODE_JSON, $appendNewline = true)
{
$this->batchMode = $batchMode;
$this->appendNewline = $appendNewline;
}
/**
* The batch mode option configures the formatting style for
* multiple records. By default, multiple records will be
* formatted as a JSON-encoded array. However, for
* compatibility with some API endpoints, alternative styles
* are available.
*
* @return int
*/
public function getBatchMode()
{
return $this->batchMode;
}
/**
* True if newlines are appended to every formatted record
*
* @return bool
*/
public function isAppendingNewlines()
{
return $this->appendNewline;
}
/**
* {@inheritdoc}
*/
public function format(array $record)
{
return json_encode($record) . ($this->appendNewline ? "\n" : '');
}
/**
* {@inheritdoc}
*/
public function formatBatch(array $records)
{
switch ($this->batchMode) {
case static::BATCH_MODE_NEWLINES:
return $this->formatBatchNewlines($records);
case static::BATCH_MODE_JSON:
default:
return $this->formatBatchJson($records);
}
}
/**
* Return a JSON-encoded array of records.
*
* @param array $records
* @return string
*/
protected function formatBatchJson(array $records)
{
return json_encode($records);
}
/**
* Use new lines to separate records instead of a
* JSON-encoded array.
*
* @param array $records
* @return string
*/
protected function formatBatchNewlines(array $records)
{
$instance = $this;
$oldNewline = $this->appendNewline;
$this->appendNewline = false;
array_walk($records, function (&$value, $key) use ($instance) {
$value = $instance->format($value);
});
$this->appendNewline = $oldNewline;
return implode("\n", $records);
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Formatter;
use Exception;
/**
* Formats incoming records into a one-line string
*
* This is especially useful for logging to files
*
* @author Jordi Boggiano <j.boggiano@seld.be>
* @author Christophe Coevoet <stof@notk.org>
*/
class LineFormatter extends NormalizerFormatter
{
const SIMPLE_FORMAT = "[%datetime%] %channel%.%level_name%: %message% %context% %extra%\n";
protected $format;
protected $allowInlineLineBreaks;
protected $ignoreEmptyContextAndExtra;
protected $includeStacktraces;
/**
* @param string $format The format of the message
* @param string $dateFormat The format of the timestamp: one supported by DateTime::format
* @param bool $allowInlineLineBreaks Whether to allow inline line breaks in log entries
* @param bool $ignoreEmptyContextAndExtra
*/
public function __construct($format = null, $dateFormat = null, $allowInlineLineBreaks = false, $ignoreEmptyContextAndExtra = false)
{
$this->format = $format ?: static::SIMPLE_FORMAT;
$this->allowInlineLineBreaks = $allowInlineLineBreaks;
$this->ignoreEmptyContextAndExtra = $ignoreEmptyContextAndExtra;
parent::__construct($dateFormat);
}
public function includeStacktraces($include = true)
{
$this->includeStacktraces = $include;
if ($this->includeStacktraces) {
$this->allowInlineLineBreaks = true;
}
}
public function allowInlineLineBreaks($allow = true)
{
$this->allowInlineLineBreaks = $allow;
}
public function ignoreEmptyContextAndExtra($ignore = true)
{
$this->ignoreEmptyContextAndExtra = $ignore;
}
/**
* {@inheritdoc}
*/
public function format(array $record)
{
$vars = parent::format($record);
$output = $this->format;
foreach ($vars['extra'] as $var => $val) {
if (false !== strpos($output, '%extra.'.$var.'%')) {
$output = str_replace('%extra.'.$var.'%', $this->stringify($val), $output);
unset($vars['extra'][$var]);
}
}
if ($this->ignoreEmptyContextAndExtra) {
if (empty($vars['context'])) {
unset($vars['context']);
$output = str_replace('%context%', '', $output);
}
if (empty($vars['extra'])) {
unset($vars['extra']);
$output = str_replace('%extra%', '', $output);
}
}
foreach ($vars as $var => $val) {
if (false !== strpos($output, '%'.$var.'%')) {
$output = str_replace('%'.$var.'%', $this->stringify($val), $output);
}
}
return $output;
}
public function formatBatch(array $records)
{
$message = '';
foreach ($records as $record) {
$message .= $this->format($record);
}
return $message;
}
public function stringify($value)
{
return $this->replaceNewlines($this->convertToString($value));
}
protected function normalizeException(Exception $e)
{
$previousText = '';
if ($previous = $e->getPrevious()) {
do {
$previousText .= ', '.get_class($previous).'(code: '.$previous->getCode().'): '.$previous->getMessage().' at '.$previous->getFile().':'.$previous->getLine();
} while ($previous = $previous->getPrevious());
}
$str = '[object] ('.get_class($e).'(code: '.$e->getCode().'): '.$e->getMessage().' at '.$e->getFile().':'.$e->getLine().$previousText.')';
if ($this->includeStacktraces) {
$str .= "\n[stacktrace]\n".$e->getTraceAsString();
}
return $str;
}
protected function convertToString($data)
{
if (null === $data || is_bool($data)) {
return var_export($data, true);
}
if (is_scalar($data)) {
return (string) $data;
}
if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
return $this->toJson($data, true);
}
return str_replace('\\/', '/', @json_encode($data));
}
protected function replaceNewlines($str)
{
if ($this->allowInlineLineBreaks) {
return $str;
}
return str_replace(array("\r\n", "\r", "\n"), ' ', $str);
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Formatter;
/**
* Encodes message information into JSON in a format compatible with Loggly.
*
* @author Adam Pancutt <adam@pancutt.com>
*/
class LogglyFormatter extends JsonFormatter
{
/**
* Overrides the default batch mode to new lines for compatibility with the
* Loggly bulk API.
*
* @param integer $batchMode
*/
public function __construct($batchMode = self::BATCH_MODE_NEWLINES, $appendNewline = false)
{
parent::__construct($batchMode, $appendNewline);
}
/**
* Appends the 'timestamp' parameter for indexing by Loggly.
*
* @see https://www.loggly.com/docs/automated-parsing/#json
* @see \Monolog\Formatter\JsonFormatter::format()
*/
public function format(array $record)
{
if (isset($record["datetime"]) && ($record["datetime"] instanceof \DateTime)) {
$record["timestamp"] = $record["datetime"]->format("Y-m-d\TH:i:s.uO");
// TODO 2.0 unset the 'datetime' parameter, retained for BC
}
return parent::format($record);
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Formatter;
/**
* Serializes a log message to Logstash Event Format
*
* @see http://logstash.net/
* @see https://github.com/logstash/logstash/blob/master/lib/logstash/event.rb
*
* @author Tim Mower <timothy.mower@gmail.com>
*/
class LogstashFormatter extends NormalizerFormatter
{
const V0 = 0;
const V1 = 1;
/**
* @var string the name of the system for the Logstash log message, used to fill the @source field
*/
protected $systemName;
/**
* @var string an application name for the Logstash log message, used to fill the @type field
*/
protected $applicationName;
/**
* @var string a prefix for 'extra' fields from the Monolog record (optional)
*/
protected $extraPrefix;
/**
* @var string a prefix for 'context' fields from the Monolog record (optional)
*/
protected $contextPrefix;
/**
* @var integer logstash format version to use
*/
protected $version;
/**
* @param string $applicationName the application that sends the data, used as the "type" field of logstash
* @param string $systemName the system/machine name, used as the "source" field of logstash, defaults to the hostname of the machine
* @param string $extraPrefix prefix for extra keys inside logstash "fields"
* @param string $contextPrefix prefix for context keys inside logstash "fields", defaults to ctxt_
* @param integer $version the logstash format version to use, defaults to 0
*/
public function __construct($applicationName, $systemName = null, $extraPrefix = null, $contextPrefix = 'ctxt_', $version = self::V0)
{
// logstash requires a ISO 8601 format date with optional millisecond precision.
parent::__construct('Y-m-d\TH:i:s.uP');
$this->systemName = $systemName ?: gethostname();
$this->applicationName = $applicationName;
$this->extraPrefix = $extraPrefix;
$this->contextPrefix = $contextPrefix;
$this->version = $version;
}
/**
* {@inheritdoc}
*/
public function format(array $record)
{
$record = parent::format($record);
if ($this->version === self::V1) {
$message = $this->formatV1($record);
} else {
$message = $this->formatV0($record);
}
return $this->toJson($message) . "\n";
}
protected function formatV0(array $record)
{
if (empty($record['datetime'])) {
$record['datetime'] = gmdate('c');
}
$message = array(
'@timestamp' => $record['datetime'],
'@source' => $this->systemName,
'@fields' => array()
);
if (isset($record['message'])) {
$message['@message'] = $record['message'];
}
if (isset($record['channel'])) {
$message['@tags'] = array($record['channel']);
$message['@fields']['channel'] = $record['channel'];
}
if (isset($record['level'])) {
$message['@fields']['level'] = $record['level'];
}
if ($this->applicationName) {
$message['@type'] = $this->applicationName;
}
if (isset($record['extra']['server'])) {
$message['@source_host'] = $record['extra']['server'];
}
if (isset($record['extra']['url'])) {
$message['@source_path'] = $record['extra']['url'];
}
if (!empty($record['extra'])) {
foreach ($record['extra'] as $key => $val) {
$message['@fields'][$this->extraPrefix . $key] = $val;
}
}
if (!empty($record['context'])) {
foreach ($record['context'] as $key => $val) {
$message['@fields'][$this->contextPrefix . $key] = $val;
}
}
return $message;
}
protected function formatV1(array $record)
{
if (empty($record['datetime'])) {
$record['datetime'] = gmdate('c');
}
$message = array(
'@timestamp' => $record['datetime'],
'@version' => 1,
'host' => $this->systemName,
);
if (isset($record['message'])) {
$message['message'] = $record['message'];
}
if (isset($record['channel'])) {
$message['type'] = $record['channel'];
$message['channel'] = $record['channel'];
}
if (isset($record['level_name'])) {
$message['level'] = $record['level_name'];
}
if ($this->applicationName) {
$message['type'] = $this->applicationName;
}
if (!empty($record['extra'])) {
foreach ($record['extra'] as $key => $val) {
$message[$this->extraPrefix . $key] = $val;
}
}
if (!empty($record['context'])) {
foreach ($record['context'] as $key => $val) {
$message[$this->contextPrefix . $key] = $val;
}
}
return $message;
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Formatter;
/**
* Formats a record for use with the MongoDBHandler.
*
* @author Florian Plattner <me@florianplattner.de>
*/
class MongoDBFormatter implements FormatterInterface
{
private $exceptionTraceAsString;
private $maxNestingLevel;
/**
* @param int $maxNestingLevel 0 means infinite nesting, the $record itself is level 1, $record['context'] is 2
* @param bool $exceptionTraceAsString set to false to log exception traces as a sub documents instead of strings
*/
public function __construct($maxNestingLevel = 3, $exceptionTraceAsString = true)
{
$this->maxNestingLevel = max($maxNestingLevel, 0);
$this->exceptionTraceAsString = (bool) $exceptionTraceAsString;
}
/**
* {@inheritDoc}
*/
public function format(array $record)
{
return $this->formatArray($record);
}
/**
* {@inheritDoc}
*/
public function formatBatch(array $records)
{
foreach ($records as $key => $record) {
$records[$key] = $this->format($record);
}
return $records;
}
protected function formatArray(array $record, $nestingLevel = 0)
{
if ($this->maxNestingLevel == 0 || $nestingLevel <= $this->maxNestingLevel) {
foreach ($record as $name => $value) {
if ($value instanceof \DateTime) {
$record[$name] = $this->formatDate($value, $nestingLevel + 1);
} elseif ($value instanceof \Exception) {
$record[$name] = $this->formatException($value, $nestingLevel + 1);
} elseif (is_array($value)) {
$record[$name] = $this->formatArray($value, $nestingLevel + 1);
} elseif (is_object($value)) {
$record[$name] = $this->formatObject($value, $nestingLevel + 1);
}
}
} else {
$record = '[...]';
}
return $record;
}
protected function formatObject($value, $nestingLevel)
{
$objectVars = get_object_vars($value);
$objectVars['class'] = get_class($value);
return $this->formatArray($objectVars, $nestingLevel);
}
protected function formatException(\Exception $exception, $nestingLevel)
{
$formattedException = array(
'class' => get_class($exception),
'message' => $exception->getMessage(),
'code' => $exception->getCode(),
'file' => $exception->getFile() . ':' . $exception->getLine(),
);
if ($this->exceptionTraceAsString === true) {
$formattedException['trace'] = $exception->getTraceAsString();
} else {
$formattedException['trace'] = $exception->getTrace();
}
return $this->formatArray($formattedException, $nestingLevel);
}
protected function formatDate(\DateTime $value, $nestingLevel)
{
return new \MongoDate($value->getTimestamp());
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Formatter;
use Exception;
/**
* Normalizes incoming records to remove objects/resources so it's easier to dump to various targets
*
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class NormalizerFormatter implements FormatterInterface
{
const SIMPLE_DATE = "Y-m-d H:i:s";
protected $dateFormat;
/**
* @param string $dateFormat The format of the timestamp: one supported by DateTime::format
*/
public function __construct($dateFormat = null)
{
$this->dateFormat = $dateFormat ?: static::SIMPLE_DATE;
if (!function_exists('json_encode')) {
throw new \RuntimeException('PHP\'s json extension is required to use Monolog\'s NormalizerFormatter');
}
}
/**
* {@inheritdoc}
*/
public function format(array $record)
{
return $this->normalize($record);
}
/**
* {@inheritdoc}
*/
public function formatBatch(array $records)
{
foreach ($records as $key => $record) {
$records[$key] = $this->format($record);
}
return $records;
}
protected function normalize($data)
{
if (null === $data || is_scalar($data)) {
if (is_float($data)) {
if (is_infinite($data)) {
return ($data > 0 ? '' : '-') . 'INF';
}
if (is_nan($data)) {
return 'NaN';
}
}
return $data;
}
if (is_array($data) || $data instanceof \Traversable) {
$normalized = array();
$count = 1;
foreach ($data as $key => $value) {
if ($count++ >= 1000) {
$normalized['...'] = 'Over 1000 items, aborting normalization';
break;
}
$normalized[$key] = $this->normalize($value);
}
return $normalized;
}
if ($data instanceof \DateTime) {
return $data->format($this->dateFormat);
}
if (is_object($data)) {
if ($data instanceof Exception) {
return $this->normalizeException($data);
}
// non-serializable objects that implement __toString stringified
if (method_exists($data, '__toString') && !$data instanceof \JsonSerializable) {
$value = (string) $data;
} else {
// the rest is json-serialized in some way
$value = $this->toJson($data, true);
}
return sprintf("[object] (%s: %s)", get_class($data), $value);
}
if (is_resource($data)) {
return sprintf('[resource] (%s)', get_resource_type($data));
}
return '[unknown('.gettype($data).')]';
}
protected function normalizeException(Exception $e)
{
$data = array(
'class' => get_class($e),
'message' => $e->getMessage(),
'code' => $e->getCode(),
'file' => $e->getFile().':'.$e->getLine(),
);
$trace = $e->getTrace();
foreach ($trace as $frame) {
if (isset($frame['file'])) {
$data['trace'][] = $frame['file'].':'.$frame['line'];
} else {
// We should again normalize the frames, because it might contain invalid items
$data['trace'][] = $this->toJson($this->normalize($frame), true);
}
}
if ($previous = $e->getPrevious()) {
$data['previous'] = $this->normalizeException($previous);
}
return $data;
}
protected function toJson($data, $ignoreErrors = false)
{
// suppress json_encode errors since it's twitchy with some inputs
if ($ignoreErrors) {
if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
return @json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
}
return @json_encode($data);
}
if (version_compare(PHP_VERSION, '5.4.0', '>=')) {
$json = json_encode($data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE);
} else {
$json = json_encode($data);
}
if ($json === false) {
$this->throwEncodeError(json_last_error(), $data);
}
return $json;
}
/**
* Throws an exception according to a given code with a customized message
*
* @param int $code return code of json_last_error function
* @param mixed $data data that was meant to be encoded
* @throws \RuntimeException
*/
private function throwEncodeError($code, $data)
{
switch ($code) {
case JSON_ERROR_DEPTH:
$msg = 'Maximum stack depth exceeded';
break;
case JSON_ERROR_STATE_MISMATCH:
$msg = 'Underflow or the modes mismatch';
break;
case JSON_ERROR_CTRL_CHAR:
$msg = 'Unexpected control character found';
break;
case JSON_ERROR_UTF8:
$msg = 'Malformed UTF-8 characters, possibly incorrectly encoded';
break;
default:
$msg = 'Unknown error';
}
throw new \RuntimeException('JSON encoding failed: '.$msg.'. Encoding: '.var_export($data, true));
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Formatter;
/**
* Formats data into an associative array of scalar values.
* Objects and arrays will be JSON encoded.
*
* @author Andrew Lawson <adlawson@gmail.com>
*/
class ScalarFormatter extends NormalizerFormatter
{
/**
* {@inheritdoc}
*/
public function format(array $record)
{
foreach ($record as $key => $value) {
$record[$key] = $this->normalizeValue($value);
}
return $record;
}
/**
* @param mixed $value
* @return mixed
*/
protected function normalizeValue($value)
{
$normalized = $this->normalize($value);
if (is_array($normalized) || is_object($normalized)) {
return $this->toJson($normalized, true);
}
return $normalized;
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Formatter;
use Monolog\Logger;
/**
* Serializes a log message according to Wildfire's header requirements
*
* @author Eric Clemmons (@ericclemmons) <eric@uxdriven.com>
* @author Christophe Coevoet <stof@notk.org>
* @author Kirill chEbba Chebunin <iam@chebba.org>
*/
class WildfireFormatter extends NormalizerFormatter
{
const TABLE = 'table';
/**
* Translates Monolog log levels to Wildfire levels.
*/
private $logLevels = array(
Logger::DEBUG => 'LOG',
Logger::INFO => 'INFO',
Logger::NOTICE => 'INFO',
Logger::WARNING => 'WARN',
Logger::ERROR => 'ERROR',
Logger::CRITICAL => 'ERROR',
Logger::ALERT => 'ERROR',
Logger::EMERGENCY => 'ERROR',
);
/**
* {@inheritdoc}
*/
public function format(array $record)
{
// Retrieve the line and file if set and remove them from the formatted extra
$file = $line = '';
if (isset($record['extra']['file'])) {
$file = $record['extra']['file'];
unset($record['extra']['file']);
}
if (isset($record['extra']['line'])) {
$line = $record['extra']['line'];
unset($record['extra']['line']);
}
$record = $this->normalize($record);
$message = array('message' => $record['message']);
$handleError = false;
if ($record['context']) {
$message['context'] = $record['context'];
$handleError = true;
}
if ($record['extra']) {
$message['extra'] = $record['extra'];
$handleError = true;
}
if (count($message) === 1) {
$message = reset($message);
}
if (isset($record['context'][self::TABLE])) {
$type = 'TABLE';
$label = $record['channel'] .': '. $record['message'];
$message = $record['context'][self::TABLE];
} else {
$type = $this->logLevels[$record['level']];
$label = $record['channel'];
}
// Create JSON object describing the appearance of the message in the console
$json = $this->toJson(array(
array(
'Type' => $type,
'File' => $file,
'Line' => $line,
'Label' => $label,
),
$message,
), $handleError);
// The message itself is a serialization of the above JSON object + it's length
return sprintf(
'%s|%s|',
strlen($json),
$json
);
}
public function formatBatch(array $records)
{
throw new \BadMethodCallException('Batch formatting does not make sense for the WildfireFormatter');
}
protected function normalize($data)
{
if (is_object($data) && !$data instanceof \DateTime) {
return $data;
}
return parent::normalize($data);
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Logger;
use Monolog\Formatter\FormatterInterface;
use Monolog\Formatter\LineFormatter;
/**
* Base Handler class providing the Handler structure
*
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
abstract class AbstractHandler implements HandlerInterface
{
protected $level = Logger::DEBUG;
protected $bubble = true;
/**
* @var FormatterInterface
*/
protected $formatter;
protected $processors = array();
/**
* @param integer $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
*/
public function __construct($level = Logger::DEBUG, $bubble = true)
{
$this->setLevel($level);
$this->bubble = $bubble;
}
/**
* {@inheritdoc}
*/
public function isHandling(array $record)
{
return $record['level'] >= $this->level;
}
/**
* {@inheritdoc}
*/
public function handleBatch(array $records)
{
foreach ($records as $record) {
$this->handle($record);
}
}
/**
* Closes the handler.
*
* This will be called automatically when the object is destroyed
*/
public function close()
{
}
/**
* {@inheritdoc}
*/
public function pushProcessor($callback)
{
if (!is_callable($callback)) {
throw new \InvalidArgumentException('Processors must be valid callables (callback or object with an __invoke method), '.var_export($callback, true).' given');
}
array_unshift($this->processors, $callback);
return $this;
}
/**
* {@inheritdoc}
*/
public function popProcessor()
{
if (!$this->processors) {
throw new \LogicException('You tried to pop from an empty processor stack.');
}
return array_shift($this->processors);
}
/**
* {@inheritdoc}
*/
public function setFormatter(FormatterInterface $formatter)
{
$this->formatter = $formatter;
return $this;
}
/**
* {@inheritdoc}
*/
public function getFormatter()
{
if (!$this->formatter) {
$this->formatter = $this->getDefaultFormatter();
}
return $this->formatter;
}
/**
* Sets minimum logging level at which this handler will be triggered.
*
* @param integer $level
* @return self
*/
public function setLevel($level)
{
$this->level = Logger::toMonologLevel($level);
return $this;
}
/**
* Gets minimum logging level at which this handler will be triggered.
*
* @return integer
*/
public function getLevel()
{
return $this->level;
}
/**
* Sets the bubbling behavior.
*
* @param Boolean $bubble true means that this handler allows bubbling.
* false means that bubbling is not permitted.
* @return self
*/
public function setBubble($bubble)
{
$this->bubble = $bubble;
return $this;
}
/**
* Gets the bubbling behavior.
*
* @return Boolean true means that this handler allows bubbling.
* false means that bubbling is not permitted.
*/
public function getBubble()
{
return $this->bubble;
}
public function __destruct()
{
try {
$this->close();
} catch (\Exception $e) {
// do nothing
}
}
/**
* Gets the default formatter.
*
* @return FormatterInterface
*/
protected function getDefaultFormatter()
{
return new LineFormatter();
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
/**
* Base Handler class providing the Handler structure
*
* Classes extending it should (in most cases) only implement write($record)
*
* @author Jordi Boggiano <j.boggiano@seld.be>
* @author Christophe Coevoet <stof@notk.org>
*/
abstract class AbstractProcessingHandler extends AbstractHandler
{
/**
* {@inheritdoc}
*/
public function handle(array $record)
{
if (!$this->isHandling($record)) {
return false;
}
$record = $this->processRecord($record);
$record['formatted'] = $this->getFormatter()->format($record);
$this->write($record);
return false === $this->bubble;
}
/**
* Writes the record down to the log of the implementing handler
*
* @param array $record
* @return void
*/
abstract protected function write(array $record);
/**
* Processes a record.
*
* @param array $record
* @return array
*/
protected function processRecord(array $record)
{
if ($this->processors) {
foreach ($this->processors as $processor) {
$record = call_user_func($processor, $record);
}
}
return $record;
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Logger;
use Monolog\Formatter\LineFormatter;
/**
* Common syslog functionality
*/
abstract class AbstractSyslogHandler extends AbstractProcessingHandler
{
protected $facility;
/**
* Translates Monolog log levels to syslog log priorities.
*/
protected $logLevels = array(
Logger::DEBUG => LOG_DEBUG,
Logger::INFO => LOG_INFO,
Logger::NOTICE => LOG_NOTICE,
Logger::WARNING => LOG_WARNING,
Logger::ERROR => LOG_ERR,
Logger::CRITICAL => LOG_CRIT,
Logger::ALERT => LOG_ALERT,
Logger::EMERGENCY => LOG_EMERG,
);
/**
* List of valid log facility names.
*/
protected $facilities = array(
'auth' => LOG_AUTH,
'authpriv' => LOG_AUTHPRIV,
'cron' => LOG_CRON,
'daemon' => LOG_DAEMON,
'kern' => LOG_KERN,
'lpr' => LOG_LPR,
'mail' => LOG_MAIL,
'news' => LOG_NEWS,
'syslog' => LOG_SYSLOG,
'user' => LOG_USER,
'uucp' => LOG_UUCP,
);
/**
* @param mixed $facility
* @param integer $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
*/
public function __construct($facility = LOG_USER, $level = Logger::DEBUG, $bubble = true)
{
parent::__construct($level, $bubble);
if (!defined('PHP_WINDOWS_VERSION_BUILD')) {
$this->facilities['local0'] = LOG_LOCAL0;
$this->facilities['local1'] = LOG_LOCAL1;
$this->facilities['local2'] = LOG_LOCAL2;
$this->facilities['local3'] = LOG_LOCAL3;
$this->facilities['local4'] = LOG_LOCAL4;
$this->facilities['local5'] = LOG_LOCAL5;
$this->facilities['local6'] = LOG_LOCAL6;
$this->facilities['local7'] = LOG_LOCAL7;
}
// convert textual description of facility to syslog constant
if (array_key_exists(strtolower($facility), $this->facilities)) {
$facility = $this->facilities[strtolower($facility)];
} elseif (!in_array($facility, array_values($this->facilities), true)) {
throw new \UnexpectedValueException('Unknown facility value "'.$facility.'" given');
}
$this->facility = $facility;
}
/**
* {@inheritdoc}
*/
protected function getDefaultFormatter()
{
return new LineFormatter('%channel%.%level_name%: %message% %context% %extra%');
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Logger;
use Monolog\Formatter\JsonFormatter;
use PhpAmqpLib\Message\AMQPMessage;
use PhpAmqpLib\Channel\AMQPChannel;
use AMQPExchange;
class AmqpHandler extends AbstractProcessingHandler
{
/**
* @var AMQPExchange|AMQPChannel $exchange
*/
protected $exchange;
/**
* @var string
*/
protected $exchangeName;
/**
* @param AMQPExchange|AMQPChannel $exchange AMQPExchange (php AMQP ext) or PHP AMQP lib channel, ready for use
* @param string $exchangeName
* @param int $level
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
*/
public function __construct($exchange, $exchangeName = 'log', $level = Logger::DEBUG, $bubble = true)
{
if ($exchange instanceof AMQPExchange) {
$exchange->setName($exchangeName);
} elseif ($exchange instanceof AMQPChannel) {
$this->exchangeName = $exchangeName;
} else {
throw new \InvalidArgumentException('PhpAmqpLib\Channel\AMQPChannel or AMQPExchange instance required');
}
$this->exchange = $exchange;
parent::__construct($level, $bubble);
}
/**
* {@inheritDoc}
*/
protected function write(array $record)
{
$data = $record["formatted"];
$routingKey = sprintf(
'%s.%s',
// TODO 2.0 remove substr call
substr($record['level_name'], 0, 4),
$record['channel']
);
if ($this->exchange instanceof AMQPExchange) {
$this->exchange->publish(
$data,
strtolower($routingKey),
0,
array(
'delivery_mode' => 2,
'Content-type' => 'application/json'
)
);
} else {
$this->exchange->basic_publish(
new AMQPMessage(
(string) $data,
array(
'delivery_mode' => 2,
'content_type' => 'application/json'
)
),
$this->exchangeName,
strtolower($routingKey)
);
}
}
/**
* {@inheritDoc}
*/
protected function getDefaultFormatter()
{
return new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false);
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Formatter\LineFormatter;
/**
* Handler sending logs to browser's javascript console with no browser extension required
*
* @author Olivier Poitrey <rs@dailymotion.com>
*/
class BrowserConsoleHandler extends AbstractProcessingHandler
{
protected static $initialized = false;
protected static $records = array();
/**
* {@inheritDoc}
*
* Formatted output may contain some formatting markers to be transferred to `console.log` using the %c format.
*
* Example of formatted string:
*
* You can do [[blue text]]{color: blue} or [[green background]]{background-color: green; color: white}
*
*/
protected function getDefaultFormatter()
{
return new LineFormatter('[[%channel%]]{macro: autolabel} [[%level_name%]]{font-weight: bold} %message%');
}
/**
* {@inheritDoc}
*/
protected function write(array $record)
{
// Accumulate records
self::$records[] = $record;
// Register shutdown handler if not already done
if (PHP_SAPI !== 'cli' && !self::$initialized) {
self::$initialized = true;
register_shutdown_function(array('Monolog\Handler\BrowserConsoleHandler', 'send'));
}
}
/**
* Convert records to javascript console commands and send it to the browser.
* This method is automatically called on PHP shutdown if output is HTML or Javascript.
*/
public static function send()
{
$htmlTags = true;
// Check content type
foreach (headers_list() as $header) {
if (stripos($header, 'content-type:') === 0) {
// This handler only works with HTML and javascript outputs
// text/javascript is obsolete in favour of application/javascript, but still used
if (stripos($header, 'application/javascript') !== false || stripos($header, 'text/javascript') !== false) {
$htmlTags = false;
} elseif (stripos($header, 'text/html') === false) {
return;
}
break;
}
}
if (count(self::$records)) {
if ($htmlTags) {
echo '<script>' , self::generateScript() , '</script>';
} else {
echo self::generateScript();
}
self::reset();
}
}
/**
* Forget all logged records
*/
public static function reset()
{
self::$records = array();
}
private static function generateScript()
{
$script = array();
foreach (self::$records as $record) {
$context = self::dump('Context', $record['context']);
$extra = self::dump('Extra', $record['extra']);
if (empty($context) && empty($extra)) {
$script[] = self::call_array('log', self::handleStyles($record['formatted']));
} else {
$script = array_merge($script,
array(self::call_array('groupCollapsed', self::handleStyles($record['formatted']))),
$context,
$extra,
array(self::call('groupEnd'))
);
}
}
return "(function (c) {if (c && c.groupCollapsed) {\n" . implode("\n", $script) . "\n}})(console);";
}
private static function handleStyles($formatted)
{
$args = array(self::quote('font-weight: normal'));
$format = '%c' . $formatted;
preg_match_all('/\[\[(.*?)\]\]\{([^}]*)\}/s', $format, $matches, PREG_OFFSET_CAPTURE | PREG_SET_ORDER);
foreach (array_reverse($matches) as $match) {
$args[] = self::quote(self::handleCustomStyles($match[2][0], $match[1][0]));
$args[] = '"font-weight: normal"';
$pos = $match[0][1];
$format = substr($format, 0, $pos) . '%c' . $match[1][0] . '%c' . substr($format, $pos + strlen($match[0][0]));
}
array_unshift($args, self::quote($format));
return $args;
}
private static function handleCustomStyles($style, $string)
{
static $colors = array('blue', 'green', 'red', 'magenta', 'orange', 'black', 'grey');
static $labels = array();
return preg_replace_callback('/macro\s*:(.*?)(?:;|$)/', function ($m) use ($string, &$colors, &$labels) {
if (trim($m[1]) === 'autolabel') {
// Format the string as a label with consistent auto assigned background color
if (!isset($labels[$string])) {
$labels[$string] = $colors[count($labels) % count($colors)];
}
$color = $labels[$string];
return "background-color: $color; color: white; border-radius: 3px; padding: 0 2px 0 2px";
}
return $m[1];
}, $style);
}
private static function dump($title, array $dict)
{
$script = array();
$dict = array_filter($dict);
if (empty($dict)) {
return $script;
}
$script[] = self::call('log', self::quote('%c%s'), self::quote('font-weight: bold'), self::quote($title));
foreach ($dict as $key => $value) {
$value = json_encode($value);
if (empty($value)) {
$value = self::quote('');
}
$script[] = self::call('log', self::quote('%s: %o'), self::quote($key), $value);
}
return $script;
}
private static function quote($arg)
{
return '"' . addcslashes($arg, "\"\n\\") . '"';
}
private static function call()
{
$args = func_get_args();
$method = array_shift($args);
return self::call_array($method, $args);
}
private static function call_array($method, array $args)
{
return 'c.' . $method . '(' . implode(', ', $args) . ');';
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Logger;
/**
* Buffers all records until closing the handler and then pass them as batch.
*
* This is useful for a MailHandler to send only one mail per request instead of
* sending one per log message.
*
* @author Christophe Coevoet <stof@notk.org>
*/
class BufferHandler extends AbstractHandler
{
protected $handler;
protected $bufferSize = 0;
protected $bufferLimit;
protected $flushOnOverflow;
protected $buffer = array();
protected $initialized = false;
/**
* @param HandlerInterface $handler Handler.
* @param integer $bufferLimit How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
* @param integer $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
* @param Boolean $flushOnOverflow If true, the buffer is flushed when the max size has been reached, by default oldest entries are discarded
*/
public function __construct(HandlerInterface $handler, $bufferLimit = 0, $level = Logger::DEBUG, $bubble = true, $flushOnOverflow = false)
{
parent::__construct($level, $bubble);
$this->handler = $handler;
$this->bufferLimit = (int) $bufferLimit;
$this->flushOnOverflow = $flushOnOverflow;
}
/**
* {@inheritdoc}
*/
public function handle(array $record)
{
if ($record['level'] < $this->level) {
return false;
}
if (!$this->initialized) {
// __destructor() doesn't get called on Fatal errors
register_shutdown_function(array($this, 'close'));
$this->initialized = true;
}
if ($this->bufferLimit > 0 && $this->bufferSize === $this->bufferLimit) {
if ($this->flushOnOverflow) {
$this->flush();
} else {
array_shift($this->buffer);
$this->bufferSize--;
}
}
if ($this->processors) {
foreach ($this->processors as $processor) {
$record = call_user_func($processor, $record);
}
}
$this->buffer[] = $record;
$this->bufferSize++;
return false === $this->bubble;
}
public function flush()
{
if ($this->bufferSize === 0) {
return;
}
$this->handler->handleBatch($this->buffer);
$this->clear();
}
public function __destruct()
{
// suppress the parent behavior since we already have register_shutdown_function()
// to call close(), and the reference contained there will prevent this from being
// GC'd until the end of the request
}
/**
* {@inheritdoc}
*/
public function close()
{
$this->flush();
}
/**
* Clears the buffer without flushing any messages down to the wrapped handler.
*/
public function clear()
{
$this->bufferSize = 0;
$this->buffer = array();
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Formatter\ChromePHPFormatter;
use Monolog\Logger;
/**
* Handler sending logs to the ChromePHP extension (http://www.chromephp.com/)
*
* @author Christophe Coevoet <stof@notk.org>
*/
class ChromePHPHandler extends AbstractProcessingHandler
{
/**
* Version of the extension
*/
const VERSION = '4.0';
/**
* Header name
*/
const HEADER_NAME = 'X-ChromeLogger-Data';
protected static $initialized = false;
/**
* Tracks whether we sent too much data
*
* Chrome limits the headers to 256KB, so when we sent 240KB we stop sending
*
* @var Boolean
*/
protected static $overflowed = false;
protected static $json = array(
'version' => self::VERSION,
'columns' => array('label', 'log', 'backtrace', 'type'),
'rows' => array(),
);
protected static $sendHeaders = true;
/**
* @param integer $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
*/
public function __construct($level = Logger::DEBUG, $bubble = true)
{
parent::__construct($level, $bubble);
if (!function_exists('json_encode')) {
throw new \RuntimeException('PHP\'s json extension is required to use Monolog\'s ChromePHPHandler');
}
}
/**
* {@inheritdoc}
*/
public function handleBatch(array $records)
{
$messages = array();
foreach ($records as $record) {
if ($record['level'] < $this->level) {
continue;
}
$messages[] = $this->processRecord($record);
}
if (!empty($messages)) {
$messages = $this->getFormatter()->formatBatch($messages);
self::$json['rows'] = array_merge(self::$json['rows'], $messages);
$this->send();
}
}
/**
* {@inheritDoc}
*/
protected function getDefaultFormatter()
{
return new ChromePHPFormatter();
}
/**
* Creates & sends header for a record
*
* @see sendHeader()
* @see send()
* @param array $record
*/
protected function write(array $record)
{
self::$json['rows'][] = $record['formatted'];
$this->send();
}
/**
* Sends the log header
*
* @see sendHeader()
*/
protected function send()
{
if (self::$overflowed || !self::$sendHeaders) {
return;
}
if (!self::$initialized) {
self::$initialized = true;
self::$sendHeaders = $this->headersAccepted();
if (!self::$sendHeaders) {
return;
}
self::$json['request_uri'] = isset($_SERVER['REQUEST_URI']) ? $_SERVER['REQUEST_URI'] : '';
}
$json = @json_encode(self::$json);
$data = base64_encode(utf8_encode($json));
if (strlen($data) > 240 * 1024) {
self::$overflowed = true;
$record = array(
'message' => 'Incomplete logs, chrome header size limit reached',
'context' => array(),
'level' => Logger::WARNING,
'level_name' => Logger::getLevelName(Logger::WARNING),
'channel' => 'monolog',
'datetime' => new \DateTime(),
'extra' => array(),
);
self::$json['rows'][count(self::$json['rows']) - 1] = $this->getFormatter()->format($record);
$json = @json_encode(self::$json);
$data = base64_encode(utf8_encode($json));
}
if (trim($data) !== '') {
$this->sendHeader(self::HEADER_NAME, $data);
}
}
/**
* Send header string to the client
*
* @param string $header
* @param string $content
*/
protected function sendHeader($header, $content)
{
if (!headers_sent() && self::$sendHeaders) {
header(sprintf('%s: %s', $header, $content));
}
}
/**
* Verifies if the headers are accepted by the current user agent
*
* @return Boolean
*/
protected function headersAccepted()
{
if (empty($_SERVER['HTTP_USER_AGENT'])) {
return false;
}
return preg_match('{\bChrome/\d+[\.\d+]*\b}', $_SERVER['HTTP_USER_AGENT']);
}
/**
* BC getter for the sendHeaders property that has been made static
*/
public function __get($property)
{
if ('sendHeaders' !== $property) {
throw new \InvalidArgumentException('Undefined property '.$property);
}
return static::$sendHeaders;
}
/**
* BC setter for the sendHeaders property that has been made static
*/
public function __set($property, $value)
{
if ('sendHeaders' !== $property) {
throw new \InvalidArgumentException('Undefined property '.$property);
}
static::$sendHeaders = $value;
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Formatter\JsonFormatter;
use Monolog\Logger;
/**
* CouchDB handler
*
* @author Markus Bachmann <markus.bachmann@bachi.biz>
*/
class CouchDBHandler extends AbstractProcessingHandler
{
private $options;
public function __construct(array $options = array(), $level = Logger::DEBUG, $bubble = true)
{
$this->options = array_merge(array(
'host' => 'localhost',
'port' => 5984,
'dbname' => 'logger',
'username' => null,
'password' => null,
), $options);
parent::__construct($level, $bubble);
}
/**
* {@inheritDoc}
*/
protected function write(array $record)
{
$basicAuth = null;
if ($this->options['username']) {
$basicAuth = sprintf('%s:%s@', $this->options['username'], $this->options['password']);
}
$url = 'http://'.$basicAuth.$this->options['host'].':'.$this->options['port'].'/'.$this->options['dbname'];
$context = stream_context_create(array(
'http' => array(
'method' => 'POST',
'content' => $record['formatted'],
'ignore_errors' => true,
'max_redirects' => 0,
'header' => 'Content-type: application/json',
)
));
if (false === @file_get_contents($url, null, $context)) {
throw new \RuntimeException(sprintf('Could not connect to %s', $url));
}
}
/**
* {@inheritDoc}
*/
protected function getDefaultFormatter()
{
return new JsonFormatter(JsonFormatter::BATCH_MODE_JSON, false);
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Logger;
/**
* Logs to Cube.
*
* @link http://square.github.com/cube/
* @author Wan Chen <kami@kamisama.me>
*/
class CubeHandler extends AbstractProcessingHandler
{
private $udpConnection = null;
private $httpConnection = null;
private $scheme = null;
private $host = null;
private $port = null;
private $acceptedSchemes = array('http', 'udp');
/**
* Create a Cube handler
*
* @throws \UnexpectedValueException when given url is not a valid url.
* A valid url must consists of three parts : protocol://host:port
* Only valid protocol used by Cube are http and udp
*/
public function __construct($url, $level = Logger::DEBUG, $bubble = true)
{
$urlInfos = parse_url($url);
if (!isset($urlInfos['scheme']) || !isset($urlInfos['host']) || !isset($urlInfos['port'])) {
throw new \UnexpectedValueException('URL "'.$url.'" is not valid');
}
if (!in_array($urlInfos['scheme'], $this->acceptedSchemes)) {
throw new \UnexpectedValueException(
'Invalid protocol (' . $urlInfos['scheme'] . ').'
. ' Valid options are ' . implode(', ', $this->acceptedSchemes));
}
$this->scheme = $urlInfos['scheme'];
$this->host = $urlInfos['host'];
$this->port = $urlInfos['port'];
parent::__construct($level, $bubble);
}
/**
* Establish a connection to an UDP socket
*
* @throws \LogicException when unable to connect to the socket
*/
protected function connectUdp()
{
if (!extension_loaded('sockets')) {
throw new MissingExtensionException('The sockets extension is required to use udp URLs with the CubeHandler');
}
$this->udpConnection = socket_create(AF_INET, SOCK_DGRAM, 0);
if (!$this->udpConnection) {
throw new \LogicException('Unable to create a socket');
}
if (!socket_connect($this->udpConnection, $this->host, $this->port)) {
throw new \LogicException('Unable to connect to the socket at ' . $this->host . ':' . $this->port);
}
}
/**
* Establish a connection to a http server
*/
protected function connectHttp()
{
if (!extension_loaded('curl')) {
throw new \LogicException('The curl extension is needed to use http URLs with the CubeHandler');
}
$this->httpConnection = curl_init('http://'.$this->host.':'.$this->port.'/1.0/event/put');
if (!$this->httpConnection) {
throw new \LogicException('Unable to connect to ' . $this->host . ':' . $this->port);
}
curl_setopt($this->httpConnection, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($this->httpConnection, CURLOPT_RETURNTRANSFER, true);
}
/**
* {@inheritdoc}
*/
protected function write(array $record)
{
$date = $record['datetime'];
$data = array('time' => $date->format('Y-m-d\TH:i:s.uO'));
unset($record['datetime']);
if (isset($record['context']['type'])) {
$data['type'] = $record['context']['type'];
unset($record['context']['type']);
} else {
$data['type'] = $record['channel'];
}
$data['data'] = $record['context'];
$data['data']['level'] = $record['level'];
if ($this->scheme === 'http') {
$this->writeHttp(json_encode($data));
} else {
$this->writeUdp(json_encode($data));
}
}
private function writeUdp($data)
{
if (!$this->udpConnection) {
$this->connectUdp();
}
socket_send($this->udpConnection, $data, strlen($data), 0);
}
private function writeHttp($data)
{
if (!$this->httpConnection) {
$this->connectHttp();
}
curl_setopt($this->httpConnection, CURLOPT_POSTFIELDS, '['.$data.']');
curl_setopt($this->httpConnection, CURLOPT_HTTPHEADER, array(
'Content-Type: application/json',
'Content-Length: ' . strlen('['.$data.']'))
);
Curl\Util::execute($ch, 5, false);
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler\Curl;
class Util
{
private static $retriableErrorCodes = array(
CURLE_COULDNT_RESOLVE_HOST,
CURLE_COULDNT_CONNECT,
CURLE_HTTP_NOT_FOUND,
CURLE_READ_ERROR,
CURLE_OPERATION_TIMEOUTED,
CURLE_HTTP_POST_ERROR,
CURLE_SSL_CONNECT_ERROR,
);
/**
* Executes a CURL request with optional retries and exception on failure
*
* @param resource $ch curl handler
* @throws \RuntimeException
*/
public static function execute($ch, $retries = 5, $closeAfterDone = true)
{
while ($retries--) {
if (curl_exec($ch) === false) {
$curlErrno = curl_errno($ch);
if (false === in_array($curlErrno, self::$retriableErrorCodes, true) || !$retries) {
$curlError = curl_error($ch);
if ($closeAfterDone) {
curl_close($ch);
}
throw new \RuntimeException(sprintf('Curl error (code %s): %s', $curlErrno, $curlError));
}
continue;
}
if ($closeAfterDone) {
curl_close($ch);
}
break;
}
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Logger;
use Monolog\Formatter\NormalizerFormatter;
use Doctrine\CouchDB\CouchDBClient;
/**
* CouchDB handler for Doctrine CouchDB ODM
*
* @author Markus Bachmann <markus.bachmann@bachi.biz>
*/
class DoctrineCouchDBHandler extends AbstractProcessingHandler
{
private $client;
public function __construct(CouchDBClient $client, $level = Logger::DEBUG, $bubble = true)
{
$this->client = $client;
parent::__construct($level, $bubble);
}
/**
* {@inheritDoc}
*/
protected function write(array $record)
{
$this->client->postDocument($record['formatted']);
}
protected function getDefaultFormatter()
{
return new NormalizerFormatter;
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Aws\Common\Aws;
use Aws\DynamoDb\DynamoDbClient;
use Monolog\Formatter\ScalarFormatter;
use Monolog\Logger;
/**
* Amazon DynamoDB handler (http://aws.amazon.com/dynamodb/)
*
* @link https://github.com/aws/aws-sdk-php/
* @author Andrew Lawson <adlawson@gmail.com>
*/
class DynamoDbHandler extends AbstractProcessingHandler
{
const DATE_FORMAT = 'Y-m-d\TH:i:s.uO';
/**
* @var DynamoDbClient
*/
protected $client;
/**
* @var string
*/
protected $table;
/**
* @param DynamoDbClient $client
* @param string $table
* @param integer $level
* @param boolean $bubble
*/
public function __construct(DynamoDbClient $client, $table, $level = Logger::DEBUG, $bubble = true)
{
if (!defined('Aws\Common\Aws::VERSION') || version_compare('3.0', Aws::VERSION, '<=')) {
throw new \RuntimeException('The DynamoDbHandler is only known to work with the AWS SDK 2.x releases');
}
$this->client = $client;
$this->table = $table;
parent::__construct($level, $bubble);
}
/**
* {@inheritdoc}
*/
protected function write(array $record)
{
$filtered = $this->filterEmptyFields($record['formatted']);
$formatted = $this->client->formatAttributes($filtered);
$this->client->putItem(array(
'TableName' => $this->table,
'Item' => $formatted
));
}
/**
* @param array $record
* @return array
*/
protected function filterEmptyFields(array $record)
{
return array_filter($record, function ($value) {
return !empty($value) || false === $value || 0 === $value;
});
}
/**
* {@inheritdoc}
*/
protected function getDefaultFormatter()
{
return new ScalarFormatter(self::DATE_FORMAT);
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Formatter\FormatterInterface;
use Monolog\Formatter\ElasticaFormatter;
use Monolog\Logger;
use Elastica\Client;
use Elastica\Exception\ExceptionInterface;
/**
* Elastic Search handler
*
* Usage example:
*
* $client = new \Elastica\Client();
* $options = array(
* 'index' => 'elastic_index_name',
* 'type' => 'elastic_doc_type',
* );
* $handler = new ElasticSearchHandler($client, $options);
* $log = new Logger('application');
* $log->pushHandler($handler);
*
* @author Jelle Vink <jelle.vink@gmail.com>
*/
class ElasticSearchHandler extends AbstractProcessingHandler
{
/**
* @var Client
*/
protected $client;
/**
* @var array Handler config options
*/
protected $options = array();
/**
* @param Client $client Elastica Client object
* @param array $options Handler configuration
* @param integer $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
*/
public function __construct(Client $client, array $options = array(), $level = Logger::DEBUG, $bubble = true)
{
parent::__construct($level, $bubble);
$this->client = $client;
$this->options = array_merge(
array(
'index' => 'monolog', // Elastic index name
'type' => 'record', // Elastic document type
'ignore_error' => false, // Suppress Elastica exceptions
),
$options
);
}
/**
* {@inheritDoc}
*/
protected function write(array $record)
{
$this->bulkSend(array($record['formatted']));
}
/**
* {@inheritdoc}
*/
public function setFormatter(FormatterInterface $formatter)
{
if ($formatter instanceof ElasticaFormatter) {
return parent::setFormatter($formatter);
}
throw new \InvalidArgumentException('ElasticSearchHandler is only compatible with ElasticaFormatter');
}
/**
* Getter options
* @return array
*/
public function getOptions()
{
return $this->options;
}
/**
* {@inheritDoc}
*/
protected function getDefaultFormatter()
{
return new ElasticaFormatter($this->options['index'], $this->options['type']);
}
/**
* {@inheritdoc}
*/
public function handleBatch(array $records)
{
$documents = $this->getFormatter()->formatBatch($records);
$this->bulkSend($documents);
}
/**
* Use Elasticsearch bulk API to send list of documents
* @param array $documents
* @throws \RuntimeException
*/
protected function bulkSend(array $documents)
{
try {
$this->client->addDocuments($documents);
} catch (ExceptionInterface $e) {
if (!$this->options['ignore_error']) {
throw new \RuntimeException("Error sending messages to Elasticsearch", 0, $e);
}
}
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Formatter\LineFormatter;
use Monolog\Logger;
/**
* Stores to PHP error_log() handler.
*
* @author Elan Ruusamäe <glen@delfi.ee>
*/
class ErrorLogHandler extends AbstractProcessingHandler
{
const OPERATING_SYSTEM = 0;
const SAPI = 4;
protected $messageType;
protected $expandNewlines;
/**
* @param integer $messageType Says where the error should go.
* @param integer $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
* @param Boolean $expandNewlines If set to true, newlines in the message will be expanded to be take multiple log entries
*/
public function __construct($messageType = self::OPERATING_SYSTEM, $level = Logger::DEBUG, $bubble = true, $expandNewlines = false)
{
parent::__construct($level, $bubble);
if (false === in_array($messageType, self::getAvailableTypes())) {
$message = sprintf('The given message type "%s" is not supported', print_r($messageType, true));
throw new \InvalidArgumentException($message);
}
$this->messageType = $messageType;
$this->expandNewlines = $expandNewlines;
}
/**
* @return array With all available types
*/
public static function getAvailableTypes()
{
return array(
self::OPERATING_SYSTEM,
self::SAPI,
);
}
/**
* {@inheritDoc}
*/
protected function getDefaultFormatter()
{
return new LineFormatter('[%datetime%] %channel%.%level_name%: %message% %context% %extra%');
}
/**
* {@inheritdoc}
*/
protected function write(array $record)
{
if ($this->expandNewlines) {
$lines = preg_split('{[\r\n]+}', (string) $record['formatted']);
foreach ($lines as $line) {
error_log($line, $this->messageType);
}
} else {
error_log((string) $record['formatted'], $this->messageType);
}
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Logger;
/**
* Simple handler wrapper that filters records based on a list of levels
*
* It can be configured with an exact list of levels to allow, or a min/max level.
*
* @author Hennadiy Verkh
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class FilterHandler extends AbstractHandler
{
/**
* Handler or factory callable($record, $this)
*
* @var callable|\Monolog\Handler\HandlerInterface
*/
protected $handler;
/**
* Minimum level for logs that are passes to handler
*
* @var int[]
*/
protected $acceptedLevels;
/**
* Whether the messages that are handled can bubble up the stack or not
*
* @var Boolean
*/
protected $bubble;
/**
* @param callable|HandlerInterface $handler Handler or factory callable($record, $this).
* @param int|array $minLevelOrList A list of levels to accept or a minimum level if maxLevel is provided
* @param int $maxLevel Maximum level to accept, only used if $minLevelOrList is not an array
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
*/
public function __construct($handler, $minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY, $bubble = true)
{
$this->handler = $handler;
$this->bubble = $bubble;
$this->setAcceptedLevels($minLevelOrList, $maxLevel);
if (!$this->handler instanceof HandlerInterface && !is_callable($this->handler)) {
throw new \RuntimeException("The given handler (".json_encode($this->handler).") is not a callable nor a Monolog\Handler\HandlerInterface object");
}
}
/**
* @return array
*/
public function getAcceptedLevels()
{
return array_flip($this->acceptedLevels);
}
/**
* @param int|array $minLevelOrList A list of levels to accept or a minimum level if maxLevel is provided
* @param int $maxLevel Maximum level to accept, only used if $minLevelOrList is not an array
*/
public function setAcceptedLevels($minLevelOrList = Logger::DEBUG, $maxLevel = Logger::EMERGENCY)
{
if (is_array($minLevelOrList)) {
$acceptedLevels = array_map('Monolog\Logger::toMonologLevel', $minLevelOrList);
} else {
$minLevelOrList = Logger::toMonologLevel($minLevelOrList);
$maxLevel = Logger::toMonologLevel($maxLevel);
$acceptedLevels = array_values(array_filter(Logger::getLevels(), function ($level) use ($minLevelOrList, $maxLevel) {
return $level >= $minLevelOrList && $level <= $maxLevel;
}));
}
$this->acceptedLevels = array_flip($acceptedLevels);
}
/**
* {@inheritdoc}
*/
public function isHandling(array $record)
{
return isset($this->acceptedLevels[$record['level']]);
}
/**
* {@inheritdoc}
*/
public function handle(array $record)
{
if (!$this->isHandling($record)) {
return false;
}
// The same logic as in FingersCrossedHandler
if (!$this->handler instanceof HandlerInterface) {
$this->handler = call_user_func($this->handler, $record, $this);
if (!$this->handler instanceof HandlerInterface) {
throw new \RuntimeException("The factory callable should return a HandlerInterface");
}
}
if ($this->processors) {
foreach ($this->processors as $processor) {
$record = call_user_func($processor, $record);
}
}
$this->handler->handle($record);
return false === $this->bubble;
}
/**
* {@inheritdoc}
*/
public function handleBatch(array $records)
{
$filtered = array();
foreach ($records as $record) {
if ($this->isHandling($record)) {
$filtered[] = $record;
}
}
$this->handler->handleBatch($filtered);
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler\FingersCrossed;
/**
* Interface for activation strategies for the FingersCrossedHandler.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
interface ActivationStrategyInterface
{
/**
* Returns whether the given record activates the handler.
*
* @param array $record
* @return Boolean
*/
public function isHandlerActivated(array $record);
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler\FingersCrossed;
use Monolog\Logger;
/**
* Channel and Error level based monolog activation strategy. Allows to trigger activation
* based on level per channel. e.g. trigger activation on level 'ERROR' by default, except
* for records of the 'sql' channel; those should trigger activation on level 'WARN'.
*
* Example:
*
* <code>
* $activationStrategy = new ChannelLevelActivationStrategy(
* Logger::CRITICAL,
* array(
* 'request' => Logger::ALERT,
* 'sensitive' => Logger::ERROR,
* )
* );
* $handler = new FingersCrossedHandler(new StreamHandler('php://stderr'), $activationStrategy);
* </code>
*
* @author Mike Meessen <netmikey@gmail.com>
*/
class ChannelLevelActivationStrategy implements ActivationStrategyInterface
{
private $defaultActionLevel;
private $channelToActionLevel;
/**
* @param int $defaultActionLevel The default action level to be used if the record's category doesn't match any
* @param array $channelToActionLevel An array that maps channel names to action levels.
*/
public function __construct($defaultActionLevel, $channelToActionLevel = array())
{
$this->defaultActionLevel = Logger::toMonologLevel($defaultActionLevel);
$this->channelToActionLevel = array_map('Monolog\Logger::toMonologLevel', $channelToActionLevel);
}
public function isHandlerActivated(array $record)
{
if (isset($this->channelToActionLevel[$record['channel']])) {
return $record['level'] >= $this->channelToActionLevel[$record['channel']];
}
return $record['level'] >= $this->defaultActionLevel;
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler\FingersCrossed;
use Monolog\Logger;
/**
* Error level based activation strategy.
*
* @author Johannes M. Schmitt <schmittjoh@gmail.com>
*/
class ErrorLevelActivationStrategy implements ActivationStrategyInterface
{
private $actionLevel;
public function __construct($actionLevel)
{
$this->actionLevel = Logger::toMonologLevel($actionLevel);
}
public function isHandlerActivated(array $record)
{
return $record['level'] >= $this->actionLevel;
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Handler\FingersCrossed\ErrorLevelActivationStrategy;
use Monolog\Handler\FingersCrossed\ActivationStrategyInterface;
use Monolog\Logger;
/**
* Buffers all records until a certain level is reached
*
* The advantage of this approach is that you don't get any clutter in your log files.
* Only requests which actually trigger an error (or whatever your actionLevel is) will be
* in the logs, but they will contain all records, not only those above the level threshold.
*
* You can find the various activation strategies in the
* Monolog\Handler\FingersCrossed\ namespace.
*
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class FingersCrossedHandler extends AbstractHandler
{
protected $handler;
protected $activationStrategy;
protected $buffering = true;
protected $bufferSize;
protected $buffer = array();
protected $stopBuffering;
protected $passthruLevel;
/**
* @param callable|HandlerInterface $handler Handler or factory callable($record, $fingersCrossedHandler).
* @param int|ActivationStrategyInterface $activationStrategy Strategy which determines when this handler takes action
* @param int $bufferSize How many entries should be buffered at most, beyond that the oldest items are removed from the buffer.
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
* @param Boolean $stopBuffering Whether the handler should stop buffering after being triggered (default true)
* @param int $passthruLevel Minimum level to always flush to handler on close, even if strategy not triggered
*/
public function __construct($handler, $activationStrategy = null, $bufferSize = 0, $bubble = true, $stopBuffering = true, $passthruLevel = null)
{
if (null === $activationStrategy) {
$activationStrategy = new ErrorLevelActivationStrategy(Logger::WARNING);
}
// convert simple int activationStrategy to an object
if (!$activationStrategy instanceof ActivationStrategyInterface) {
$activationStrategy = new ErrorLevelActivationStrategy($activationStrategy);
}
$this->handler = $handler;
$this->activationStrategy = $activationStrategy;
$this->bufferSize = $bufferSize;
$this->bubble = $bubble;
$this->stopBuffering = $stopBuffering;
if ($passthruLevel !== null) {
$this->passthruLevel = Logger::toMonologLevel($passthruLevel);
}
if (!$this->handler instanceof HandlerInterface && !is_callable($this->handler)) {
throw new \RuntimeException("The given handler (".json_encode($this->handler).") is not a callable nor a Monolog\Handler\HandlerInterface object");
}
}
/**
* {@inheritdoc}
*/
public function isHandling(array $record)
{
return true;
}
/**
* {@inheritdoc}
*/
public function handle(array $record)
{
if ($this->processors) {
foreach ($this->processors as $processor) {
$record = call_user_func($processor, $record);
}
}
if ($this->buffering) {
$this->buffer[] = $record;
if ($this->bufferSize > 0 && count($this->buffer) > $this->bufferSize) {
array_shift($this->buffer);
}
if ($this->activationStrategy->isHandlerActivated($record)) {
if ($this->stopBuffering) {
$this->buffering = false;
}
if (!$this->handler instanceof HandlerInterface) {
$this->handler = call_user_func($this->handler, $record, $this);
if (!$this->handler instanceof HandlerInterface) {
throw new \RuntimeException("The factory callable should return a HandlerInterface");
}
}
$this->handler->handleBatch($this->buffer);
$this->buffer = array();
}
} else {
$this->handler->handle($record);
}
return false === $this->bubble;
}
/**
* {@inheritdoc}
*/
public function close()
{
if (null !== $this->passthruLevel) {
$level = $this->passthruLevel;
$this->buffer = array_filter($this->buffer, function ($record) use ($level) {
return $record['level'] >= $level;
});
if (count($this->buffer) > 0) {
$this->handler->handleBatch($this->buffer);
$this->buffer = array();
}
}
}
/**
* Resets the state of the handler. Stops forwarding records to the wrapped handler.
*/
public function reset()
{
$this->buffering = true;
}
/**
* Clears the buffer without flushing any messages down to the wrapped handler.
*
* It also resets the handler to its initial buffering state.
*/
public function clear()
{
$this->buffer = array();
$this->reset();
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Formatter\WildfireFormatter;
/**
* Simple FirePHP Handler (http://www.firephp.org/), which uses the Wildfire protocol.
*
* @author Eric Clemmons (@ericclemmons) <eric@uxdriven.com>
*/
class FirePHPHandler extends AbstractProcessingHandler
{
/**
* WildFire JSON header message format
*/
const PROTOCOL_URI = 'http://meta.wildfirehq.org/Protocol/JsonStream/0.2';
/**
* FirePHP structure for parsing messages & their presentation
*/
const STRUCTURE_URI = 'http://meta.firephp.org/Wildfire/Structure/FirePHP/FirebugConsole/0.1';
/**
* Must reference a "known" plugin, otherwise headers won't display in FirePHP
*/
const PLUGIN_URI = 'http://meta.firephp.org/Wildfire/Plugin/FirePHP/Library-FirePHPCore/0.3';
/**
* Header prefix for Wildfire to recognize & parse headers
*/
const HEADER_PREFIX = 'X-Wf';
/**
* Whether or not Wildfire vendor-specific headers have been generated & sent yet
*/
protected static $initialized = false;
/**
* Shared static message index between potentially multiple handlers
* @var int
*/
protected static $messageIndex = 1;
protected static $sendHeaders = true;
/**
* Base header creation function used by init headers & record headers
*
* @param array $meta Wildfire Plugin, Protocol & Structure Indexes
* @param string $message Log message
* @return array Complete header string ready for the client as key and message as value
*/
protected function createHeader(array $meta, $message)
{
$header = sprintf('%s-%s', self::HEADER_PREFIX, join('-', $meta));
return array($header => $message);
}
/**
* Creates message header from record
*
* @see createHeader()
* @param array $record
* @return string
*/
protected function createRecordHeader(array $record)
{
// Wildfire is extensible to support multiple protocols & plugins in a single request,
// but we're not taking advantage of that (yet), so we're using "1" for simplicity's sake.
return $this->createHeader(
array(1, 1, 1, self::$messageIndex++),
$record['formatted']
);
}
/**
* {@inheritDoc}
*/
protected function getDefaultFormatter()
{
return new WildfireFormatter();
}
/**
* Wildfire initialization headers to enable message parsing
*
* @see createHeader()
* @see sendHeader()
* @return array
*/
protected function getInitHeaders()
{
// Initial payload consists of required headers for Wildfire
return array_merge(
$this->createHeader(array('Protocol', 1), self::PROTOCOL_URI),
$this->createHeader(array(1, 'Structure', 1), self::STRUCTURE_URI),
$this->createHeader(array(1, 'Plugin', 1), self::PLUGIN_URI)
);
}
/**
* Send header string to the client
*
* @param string $header
* @param string $content
*/
protected function sendHeader($header, $content)
{
if (!headers_sent() && self::$sendHeaders) {
header(sprintf('%s: %s', $header, $content));
}
}
/**
* Creates & sends header for a record, ensuring init headers have been sent prior
*
* @see sendHeader()
* @see sendInitHeaders()
* @param array $record
*/
protected function write(array $record)
{
if (!self::$sendHeaders) {
return;
}
// WildFire-specific headers must be sent prior to any messages
if (!self::$initialized) {
self::$initialized = true;
self::$sendHeaders = $this->headersAccepted();
if (!self::$sendHeaders) {
return;
}
foreach ($this->getInitHeaders() as $header => $content) {
$this->sendHeader($header, $content);
}
}
$header = $this->createRecordHeader($record);
if (trim(current($header)) !== '') {
$this->sendHeader(key($header), current($header));
}
}
/**
* Verifies if the headers are accepted by the current user agent
*
* @return Boolean
*/
protected function headersAccepted()
{
if (!empty($_SERVER['HTTP_USER_AGENT']) && preg_match('{\bFirePHP/\d+\.\d+\b}', $_SERVER['HTTP_USER_AGENT'])) {
return true;
}
return isset($_SERVER['HTTP_X_FIREPHP_VERSION']);
}
/**
* BC getter for the sendHeaders property that has been made static
*/
public function __get($property)
{
if ('sendHeaders' !== $property) {
throw new \InvalidArgumentException('Undefined property '.$property);
}
return static::$sendHeaders;
}
/**
* BC setter for the sendHeaders property that has been made static
*/
public function __set($property, $value)
{
if ('sendHeaders' !== $property) {
throw new \InvalidArgumentException('Undefined property '.$property);
}
static::$sendHeaders = $value;
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Formatter\LineFormatter;
use Monolog\Logger;
/**
* Sends logs to Fleep.io using Webhook integrations
*
* You'll need a Fleep.io account to use this handler.
*
* @see https://fleep.io/integrations/webhooks/ Fleep Webhooks Documentation
* @author Ando Roots <ando@sqroot.eu>
*/
class FleepHookHandler extends SocketHandler
{
const FLEEP_HOST = 'fleep.io';
const FLEEP_HOOK_URI = '/hook/';
/**
* @var string Webhook token (specifies the conversation where logs are sent)
*/
protected $token;
/**
* Construct a new Fleep.io Handler.
*
* For instructions on how to create a new web hook in your conversations
* see https://fleep.io/integrations/webhooks/
*
* @param string $token Webhook token
* @param bool|int $level The minimum logging level at which this handler will be triggered
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
* @throws MissingExtensionException
*/
public function __construct($token, $level = Logger::DEBUG, $bubble = true)
{
if (!extension_loaded('openssl')) {
throw new MissingExtensionException('The OpenSSL PHP extension is required to use the FleepHookHandler');
}
$this->token = $token;
$connectionString = 'ssl://' . self::FLEEP_HOST . ':443';
parent::__construct($connectionString, $level, $bubble);
}
/**
* Returns the default formatter to use with this handler
*
* Overloaded to remove empty context and extra arrays from the end of the log message.
*
* @return LineFormatter
*/
protected function getDefaultFormatter()
{
return new LineFormatter(null, null, true, true);
}
/**
* Handles a log record
*
* @param array $record
*/
public function write(array $record)
{
parent::write($record);
$this->closeSocket();
}
/**
* {@inheritdoc}
*
* @param array $record
* @return string
*/
protected function generateDataStream($record)
{
$content = $this->buildContent($record);
return $this->buildHeader($content) . $content;
}
/**
* Builds the header of the API Call
*
* @param string $content
* @return string
*/
private function buildHeader($content)
{
$header = "POST " . self::FLEEP_HOOK_URI . $this->token . " HTTP/1.1\r\n";
$header .= "Host: " . self::FLEEP_HOST . "\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($content) . "\r\n";
$header .= "\r\n";
return $header;
}
/**
* Builds the body of API call
*
* @param array $record
* @return string
*/
private function buildContent($record)
{
$dataArray = array(
'message' => $record['formatted']
);
return http_build_query($dataArray);
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Logger;
use Monolog\Formatter\FlowdockFormatter;
use Monolog\Formatter\FormatterInterface;
/**
* Sends notifications through the Flowdock push API
*
* This must be configured with a FlowdockFormatter instance via setFormatter()
*
* Notes:
* API token - Flowdock API token
*
* @author Dominik Liebler <liebler.dominik@gmail.com>
* @see https://www.flowdock.com/api/push
*/
class FlowdockHandler extends SocketHandler
{
/**
* @var string
*/
protected $apiToken;
/**
* @param string $apiToken
* @param bool|int $level The minimum logging level at which this handler will be triggered
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
*
* @throws MissingExtensionException if OpenSSL is missing
*/
public function __construct($apiToken, $level = Logger::DEBUG, $bubble = true)
{
if (!extension_loaded('openssl')) {
throw new MissingExtensionException('The OpenSSL PHP extension is required to use the FlowdockHandler');
}
parent::__construct('ssl://api.flowdock.com:443', $level, $bubble);
$this->apiToken = $apiToken;
}
/**
* {@inheritdoc}
*/
public function setFormatter(FormatterInterface $formatter)
{
if (!$formatter instanceof FlowdockFormatter) {
throw new \InvalidArgumentException('The FlowdockHandler requires an instance of Monolog\Formatter\FlowdockFormatter to function correctly');
}
return parent::setFormatter($formatter);
}
/**
* Gets the default formatter.
*
* @return FormatterInterface
*/
protected function getDefaultFormatter()
{
throw new \InvalidArgumentException('The FlowdockHandler must be configured (via setFormatter) with an instance of Monolog\Formatter\FlowdockFormatter to function correctly');
}
/**
* {@inheritdoc}
*
* @param array $record
*/
protected function write(array $record)
{
parent::write($record);
$this->closeSocket();
}
/**
* {@inheritdoc}
*
* @param array $record
* @return string
*/
protected function generateDataStream($record)
{
$content = $this->buildContent($record);
return $this->buildHeader($content) . $content;
}
/**
* Builds the body of API call
*
* @param array $record
* @return string
*/
private function buildContent($record)
{
return json_encode($record['formatted']['flowdock']);
}
/**
* Builds the header of the API Call
*
* @param string $content
* @return string
*/
private function buildHeader($content)
{
$header = "POST /v1/messages/team_inbox/" . $this->apiToken . " HTTP/1.1\r\n";
$header .= "Host: api.flowdock.com\r\n";
$header .= "Content-Type: application/json\r\n";
$header .= "Content-Length: " . strlen($content) . "\r\n";
$header .= "\r\n";
return $header;
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Gelf\IMessagePublisher;
use Gelf\PublisherInterface;
use Gelf\Publisher;
use InvalidArgumentException;
use Monolog\Logger;
use Monolog\Formatter\GelfMessageFormatter;
/**
* Handler to send messages to a Graylog2 (http://www.graylog2.org) server
*
* @author Matt Lehner <mlehner@gmail.com>
* @author Benjamin Zikarsky <benjamin@zikarsky.de>
*/
class GelfHandler extends AbstractProcessingHandler
{
/**
* @var Publisher the publisher object that sends the message to the server
*/
protected $publisher;
/**
* @param PublisherInterface|IMessagePublisher|Publisher $publisher a publisher object
* @param integer $level The minimum logging level at which this handler will be triggered
* @param boolean $bubble Whether the messages that are handled can bubble up the stack or not
*/
public function __construct($publisher, $level = Logger::DEBUG, $bubble = true)
{
parent::__construct($level, $bubble);
if (!$publisher instanceof Publisher && !$publisher instanceof IMessagePublisher && !$publisher instanceof PublisherInterface) {
throw new InvalidArgumentException("Invalid publisher, expected a Gelf\Publisher, Gelf\IMessagePublisher or Gelf\PublisherInterface instance");
}
$this->publisher = $publisher;
}
/**
* {@inheritdoc}
*/
public function close()
{
$this->publisher = null;
}
/**
* {@inheritdoc}
*/
protected function write(array $record)
{
$this->publisher->publish($record['formatted']);
}
/**
* {@inheritDoc}
*/
protected function getDefaultFormatter()
{
return new GelfMessageFormatter();
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
/**
* Forwards records to multiple handlers
*
* @author Lenar Lõhmus <lenar@city.ee>
*/
class GroupHandler extends AbstractHandler
{
protected $handlers;
/**
* @param array $handlers Array of Handlers.
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
*/
public function __construct(array $handlers, $bubble = true)
{
foreach ($handlers as $handler) {
if (!$handler instanceof HandlerInterface) {
throw new \InvalidArgumentException('The first argument of the GroupHandler must be an array of HandlerInterface instances.');
}
}
$this->handlers = $handlers;
$this->bubble = $bubble;
}
/**
* {@inheritdoc}
*/
public function isHandling(array $record)
{
foreach ($this->handlers as $handler) {
if ($handler->isHandling($record)) {
return true;
}
}
return false;
}
/**
* {@inheritdoc}
*/
public function handle(array $record)
{
if ($this->processors) {
foreach ($this->processors as $processor) {
$record = call_user_func($processor, $record);
}
}
foreach ($this->handlers as $handler) {
$handler->handle($record);
}
return false === $this->bubble;
}
/**
* {@inheritdoc}
*/
public function handleBatch(array $records)
{
foreach ($this->handlers as $handler) {
$handler->handleBatch($records);
}
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Formatter\FormatterInterface;
/**
* Interface that all Monolog Handlers must implement
*
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
interface HandlerInterface
{
/**
* Checks whether the given record will be handled by this handler.
*
* This is mostly done for performance reasons, to avoid calling processors for nothing.
*
* Handlers should still check the record levels within handle(), returning false in isHandling()
* is no guarantee that handle() will not be called, and isHandling() might not be called
* for a given record.
*
* @param array $record Partial log record containing only a level key
*
* @return Boolean
*/
public function isHandling(array $record);
/**
* Handles a record.
*
* All records may be passed to this method, and the handler should discard
* those that it does not want to handle.
*
* The return value of this function controls the bubbling process of the handler stack.
* Unless the bubbling is interrupted (by returning true), the Logger class will keep on
* calling further handlers in the stack with a given log record.
*
* @param array $record The record to handle
* @return Boolean true means that this handler handled the record, and that bubbling is not permitted.
* false means the record was either not processed or that this handler allows bubbling.
*/
public function handle(array $record);
/**
* Handles a set of records at once.
*
* @param array $records The records to handle (an array of record arrays)
*/
public function handleBatch(array $records);
/**
* Adds a processor in the stack.
*
* @param callable $callback
* @return self
*/
public function pushProcessor($callback);
/**
* Removes the processor on top of the stack and returns it.
*
* @return callable
*/
public function popProcessor();
/**
* Sets the formatter.
*
* @param FormatterInterface $formatter
* @return self
*/
public function setFormatter(FormatterInterface $formatter);
/**
* Gets the formatter.
*
* @return FormatterInterface
*/
public function getFormatter();
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Logger;
/**
* Sends notifications through the hipchat api to a hipchat room
*
* Notes:
* API token - HipChat API token
* Room - HipChat Room Id or name, where messages are sent
* Name - Name used to send the message (from)
* notify - Should the message trigger a notification in the clients
* version - The API version to use (HipChatHandler::API_V1 | HipChatHandler::API_V2)
*
* @author Rafael Dohms <rafael@doh.ms>
* @see https://www.hipchat.com/docs/api
*/
class HipChatHandler extends SocketHandler
{
/**
* Use API version 1
*/
const API_V1 = 'v1';
/**
* Use API version v2
*/
const API_V2 = 'v2';
/**
* The maximum allowed length for the name used in the "from" field.
*/
const MAXIMUM_NAME_LENGTH = 15;
/**
* The maximum allowed length for the message.
*/
const MAXIMUM_MESSAGE_LENGTH = 9500;
/**
* @var string
*/
private $token;
/**
* @var string
*/
private $room;
/**
* @var string
*/
private $name;
/**
* @var bool
*/
private $notify;
/**
* @var string
*/
private $format;
/**
* @var string
*/
private $host;
/**
* @var string
*/
private $version;
/**
* @param string $token HipChat API Token
* @param string $room The room that should be alerted of the message (Id or Name)
* @param string $name Name used in the "from" field. Not used for v2
* @param bool $notify Trigger a notification in clients or not
* @param int $level The minimum logging level at which this handler will be triggered
* @param bool $bubble Whether the messages that are handled can bubble up the stack or not
* @param bool $useSSL Whether to connect via SSL.
* @param string $format The format of the messages (default to text, can be set to html if you have html in the messages)
* @param string $host The HipChat server hostname.
* @param string $version The HipChat API version (default HipChatHandler::API_V1)
*/
public function __construct($token, $room, $name = 'Monolog', $notify = false, $level = Logger::CRITICAL, $bubble = true, $useSSL = true, $format = 'text', $host = 'api.hipchat.com', $version = self::API_V1)
{
if ($version == self::API_V1 && !$this->validateStringLength($name, static::MAXIMUM_NAME_LENGTH)) {
throw new \InvalidArgumentException('The supplied name is too long. HipChat\'s v1 API supports names up to 15 UTF-8 characters.');
}
$connectionString = $useSSL ? 'ssl://'.$host.':443' : $host.':80';
parent::__construct($connectionString, $level, $bubble);
$this->token = $token;
$this->name = $name;
$this->notify = $notify;
$this->room = $room;
$this->format = $format;
$this->host = $host;
$this->version = $version;
}
/**
* {@inheritdoc}
*
* @param array $record
* @return string
*/
protected function generateDataStream($record)
{
$content = $this->buildContent($record);
return $this->buildHeader($content) . $content;
}
/**
* Builds the body of API call
*
* @param array $record
* @return string
*/
private function buildContent($record)
{
$dataArray = array(
'notify' => $this->version == self::API_V1 ?
($this->notify ? 1 : 0) :
($this->notify ? 'true' : 'false'),
'message' => $record['formatted'],
'message_format' => $this->format,
'color' => $this->getAlertColor($record['level']),
);
// if we are using the legacy API then we need to send some additional information
if ($this->version == self::API_V1) {
$dataArray['room_id'] = $this->room;
$dataArray['from'] = $this->name;
}
return http_build_query($dataArray);
}
/**
* Builds the header of the API Call
*
* @param string $content
* @return string
*/
private function buildHeader($content)
{
if ($this->version == self::API_V1) {
$header = "POST /v1/rooms/message?format=json&auth_token={$this->token} HTTP/1.1\r\n";
} else {
// needed for rooms with special (spaces, etc) characters in the name
$room = rawurlencode($this->room);
$header = "POST /v2/room/{$room}/notification?auth_token={$this->token} HTTP/1.1\r\n";
}
$header .= "Host: {$this->host}\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($content) . "\r\n";
$header .= "\r\n";
return $header;
}
/**
* Assigns a color to each level of log records.
*
* @param integer $level
* @return string
*/
protected function getAlertColor($level)
{
switch (true) {
case $level >= Logger::ERROR:
return 'red';
case $level >= Logger::WARNING:
return 'yellow';
case $level >= Logger::INFO:
return 'green';
case $level == Logger::DEBUG:
return 'gray';
default:
return 'yellow';
}
}
/**
* {@inheritdoc}
*
* @param array $record
*/
protected function write(array $record)
{
parent::write($record);
$this->closeSocket();
}
/**
* {@inheritdoc}
*/
public function handleBatch(array $records)
{
if (count($records) == 0) {
return true;
}
$batchRecords = $this->combineRecords($records);
$handled = false;
foreach ($batchRecords as $batchRecord) {
if ($this->isHandling($batchRecord)) {
$this->write($batchRecord);
$handled = true;
}
}
if (!$handled) {
return false;
}
return false === $this->bubble;
}
/**
* Combines multiple records into one. Error level of the combined record
* will be the highest level from the given records. Datetime will be taken
* from the first record.
*
* @param $records
* @return array
*/
private function combineRecords($records)
{
$batchRecord = null;
$batchRecords = array();
$messages = array();
$formattedMessages = array();
$level = 0;
$levelName = null;
$datetime = null;
foreach ($records as $record) {
$record = $this->processRecord($record);
if ($record['level'] > $level) {
$level = $record['level'];
$levelName = $record['level_name'];
}
if (null === $datetime) {
$datetime = $record['datetime'];
}
$messages[] = $record['message'];
$messageStr = implode(PHP_EOL, $messages);
$formattedMessages[] = $this->getFormatter()->format($record);
$formattedMessageStr = implode('', $formattedMessages);
$batchRecord = array(
'message' => $messageStr,
'formatted' => $formattedMessageStr,
'context' => array(),
'extra' => array(),
);
if (!$this->validateStringLength($batchRecord['formatted'], static::MAXIMUM_MESSAGE_LENGTH)) {
// Pop the last message and implode the remaining messages
$lastMessage = array_pop($messages);
$lastFormattedMessage = array_pop($formattedMessages);
$batchRecord['message'] = implode(PHP_EOL, $messages);
$batchRecord['formatted'] = implode('', $formattedMessages);
$batchRecords[] = $batchRecord;
$messages = array($lastMessage);
$formattedMessages = array($lastFormattedMessage);
$batchRecord = null;
}
}
if (null !== $batchRecord) {
$batchRecords[] = $batchRecord;
}
// Set the max level and datetime for all records
foreach ($batchRecords as &$batchRecord) {
$batchRecord = array_merge(
$batchRecord,
array(
'level' => $level,
'level_name' => $levelName,
'datetime' => $datetime
)
);
}
return $batchRecords;
}
/**
* Validates the length of a string.
*
* If the `mb_strlen()` function is available, it will use that, as HipChat
* allows UTF-8 characters. Otherwise, it will fall back to `strlen()`.
*
* Note that this might cause false failures in the specific case of using
* a valid name with less than 16 characters, but 16 or more bytes, on a
* system where `mb_strlen()` is unavailable.
*
* @param string $str
* @param int $length
*
* @return bool
*/
private function validateStringLength($str, $length)
{
if (function_exists('mb_strlen')) {
return (mb_strlen($str) <= $length);
}
return (strlen($str) <= $length);
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Logger;
/**
* IFTTTHandler uses cURL to trigger IFTTT Maker actions
*
* Register a secret key and trigger/event name at https://ifttt.com/maker
*
* value1 will be the channel from monolog's Logger constructor,
* value2 will be the level name (ERROR, WARNING, ..)
* value3 will be the log record's message
*
* @author Nehal Patel <nehal@nehalpatel.me>
*/
class IFTTTHandler extends AbstractProcessingHandler
{
private $eventName;
private $secretKey;
/**
* @param string $eventName The name of the IFTTT Maker event that should be triggered
* @param string $secretKey A valid IFTTT secret key
* @param integer $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
*/
public function __construct($eventName, $secretKey, $level = Logger::ERROR, $bubble = true)
{
$this->eventName = $eventName;
$this->secretKey = $secretKey;
parent::__construct($level, $bubble);
}
/**
* {@inheritdoc}
*/
public function write(array $record)
{
$postData = array(
"value1" => $record["channel"],
"value2" => $record["level_name"],
"value3" => $record["message"]
);
$postString = json_encode($postData);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "https://maker.ifttt.com/trigger/" . $this->eventName . "/with/key/" . $this->secretKey);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $postString);
curl_setopt($ch, CURLOPT_HTTPHEADER, array(
"Content-Type: application/json"
));
Curl\Util::execute($ch);
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Logger;
/**
* @author Robert Kaufmann III <rok3@rok3.me>
*/
class LogEntriesHandler extends SocketHandler
{
/**
* @var string
*/
protected $logToken;
/**
* @param string $token Log token supplied by LogEntries
* @param boolean $useSSL Whether or not SSL encryption should be used.
* @param int $level The minimum logging level to trigger this handler
* @param boolean $bubble Whether or not messages that are handled should bubble up the stack.
*
* @throws MissingExtensionException If SSL encryption is set to true and OpenSSL is missing
*/
public function __construct($token, $useSSL = true, $level = Logger::DEBUG, $bubble = true)
{
if ($useSSL && !extension_loaded('openssl')) {
throw new MissingExtensionException('The OpenSSL PHP plugin is required to use SSL encrypted connection for LogEntriesHandler');
}
$endpoint = $useSSL ? 'ssl://data.logentries.com:443' : 'data.logentries.com:80';
parent::__construct($endpoint, $level, $bubble);
$this->logToken = $token;
}
/**
* {@inheritdoc}
*
* @param array $record
* @return string
*/
protected function generateDataStream($record)
{
return $this->logToken . ' ' . $record['formatted'];
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Logger;
use Monolog\Formatter\LogglyFormatter;
/**
* Sends errors to Loggly.
*
* @author Przemek Sobstel <przemek@sobstel.org>
* @author Adam Pancutt <adam@pancutt.com>
* @author Gregory Barchard <gregory@barchard.net>
*/
class LogglyHandler extends AbstractProcessingHandler
{
const HOST = 'logs-01.loggly.com';
const ENDPOINT_SINGLE = 'inputs';
const ENDPOINT_BATCH = 'bulk';
protected $token;
protected $tag = array();
public function __construct($token, $level = Logger::DEBUG, $bubble = true)
{
if (!extension_loaded('curl')) {
throw new \LogicException('The curl extension is needed to use the LogglyHandler');
}
$this->token = $token;
parent::__construct($level, $bubble);
}
public function setTag($tag)
{
$tag = !empty($tag) ? $tag : array();
$this->tag = is_array($tag) ? $tag : array($tag);
}
public function addTag($tag)
{
if (!empty($tag)) {
$tag = is_array($tag) ? $tag : array($tag);
$this->tag = array_unique(array_merge($this->tag, $tag));
}
}
protected function write(array $record)
{
$this->send($record["formatted"], self::ENDPOINT_SINGLE);
}
public function handleBatch(array $records)
{
$level = $this->level;
$records = array_filter($records, function ($record) use ($level) {
return ($record['level'] >= $level);
});
if ($records) {
$this->send($this->getFormatter()->formatBatch($records), self::ENDPOINT_BATCH);
}
}
protected function send($data, $endpoint)
{
$url = sprintf("https://%s/%s/%s/", self::HOST, $endpoint, $this->token);
$headers = array('Content-Type: application/json');
if (!empty($this->tag)) {
$headers[] = 'X-LOGGLY-TAG: '.implode(',', $this->tag);
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
Curl\Util::execute($ch);
}
protected function getDefaultFormatter()
{
return new LogglyFormatter();
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
/**
* Base class for all mail handlers
*
* @author Gyula Sallai
*/
abstract class MailHandler extends AbstractProcessingHandler
{
/**
* {@inheritdoc}
*/
public function handleBatch(array $records)
{
$messages = array();
foreach ($records as $record) {
if ($record['level'] < $this->level) {
continue;
}
$messages[] = $this->processRecord($record);
}
if (!empty($messages)) {
$this->send((string) $this->getFormatter()->formatBatch($messages), $messages);
}
}
/**
* Send a mail with the given content
*
* @param string $content formatted email body to be sent
* @param array $records the array of log records that formed this content
*/
abstract protected function send($content, array $records);
/**
* {@inheritdoc}
*/
protected function write(array $record)
{
$this->send((string) $record['formatted'], array($record));
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Logger;
/**
* MandrillHandler uses cURL to send the emails to the Mandrill API
*
* @author Adam Nicholson <adamnicholson10@gmail.com>
*/
class MandrillHandler extends MailHandler
{
protected $message;
protected $apiKey;
/**
* @param string $apiKey A valid Mandrill API key
* @param callable|\Swift_Message $message An example message for real messages, only the body will be replaced
* @param integer $level The minimum logging level at which this handler will be triggered
* @param Boolean $bubble Whether the messages that are handled can bubble up the stack or not
*/
public function __construct($apiKey, $message, $level = Logger::ERROR, $bubble = true)
{
parent::__construct($level, $bubble);
if (!$message instanceof \Swift_Message && is_callable($message)) {
$message = call_user_func($message);
}
if (!$message instanceof \Swift_Message) {
throw new \InvalidArgumentException('You must provide either a Swift_Message instance or a callable returning it');
}
$this->message = $message;
$this->apiKey = $apiKey;
}
/**
* {@inheritdoc}
*/
protected function send($content, array $records)
{
$message = clone $this->message;
$message->setBody($content);
$message->setDate(time());
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://mandrillapp.com/api/1.0/messages/send-raw.json');
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_POSTFIELDS, http_build_query(array(
'key' => $this->apiKey,
'raw_message' => (string) $message,
'async' => false,
)));
Curl\Util::execute($ch);
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
/**
* Exception can be thrown if an extension for an handler is missing
*
* @author Christian Bergau <cbergau86@gmail.com>
*/
class MissingExtensionException extends \Exception
{
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Logger;
use Monolog\Formatter\NormalizerFormatter;
/**
* Logs to a MongoDB database.
*
* usage example:
*
* $log = new Logger('application');
* $mongodb = new MongoDBHandler(new \Mongo("mongodb://localhost:27017"), "logs", "prod");
* $log->pushHandler($mongodb);
*
* @author Thomas Tourlourat <thomas@tourlourat.com>
*/
class MongoDBHandler extends AbstractProcessingHandler
{
protected $mongoCollection;
public function __construct($mongo, $database, $collection, $level = Logger::DEBUG, $bubble = true)
{
if (!($mongo instanceof \MongoClient || $mongo instanceof \Mongo)) {
throw new \InvalidArgumentException('MongoClient or Mongo instance required');
}
$this->mongoCollection = $mongo->selectCollection($database, $collection);
parent::__construct($level, $bubble);
}
protected function write(array $record)
{
$this->mongoCollection->save($record["formatted"]);
}
/**
* {@inheritDoc}
*/
protected function getDefaultFormatter()
{
return new NormalizerFormatter();
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Logger;
/**
* NativeMailerHandler uses the mail() function to send the emails
*
* @author Christophe Coevoet <stof@notk.org>
* @author Mark Garrett <mark@moderndeveloperllc.com>
*/
class NativeMailerHandler extends MailHandler
{
/**
* The email addresses to which the message will be sent
* @var array
*/
protected $to;
/**
* The subject of the email
* @var string
*/
protected $subject;
/**
* Optional headers for the message
* @var array
*/
protected $headers = array();
/**
* Optional parameters for the message
* @var array
*/
protected $parameters = array();
/**
* The wordwrap length for the message
* @var integer
*/
protected $maxColumnWidth;
/**
* The Content-type for the message
* @var string
*/
protected $contentType = 'text/plain';
/**
* The encoding for the message
* @var string
*/
protected $encoding = 'utf-8';
/**
* @param string|array $to The receiver of the mail
* @param string $subject The subject of the mail
* @param string $from The sender of the mail
* @param integer $level The minimum logging level at which this handler will be triggered
* @param boolean $bubble Whether the messages that are handled can bubble up the stack or not
* @param int $maxColumnWidth The maximum column width that the message lines will have
*/
public function __construct($to, $subject, $from, $level = Logger::ERROR, $bubble = true, $maxColumnWidth = 70)
{
parent::__construct($level, $bubble);
$this->to = is_array($to) ? $to : array($to);
$this->subject = $subject;
$this->addHeader(sprintf('From: %s', $from));
$this->maxColumnWidth = $maxColumnWidth;
}
/**
* Add headers to the message
*
* @param string|array $headers Custom added headers
* @return self
*/
public function addHeader($headers)
{
foreach ((array) $headers as $header) {
if (strpos($header, "\n") !== false || strpos($header, "\r") !== false) {
throw new \InvalidArgumentException('Headers can not contain newline characters for security reasons');
}
$this->headers[] = $header;
}
return $this;
}
/**
* Add parameters to the message
*
* @param string|array $parameters Custom added parameters
* @return self
*/
public function addParameter($parameters)
{
$this->parameters = array_merge($this->parameters, (array) $parameters);
return $this;
}
/**
* {@inheritdoc}
*/
protected function send($content, array $records)
{
$content = wordwrap($content, $this->maxColumnWidth);
$headers = ltrim(implode("\r\n", $this->headers) . "\r\n", "\r\n");
$headers .= 'Content-type: ' . $this->getContentType() . '; charset=' . $this->getEncoding() . "\r\n";
if ($this->getContentType() == 'text/html' && false === strpos($headers, 'MIME-Version:')) {
$headers .= 'MIME-Version: 1.0' . "\r\n";
}
foreach ($this->to as $to) {
mail($to, $this->subject, $content, $headers, implode(' ', $this->parameters));
}
}
/**
* @return string $contentType
*/
public function getContentType()
{
return $this->contentType;
}
/**
* @return string $encoding
*/
public function getEncoding()
{
return $this->encoding;
}
/**
* @param string $contentType The content type of the email - Defaults to text/plain. Use text/html for HTML
* messages.
* @return self
*/
public function setContentType($contentType)
{
if (strpos($contentType, "\n") !== false || strpos($contentType, "\r") !== false) {
throw new \InvalidArgumentException('The content type can not contain newline characters to prevent email header injection');
}
$this->contentType = $contentType;
return $this;
}
/**
* @param string $encoding
* @return self
*/
public function setEncoding($encoding)
{
if (strpos($encoding, "\n") !== false || strpos($encoding, "\r") !== false) {
throw new \InvalidArgumentException('The encoding can not contain newline characters to prevent email header injection');
}
$this->encoding = $encoding;
return $this;
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Logger;
use Monolog\Formatter\NormalizerFormatter;
/**
* Class to record a log on a NewRelic application.
* Enabling New Relic High Security mode may prevent capture of useful information.
*
* @see https://docs.newrelic.com/docs/agents/php-agent
* @see https://docs.newrelic.com/docs/accounts-partnerships/accounts/security/high-security
*/
class NewRelicHandler extends AbstractProcessingHandler
{
/**
* Name of the New Relic application that will receive logs from this handler.
*
* @var string
*/
protected $appName;
/**
* Name of the current transaction
*
* @var string
*/
protected $transactionName;
/**
* Some context and extra data is passed into the handler as arrays of values. Do we send them as is
* (useful if we are using the API), or explode them for display on the NewRelic RPM website?
*
* @var boolean
*/
protected $explodeArrays;
/**
* {@inheritDoc}
*
* @param string $appName
* @param boolean $explodeArrays
* @param string $transactionName
*/
public function __construct(
$level = Logger::ERROR,
$bubble = true,
$appName = null,
$explodeArrays = false,
$transactionName = null
) {
parent::__construct($level, $bubble);
$this->appName = $appName;
$this->explodeArrays = $explodeArrays;
$this->transactionName = $transactionName;
}
/**
* {@inheritDoc}
*/
protected function write(array $record)
{
if (!$this->isNewRelicEnabled()) {
throw new MissingExtensionException('The newrelic PHP extension is required to use the NewRelicHandler');
}
if ($appName = $this->getAppName($record['context'])) {
$this->setNewRelicAppName($appName);
}
if ($transactionName = $this->getTransactionName($record['context'])) {
$this->setNewRelicTransactionName($transactionName);
unset($record['formatted']['context']['transaction_name']);
}
if (isset($record['context']['exception']) && $record['context']['exception'] instanceof \Exception) {
newrelic_notice_error($record['message'], $record['context']['exception']);
unset($record['formatted']['context']['exception']);
} else {
newrelic_notice_error($record['message']);
}
foreach ($record['formatted']['context'] as $key => $parameter) {
if (is_array($parameter) && $this->explodeArrays) {
foreach ($parameter as $paramKey => $paramValue) {
$this->setNewRelicParameter('context_' . $key . '_' . $paramKey, $paramValue);
}
} else {
$this->setNewRelicParameter('context_' . $key, $parameter);
}
}
foreach ($record['formatted']['extra'] as $key => $parameter) {
if (is_array($parameter) && $this->explodeArrays) {
foreach ($parameter as $paramKey => $paramValue) {
$this->setNewRelicParameter('extra_' . $key . '_' . $paramKey, $paramValue);
}
} else {
$this->setNewRelicParameter('extra_' . $key, $parameter);
}
}
}
/**
* Checks whether the NewRelic extension is enabled in the system.
*
* @return bool
*/
protected function isNewRelicEnabled()
{
return extension_loaded('newrelic');
}
/**
* Returns the appname where this log should be sent. Each log can override the default appname, set in this
* handler's constructor, by providing the appname in it's context.
*
* @param array $context
* @return null|string
*/
protected function getAppName(array $context)
{
if (isset($context['appname'])) {
return $context['appname'];
}
return $this->appName;
}
/**
* Returns the name of the current transaction. Each log can override the default transaction name, set in this
* handler's constructor, by providing the transaction_name in it's context
*
* @param array $context
*
* @return null|string
*/
protected function getTransactionName(array $context)
{
if (isset($context['transaction_name'])) {
return $context['transaction_name'];
}
return $this->transactionName;
}
/**
* Sets the NewRelic application that should receive this log.
*
* @param string $appName
*/
protected function setNewRelicAppName($appName)
{
newrelic_set_appname($appName);
}
/**
* Overwrites the name of the current transaction
*
* @param string $transactionName
*/
protected function setNewRelicTransactionName($transactionName)
{
newrelic_name_transaction($transactionName);
}
/**
* @param string $key
* @param mixed $value
*/
protected function setNewRelicParameter($key, $value)
{
if (null === $value || is_scalar($value)) {
newrelic_add_custom_parameter($key, $value);
} else {
newrelic_add_custom_parameter($key, @json_encode($value));
}
}
/**
* {@inheritDoc}
*/
protected function getDefaultFormatter()
{
return new NormalizerFormatter();
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Monolog\Logger;
/**
* Blackhole
*
* Any record it can handle will be thrown away. This can be used
* to put on top of an existing stack to override it temporarily.
*
* @author Jordi Boggiano <j.boggiano@seld.be>
*/
class NullHandler extends AbstractHandler
{
/**
* @param integer $level The minimum logging level at which this handler will be triggered
*/
public function __construct($level = Logger::DEBUG)
{
parent::__construct($level, false);
}
/**
* {@inheritdoc}
*/
public function handle(array $record)
{
if ($record['level'] < $this->level) {
return false;
}
return true;
}
}
<?php
/*
* This file is part of the Monolog package.
*
* (c) Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Monolog\Handler;
use Exception;
use Monolog\Formatter\LineFormatter;
use Monolog\Logger;
use PhpConsole\Connector;
use PhpConsole\Handler;
use PhpConsole\Helper;
/**
* Monolog handler for Google Chrome extension "PHP Console"
*
* Display PHP error/debug log messages in Google Chrome console and notification popups, executes PHP code remotely
*
* Usage:
* 1. Install Google Chrome extension https://chrome.google.com/webstore/detail/php-console/nfhmhhlpfleoednkpnnnkolmclajemef
* 2. See overview https://github.com/barbushin/php-console#overview
* 3. Install PHP Console library https://github.com/barbushin/php-console#installation
* 4. Example (result will looks like http://i.hizliresim.com/vg3Pz4.png)
*
* $logger = new \Monolog\Logger('all', array(new \Monolog\Handler\PHPConsoleHandler()));
* \Monolog\ErrorHandler::register($logger);
* echo $undefinedVar;
* $logger->addDebug('SELECT * FROM users', array('db', 'time' => 0.012));
* PC::debug($_SERVER); // PHP Console debugger for any type of vars
*
* @author Sergey Barbushin https://www.linkedin.com/in/barbushin
*/
class PHPConsoleHandler extends AbstractProcessingHandler
{
private $options = array(
'enabled' => true, // bool Is PHP Console server enabled
'classesPartialsTraceIgnore' => array('Monolog\\'), // array Hide calls of classes started with...
'debugTagsKeysInContext' => array(0, 'tag'), // bool Is PHP Console server enabled
'useOwnErrorsHandler' => false, // bool Enable errors handling
'useOwnExceptionsHandler' => false, // bool Enable exceptions handling
'sourcesBasePath' => null, // string Base path of all project sources to strip in errors source paths
'registerHelper' => true, // bool Register PhpConsole\Helper that allows short debug calls like PC::debug($var, 'ta.g.s')
'serverEncoding' => null, // string|null Server internal encoding
'headersLimit' => null, // int|null Set headers size limit for your web-server
'password' => null, // string|null Protect PHP Console connection by password
'enableSslOnlyMode' => false, // bool Force connection by SSL for clients with PHP Console installed
'ipMasks' => array(), // array Set IP masks of clients that will be allowed to connect to PHP Console: array('192.168.*.*', '127.0.0.1')
'enableEvalListener' => false, // bool Enable eval request to be handled by eval dispatcher(if enabled, 'password' option is also required)
'dumperDetectCallbacks' => false, // bool Convert callback items in dumper vars to (callback SomeClass::someMethod) strings
'dumperLevelLimit' => 5, // int Maximum dumped vars array or object nested dump level
'dumperItemsCountLimit' => 100, // int Maximum dumped var same level array items or object properties number
'dumperItemSizeLimit' => 5000, // int Maximum length of any string or dumped array item
'dumperDumpSizeLimit' => 500000, // int Maximum approximate size of dumped vars result formatted in JSON
'detectDumpTraceAndSource' => false, // bool Autodetect and append trace data to debug
'dataStorage' => null, // PhpConsole\Storage|null Fixes problem with custom $_SESSION handler(see http://goo.gl/Ne8juJ)
);
/** @var Connector */
private $connector;
/**
* @param array $options See \Monolog\Handler\PHPConsoleHandler::$options for more details
* @param Connector|null $connector Instance of \PhpConsole\Connector class (optional)
* @param int $level
* @param bool $bubble
* @throws Exception
*/
public function __construct(array $options = array(), Connector $connector = null, $level = Logger::DEBUG, $bubble = true)
{
if (!class_exists('PhpConsole\Connector')) {
throw new Exception('PHP Console library not found. See https://github.com/barbushin/php-console#installation');
}
parent::__construct($level, $bubble);
$this->options = $this->initOptions($options);
$this->connector = $this->initConnector($connector);
}
private function initOptions(array $options)
{
$wrongOptions = array_diff(array_keys($options), array_keys($this->options));
if ($wrongOptions) {
throw new Exception('Unknown options: ' . implode(', ', $wrongOptions));
}
return array_replace($this->options, $options);
}
private function initConnector(Connector $connector = null)
{
if (!$connector) {
if ($this->options['dataStorage']) {
Connector::setPostponeStorage($this->options['dataStorage']);
}
$connector = Connector::getInstance();
}
if ($this->options['registerHelper'] && !Helper::isRegistered()) {
Helper::register();
}
if ($this->options['enabled'] && $connector->isActiveClient()) {
if ($this->options['useOwnErrorsHandler'] || $this->options['useOwnExceptionsHandler']) {
$handler = Handler::getInstance();
$handler->setHandleErrors($this->options['useOwnErrorsHandler']);
$handler->setHandleExceptions($this->options['useOwnExceptionsHandler']);
$handler->start();
}
if ($this->options['sourcesBasePath']) {
$connector->setSourcesBasePath($this->options['sourcesBasePath']);
}
if ($this->options['serverEncoding']) {
$connector->setServerEncoding($this->options['serverEncoding']);
}
if ($this->options['password']) {
$connector->setPassword($this->options['password']);
}
if ($this->options['enableSslOnlyMode']) {
$connector->enableSslOnlyMode();
}
if ($this->options['ipMasks']) {
$connector->setAllowedIpMasks($this->options['ipMasks']);
}
if ($this->options['headersLimit']) {
$connector->setHeadersLimit($this->options['headersLimit']);
}
if ($this->options['detectDumpTraceAndSource']) {
$connector->getDebugDispatcher()->detectTraceAndSource = true;
}
$dumper = $connector->getDumper();
$dumper->levelLimit = $this->options['dumperLevelLimit'];
$dumper->itemsCountLimit = $this->options['dumperItemsCountLimit'];
$dumper->itemSizeLimit = $this->options['dumperItemSizeLimit'];
$dumper->dumpSizeLimit = $this->options['dumperDumpSizeLimit'];
$dumper->detectCallbacks = $this->options['dumperDetectCallbacks'];
if ($this->options['enableEvalListener']) {
$connector->startEvalRequestsListener();
}
}
return $connector;
}
public function getConnector()
{
return $this->connector;
}
public function getOptions()
{
return $this->options;
}
public function handle(array $record)
{
if ($this->options['enabled'] && $this->connector->isActiveClient()) {
return parent::handle($record);
}
return !$this->bubble;
}
/**
* Writes the record down to the log of the implementing handler
*
* @param array $record
* @return void
*/
protected function write(array $record)
{
if ($record['level'] < Logger::NOTICE) {
$this->handleDebugRecord($record);
} elseif (isset($record['context']['exception']) && $record['context']['exception'] instanceof Exception) {
$this->handleExceptionRecord($record);
} else {
$this->handleErrorRecord($record);
}
}
private function handleDebugRecord(array $record)
{
$tags = $this->getRecordTags($record);
$message = $record['message'];
if ($record['context']) {
$message .= ' ' . json_encode($this->connector->getDumper()->dump(array_filter($record['context'])));
}
$this->connector->getDebugDispatcher()->dispatchDebug($message, $tags, $this->options['classesPartialsTraceIgnore']);
}
private function handleExceptionRecord(array $record)
{
$this->connector->getErrorsDispatcher()->dispatchException($record['context']['exception']);
}
private function handleErrorRecord(array $record)
{
$context = $record['context'];
$this->connector->getErrorsDispatcher()->dispatchError(
isset($context['code']) ? $context['code'] : null,
isset($context['message']) ? $context['message'] : $record['message'],
isset($context['file']) ? $context['file'] : null,
isset($context['line']) ? $context['line'] : null,
$this->options['classesPartialsTraceIgnore']
);
}
private function getRecordTags(array &$record)
{
$tags = null;
if (!empty($record['context'])) {
$context = & $record['context'];
foreach ($this->options['debugTagsKeysInContext'] as $key) {
if (!empty($context[$key])) {
$tags = $context[$key];
if ($key === 0) {
array_shift($context);
} else {
unset($context[$key]);
}
break;
}
}
}
return $tags ?: strtolower($record['level_name']);
}
/**
* {@inheritDoc}
*/
protected function getDefaultFormatter()
{
return new LineFormatter('%message%');
}
}
View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

View raw

(Sorry about that, but we can’t show files that are this big right now.)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment