From 7cfa2eea664f068b59f8d74d8cad4063e872a0ad Mon Sep 17 00:00:00 2001
From: adamjacobbecker
Date: Mon, 17 Sep 2012 13:07:44 -0400
Subject: [PATCH] initial commit - add our laravel fork
---
application/bundles.php | 40 +
application/config/.gitignore | 1 +
application/config/application.php | 185 ++
application/config/auth.php | 73 +
application/config/cache.php | 71 +
application/config/database.php | 124 +
application/config/error.php | 69 +
application/config/mimes.php | 97 +
application/config/session.php | 117 +
application/config/strings.php | 188 ++
application/controllers/base.php | 17 +
application/controllers/home.php | 38 +
application/language/en/pagination.php | 19 +
application/language/en/validation.php | 99 +
application/language/nl/pagination.php | 8 +
application/language/nl/validation.php | 90 +
application/language/ru/pagination.php | 19 +
application/language/ru/validation.php | 99 +
application/libraries/.gitignore | 0
application/migrations/.gitignore | 0
application/models/.gitignore | 0
application/routes.php | 111 +
application/start.php | 173 +
application/tasks/.gitignore | 0
application/tests/example.test.php | 15 +
application/views/error/404.php | 125 +
application/views/error/500.php | 125 +
application/views/home/index.blade.php | 57 +
artisan | 25 +
bundles/.gitignore | 0
bundles/docs/libraries/markdown.php | 2934 +++++++++++++++++
bundles/docs/routes.php | 85 +
bundles/docs/views/page.blade.php | 5 +
bundles/docs/views/template.blade.php | 34 +
laravel/asset.php | 356 ++
laravel/auth.php | 93 +
laravel/auth/drivers/driver.php | 224 ++
laravel/auth/drivers/eloquent.php | 60 +
laravel/auth/drivers/fluent.php | 65 +
laravel/autoloader.php | 229 ++
laravel/blade.php | 453 +++
laravel/bundle.php | 464 +++
laravel/cache.php | 115 +
laravel/cache/drivers/apc.php | 89 +
laravel/cache/drivers/database.php | 125 +
laravel/cache/drivers/driver.php | 118 +
laravel/cache/drivers/file.php | 100 +
laravel/cache/drivers/memcached.php | 185 ++
laravel/cache/drivers/memory.php | 151 +
laravel/cache/drivers/redis.php | 91 +
laravel/cache/drivers/sectionable.php | 141 +
laravel/cli/artisan.php | 49 +
laravel/cli/command.php | 198 ++
laravel/cli/dependencies.php | 128 +
laravel/cli/tasks/bundle/bundler.php | 205 ++
laravel/cli/tasks/bundle/providers/github.php | 19 +
.../cli/tasks/bundle/providers/provider.php | 82 +
laravel/cli/tasks/bundle/publisher.php | 65 +
laravel/cli/tasks/bundle/repository.php | 29 +
laravel/cli/tasks/key.php | 57 +
laravel/cli/tasks/migrate/database.php | 84 +
laravel/cli/tasks/migrate/migrator.php | 245 ++
laravel/cli/tasks/migrate/resolver.php | 175 +
laravel/cli/tasks/migrate/stub.php | 25 +
laravel/cli/tasks/route.php | 56 +
laravel/cli/tasks/session/manager.php | 93 +
laravel/cli/tasks/session/migration.php | 40 +
laravel/cli/tasks/task.php | 3 +
laravel/cli/tasks/test/phpunit.php | 45 +
laravel/cli/tasks/test/runner.php | 138 +
laravel/cli/tasks/test/stub.xml | 9 +
laravel/config.php | 235 ++
laravel/cookie.php | 123 +
laravel/core.php | 229 ++
laravel/crypter.php | 166 +
laravel/database.php | 181 +
laravel/database/connection.php | 336 ++
laravel/database/connectors/connector.php | 41 +
laravel/database/connectors/mysql.php | 46 +
laravel/database/connectors/postgres.php | 50 +
laravel/database/connectors/sqlite.php | 28 +
laravel/database/connectors/sqlserver.php | 37 +
laravel/database/eloquent/model.php | 804 +++++
laravel/database/eloquent/pivot.php | 54 +
laravel/database/eloquent/query.php | 280 ++
.../eloquent/relationships/belongs_to.php | 114 +
.../eloquent/relationships/has_many.php | 105 +
.../relationships/has_many_and_belongs_to.php | 428 +++
.../eloquent/relationships/has_one.php | 52 +
.../relationships/has_one_or_many.php | 59 +
.../eloquent/relationships/relationship.php | 122 +
laravel/database/exception.php | 41 +
laravel/database/expression.php | 43 +
laravel/database/grammar.php | 174 +
laravel/database/query.php | 884 +++++
laravel/database/query/grammars/grammar.php | 464 +++
laravel/database/query/grammars/mysql.php | 12 +
laravel/database/query/grammars/postgres.php | 20 +
laravel/database/query/grammars/sqlite.php | 24 +
laravel/database/query/grammars/sqlserver.php | 140 +
laravel/database/query/join.php | 68 +
laravel/database/schema.php | 174 +
laravel/database/schema/grammars/grammar.php | 99 +
laravel/database/schema/grammars/mysql.php | 421 +++
laravel/database/schema/grammars/postgres.php | 407 +++
laravel/database/schema/grammars/sqlite.php | 351 ++
.../database/schema/grammars/sqlserver.php | 425 +++
laravel/database/schema/table.php | 417 +++
laravel/documentation/artisan/commands.md | 102 +
laravel/documentation/artisan/tasks.md | 100 +
laravel/documentation/auth/config.md | 38 +
laravel/documentation/auth/usage.md | 86 +
laravel/documentation/bundles.md | 214 ++
laravel/documentation/cache/config.md | 79 +
laravel/documentation/cache/usage.md | 59 +
laravel/documentation/changes.md | 326 ++
laravel/documentation/config.md | 34 +
laravel/documentation/contents.md | 111 +
laravel/documentation/controllers.md | 206 ++
laravel/documentation/database/config.md | 46 +
laravel/documentation/database/eloquent.md | 501 +++
laravel/documentation/database/fluent.md | 270 ++
laravel/documentation/database/migrations.md | 72 +
laravel/documentation/database/raw.md | 56 +
laravel/documentation/database/redis.md | 58 +
laravel/documentation/database/schema.md | 145 +
laravel/documentation/encryption.md | 30 +
laravel/documentation/events.md | 100 +
laravel/documentation/files.md | 84 +
laravel/documentation/home.md | 59 +
laravel/documentation/input.md | 148 +
laravel/documentation/install.md | 124 +
laravel/documentation/ioc.md | 49 +
laravel/documentation/loading.md | 58 +
laravel/documentation/localization.md | 70 +
laravel/documentation/logging.md | 40 +
laravel/documentation/models.md | 116 +
laravel/documentation/requests.md | 77 +
laravel/documentation/routing.md | 321 ++
laravel/documentation/session/config.md | 109 +
laravel/documentation/session/usage.md | 61 +
laravel/documentation/strings.md | 71 +
laravel/documentation/testing.md | 68 +
laravel/documentation/urls.md | 98 +
laravel/documentation/validation.md | 431 +++
laravel/documentation/views/assets.md | 73 +
laravel/documentation/views/forms.md | 153 +
laravel/documentation/views/home.md | 260 ++
laravel/documentation/views/html.md | 139 +
laravel/documentation/views/pagination.md | 104 +
laravel/documentation/views/templating.md | 180 +
laravel/error.php | 110 +
laravel/event.php | 220 ++
laravel/file.php | 349 ++
laravel/fluent.php | 96 +
laravel/form.php | 618 ++++
laravel/hash.php | 53 +
laravel/helpers.php | 588 ++++
laravel/html.php | 425 +++
laravel/input.php | 290 ++
laravel/ioc.php | 207 ++
laravel/lang.php | 252 ++
laravel/laravel.php | 181 +
laravel/log.php | 90 +
laravel/memcached.php | 74 +
laravel/messages.php | 194 ++
laravel/paginator.php | 423 +++
laravel/pluralizer.php | 130 +
laravel/profiling/profiler.css | 222 ++
laravel/profiling/profiler.js | 194 ++
laravel/profiling/profiler.php | 92 +
laravel/profiling/template.blade.php | 76 +
laravel/redirect.php | 168 +
laravel/redis.php | 294 ++
laravel/request.php | 278 ++
laravel/response.php | 347 ++
laravel/routing/controller.php | 440 +++
laravel/routing/filter.php | 329 ++
laravel/routing/route.php | 433 +++
laravel/routing/router.php | 590 ++++
laravel/section.php | 136 +
laravel/session.php | 153 +
laravel/session/drivers/apc.php | 60 +
laravel/session/drivers/cookie.php | 56 +
laravel/session/drivers/database.php | 107 +
laravel/session/drivers/driver.php | 78 +
laravel/session/drivers/file.php | 87 +
laravel/session/drivers/memcached.php | 60 +
laravel/session/drivers/memory.php | 49 +
laravel/session/drivers/redis.php | 60 +
laravel/session/drivers/sweeper.php | 13 +
laravel/session/payload.php | 338 ++
laravel/str.php | 350 ++
laravel/uri.php | 105 +
laravel/url.php | 319 ++
laravel/validator.php | 1069 ++++++
.../Symfony/Component/Console/Application.php | 1007 ++++++
.../Component/Console/Command/Command.php | 612 ++++
.../Component/Console/Command/HelpCommand.php | 84 +
.../Component/Console/Command/ListCommand.php | 87 +
.../Console/Formatter/OutputFormatter.php | 192 ++
.../Formatter/OutputFormatterInterface.php | 83 +
.../Formatter/OutputFormatterStyle.php | 218 ++
.../OutputFormatterStyleInterface.php | 72 +
.../Component/Console/Helper/DialogHelper.php | 139 +
.../Console/Helper/FormatterHelper.php | 97 +
.../Component/Console/Helper/Helper.php | 42 +
.../Console/Helper/HelperInterface.php | 49 +
.../Component/Console/Helper/HelperSet.php | 104 +
.../Component/Console/Input/ArgvInput.php | 311 ++
.../Component/Console/Input/ArrayInput.php | 190 ++
.../Symfony/Component/Console/Input/Input.php | 211 ++
.../Component/Console/Input/InputArgument.php | 132 +
.../Console/Input/InputDefinition.php | 533 +++
.../Console/Input/InputInterface.php | 152 +
.../Component/Console/Input/InputOption.php | 201 ++
.../Component/Console/Input/StringInput.php | 79 +
.../vendor/Symfony/Component/Console/LICENSE | 19 +
.../Console/Output/ConsoleOutput.php | 83 +
.../Console/Output/ConsoleOutputInterface.php | 30 +
.../Component/Console/Output/NullOutput.php | 34 +
.../Component/Console/Output/Output.php | 180 +
.../Console/Output/OutputInterface.php | 109 +
.../Component/Console/Output/StreamOutput.php | 113 +
.../Symfony/Component/Console/README.md | 48 +
.../Symfony/Component/Console/Shell.php | 206 ++
.../Console/Tester/ApplicationTester.php | 102 +
.../Console/Tester/CommandTester.php | 100 +
.../Symfony/Component/Console/composer.json | 30 +
.../HttpFoundation/ApacheRequest.php | 51 +
.../Component/HttpFoundation/Cookie.php | 203 ++
.../File/Exception/AccessDeniedException.php | 30 +
.../File/Exception/FileException.php | 21 +
.../File/Exception/FileNotFoundException.php | 30 +
.../Exception/UnexpectedTypeException.php | 20 +
.../File/Exception/UploadException.php | 21 +
.../Component/HttpFoundation/File/File.php | 129 +
.../File/MimeType/ExtensionGuesser.php | 100 +
.../MimeType/ExtensionGuesserInterface.php | 26 +
.../MimeType/FileBinaryMimeTypeGuesser.php | 89 +
.../File/MimeType/FileinfoMimeTypeGuesser.php | 59 +
.../MimeType/MimeTypeExtensionGuesser.php | 743 +++++
.../File/MimeType/MimeTypeGuesser.php | 121 +
.../MimeType/MimeTypeGuesserInterface.php | 32 +
.../HttpFoundation/File/UploadedFile.php | 223 ++
.../Component/HttpFoundation/FileBag.php | 158 +
.../Component/HttpFoundation/HeaderBag.php | 306 ++
.../Component/HttpFoundation/JsonResponse.php | 49 +
.../Symfony/Component/HttpFoundation/LICENSE | 19 +
.../HttpFoundation/LaravelRequest.php | 37 +
.../Component/HttpFoundation/ParameterBag.php | 281 ++
.../Component/HttpFoundation/README.md | 47 +
.../HttpFoundation/RedirectResponse.php | 83 +
.../Component/HttpFoundation/Request.php | 1413 ++++++++
.../HttpFoundation/RequestMatcher.php | 221 ++
.../RequestMatcherInterface.php | 33 +
.../stubs/SessionHandlerInterface.php | 98 +
.../Component/HttpFoundation/Response.php | 1112 +++++++
.../HttpFoundation/ResponseHeaderBag.php | 293 ++
.../Component/HttpFoundation/ServerBag.php | 48 +
.../Session/Attribute/AttributeBag.php | 137 +
.../Attribute/AttributeBagInterface.php | 72 +
.../Attribute/NamespacedAttributeBag.php | 154 +
.../Session/Flash/AutoExpireFlashBag.php | 171 +
.../HttpFoundation/Session/Flash/FlashBag.php | 158 +
.../Session/Flash/FlashBagInterface.php | 85 +
.../HttpFoundation/Session/Session.php | 300 ++
.../Session/SessionBagInterface.php | 48 +
.../Session/SessionInterface.php | 167 +
.../Handler/MemcacheSessionHandler.php | 139 +
.../Handler/MemcachedSessionHandler.php | 130 +
.../Handler/NativeFileSessionHandler.php | 41 +
.../Handler/NativeMemcacheSessionHandler.php | 65 +
.../Handler/NativeMemcachedSessionHandler.php | 64 +
.../Storage/Handler/NativeSessionHandler.php | 24 +
.../Handler/NativeSqliteSessionHandler.php | 58 +
.../Storage/Handler/NullSessionHandler.php | 72 +
.../Storage/Handler/PdoSessionHandler.php | 221 ++
.../Storage/MockArraySessionStorage.php | 218 ++
.../Storage/MockFileSessionStorage.php | 126 +
.../Session/Storage/NativeSessionStorage.php | 347 ++
.../Session/Storage/Proxy/AbstractProxy.php | 135 +
.../Session/Storage/Proxy/NativeProxy.php | 41 +
.../Storage/Proxy/SessionHandlerProxy.php | 95 +
.../Storage/SessionStorageInterface.php | 126 +
.../HttpFoundation/StreamedResponse.php | 129 +
.../Component/HttpFoundation/composer.json | 33 +
laravel/view.php | 549 +++
license.txt | 46 +
paths.php | 113 +
public/.htaccess | 23 +
public/bundles/.gitignore | 0
public/css/.gitignore | 0
public/favicon.ico | 0
public/img/.gitignore | 0
public/index.php | 34 +
public/js/.gitignore | 0
public/laravel/css/style.css | 378 +++
public/laravel/img/logoback.png | Bin 0 -> 10295 bytes
public/laravel/js/modernizr-2.5.3.min.js | 4 +
public/laravel/js/prettify.js | 1477 +++++++++
public/laravel/js/scroll.js | 236 ++
readme.md | 67 +
storage/cache/.gitignore | 2 +
storage/database/.gitignore | 1 +
storage/logs/.gitignore | 2 +
storage/sessions/.gitignore | 2 +
storage/views/.gitignore | 2 +
storage/work/.gitignore | 2 +
309 files changed, 51869 insertions(+)
create mode 100644 application/bundles.php
create mode 100644 application/config/.gitignore
create mode 100755 application/config/application.php
create mode 100644 application/config/auth.php
create mode 100644 application/config/cache.php
create mode 100644 application/config/database.php
create mode 100644 application/config/error.php
create mode 100644 application/config/mimes.php
create mode 100644 application/config/session.php
create mode 100644 application/config/strings.php
create mode 100644 application/controllers/base.php
create mode 100644 application/controllers/home.php
create mode 100644 application/language/en/pagination.php
create mode 100644 application/language/en/validation.php
create mode 100644 application/language/nl/pagination.php
create mode 100644 application/language/nl/validation.php
create mode 100644 application/language/ru/pagination.php
create mode 100644 application/language/ru/validation.php
create mode 100644 application/libraries/.gitignore
create mode 100644 application/migrations/.gitignore
create mode 100644 application/models/.gitignore
create mode 100644 application/routes.php
create mode 100755 application/start.php
create mode 100644 application/tasks/.gitignore
create mode 100644 application/tests/example.test.php
create mode 100644 application/views/error/404.php
create mode 100644 application/views/error/500.php
create mode 100644 application/views/home/index.blade.php
create mode 100644 artisan
create mode 100644 bundles/.gitignore
create mode 100755 bundles/docs/libraries/markdown.php
create mode 100644 bundles/docs/routes.php
create mode 100644 bundles/docs/views/page.blade.php
create mode 100644 bundles/docs/views/template.blade.php
create mode 100644 laravel/asset.php
create mode 100644 laravel/auth.php
create mode 100644 laravel/auth/drivers/driver.php
create mode 100644 laravel/auth/drivers/eloquent.php
create mode 100644 laravel/auth/drivers/fluent.php
create mode 100644 laravel/autoloader.php
create mode 100644 laravel/blade.php
create mode 100644 laravel/bundle.php
create mode 100644 laravel/cache.php
create mode 100644 laravel/cache/drivers/apc.php
create mode 100644 laravel/cache/drivers/database.php
create mode 100644 laravel/cache/drivers/driver.php
create mode 100644 laravel/cache/drivers/file.php
create mode 100644 laravel/cache/drivers/memcached.php
create mode 100644 laravel/cache/drivers/memory.php
create mode 100644 laravel/cache/drivers/redis.php
create mode 100644 laravel/cache/drivers/sectionable.php
create mode 100644 laravel/cli/artisan.php
create mode 100644 laravel/cli/command.php
create mode 100644 laravel/cli/dependencies.php
create mode 100644 laravel/cli/tasks/bundle/bundler.php
create mode 100644 laravel/cli/tasks/bundle/providers/github.php
create mode 100644 laravel/cli/tasks/bundle/providers/provider.php
create mode 100644 laravel/cli/tasks/bundle/publisher.php
create mode 100644 laravel/cli/tasks/bundle/repository.php
create mode 100644 laravel/cli/tasks/key.php
create mode 100644 laravel/cli/tasks/migrate/database.php
create mode 100644 laravel/cli/tasks/migrate/migrator.php
create mode 100644 laravel/cli/tasks/migrate/resolver.php
create mode 100644 laravel/cli/tasks/migrate/stub.php
create mode 100644 laravel/cli/tasks/route.php
create mode 100644 laravel/cli/tasks/session/manager.php
create mode 100644 laravel/cli/tasks/session/migration.php
create mode 100644 laravel/cli/tasks/task.php
create mode 100644 laravel/cli/tasks/test/phpunit.php
create mode 100644 laravel/cli/tasks/test/runner.php
create mode 100644 laravel/cli/tasks/test/stub.xml
create mode 100644 laravel/config.php
create mode 100644 laravel/cookie.php
create mode 100644 laravel/core.php
create mode 100644 laravel/crypter.php
create mode 100644 laravel/database.php
create mode 100644 laravel/database/connection.php
create mode 100644 laravel/database/connectors/connector.php
create mode 100644 laravel/database/connectors/mysql.php
create mode 100644 laravel/database/connectors/postgres.php
create mode 100644 laravel/database/connectors/sqlite.php
create mode 100644 laravel/database/connectors/sqlserver.php
create mode 100644 laravel/database/eloquent/model.php
create mode 100644 laravel/database/eloquent/pivot.php
create mode 100644 laravel/database/eloquent/query.php
create mode 100644 laravel/database/eloquent/relationships/belongs_to.php
create mode 100644 laravel/database/eloquent/relationships/has_many.php
create mode 100644 laravel/database/eloquent/relationships/has_many_and_belongs_to.php
create mode 100644 laravel/database/eloquent/relationships/has_one.php
create mode 100644 laravel/database/eloquent/relationships/has_one_or_many.php
create mode 100644 laravel/database/eloquent/relationships/relationship.php
create mode 100644 laravel/database/exception.php
create mode 100644 laravel/database/expression.php
create mode 100644 laravel/database/grammar.php
create mode 100644 laravel/database/query.php
create mode 100644 laravel/database/query/grammars/grammar.php
create mode 100644 laravel/database/query/grammars/mysql.php
create mode 100644 laravel/database/query/grammars/postgres.php
create mode 100644 laravel/database/query/grammars/sqlite.php
create mode 100644 laravel/database/query/grammars/sqlserver.php
create mode 100644 laravel/database/query/join.php
create mode 100644 laravel/database/schema.php
create mode 100644 laravel/database/schema/grammars/grammar.php
create mode 100644 laravel/database/schema/grammars/mysql.php
create mode 100644 laravel/database/schema/grammars/postgres.php
create mode 100644 laravel/database/schema/grammars/sqlite.php
create mode 100644 laravel/database/schema/grammars/sqlserver.php
create mode 100644 laravel/database/schema/table.php
create mode 100644 laravel/documentation/artisan/commands.md
create mode 100644 laravel/documentation/artisan/tasks.md
create mode 100644 laravel/documentation/auth/config.md
create mode 100644 laravel/documentation/auth/usage.md
create mode 100644 laravel/documentation/bundles.md
create mode 100644 laravel/documentation/cache/config.md
create mode 100644 laravel/documentation/cache/usage.md
create mode 100644 laravel/documentation/changes.md
create mode 100644 laravel/documentation/config.md
create mode 100644 laravel/documentation/contents.md
create mode 100644 laravel/documentation/controllers.md
create mode 100644 laravel/documentation/database/config.md
create mode 100644 laravel/documentation/database/eloquent.md
create mode 100644 laravel/documentation/database/fluent.md
create mode 100644 laravel/documentation/database/migrations.md
create mode 100644 laravel/documentation/database/raw.md
create mode 100644 laravel/documentation/database/redis.md
create mode 100644 laravel/documentation/database/schema.md
create mode 100644 laravel/documentation/encryption.md
create mode 100644 laravel/documentation/events.md
create mode 100644 laravel/documentation/files.md
create mode 100644 laravel/documentation/home.md
create mode 100644 laravel/documentation/input.md
create mode 100644 laravel/documentation/install.md
create mode 100644 laravel/documentation/ioc.md
create mode 100644 laravel/documentation/loading.md
create mode 100644 laravel/documentation/localization.md
create mode 100644 laravel/documentation/logging.md
create mode 100644 laravel/documentation/models.md
create mode 100644 laravel/documentation/requests.md
create mode 100644 laravel/documentation/routing.md
create mode 100644 laravel/documentation/session/config.md
create mode 100644 laravel/documentation/session/usage.md
create mode 100644 laravel/documentation/strings.md
create mode 100644 laravel/documentation/testing.md
create mode 100644 laravel/documentation/urls.md
create mode 100644 laravel/documentation/validation.md
create mode 100644 laravel/documentation/views/assets.md
create mode 100644 laravel/documentation/views/forms.md
create mode 100644 laravel/documentation/views/home.md
create mode 100644 laravel/documentation/views/html.md
create mode 100644 laravel/documentation/views/pagination.md
create mode 100644 laravel/documentation/views/templating.md
create mode 100644 laravel/error.php
create mode 100644 laravel/event.php
create mode 100644 laravel/file.php
create mode 100644 laravel/fluent.php
create mode 100644 laravel/form.php
create mode 100644 laravel/hash.php
create mode 100644 laravel/helpers.php
create mode 100644 laravel/html.php
create mode 100644 laravel/input.php
create mode 100644 laravel/ioc.php
create mode 100644 laravel/lang.php
create mode 100644 laravel/laravel.php
create mode 100644 laravel/log.php
create mode 100644 laravel/memcached.php
create mode 100644 laravel/messages.php
create mode 100644 laravel/paginator.php
create mode 100644 laravel/pluralizer.php
create mode 100755 laravel/profiling/profiler.css
create mode 100755 laravel/profiling/profiler.js
create mode 100644 laravel/profiling/profiler.php
create mode 100755 laravel/profiling/template.blade.php
create mode 100644 laravel/redirect.php
create mode 100644 laravel/redis.php
create mode 100644 laravel/request.php
create mode 100644 laravel/response.php
create mode 100644 laravel/routing/controller.php
create mode 100644 laravel/routing/filter.php
create mode 100644 laravel/routing/route.php
create mode 100644 laravel/routing/router.php
create mode 100644 laravel/section.php
create mode 100644 laravel/session.php
create mode 100644 laravel/session/drivers/apc.php
create mode 100644 laravel/session/drivers/cookie.php
create mode 100644 laravel/session/drivers/database.php
create mode 100644 laravel/session/drivers/driver.php
create mode 100644 laravel/session/drivers/file.php
create mode 100644 laravel/session/drivers/memcached.php
create mode 100644 laravel/session/drivers/memory.php
create mode 100644 laravel/session/drivers/redis.php
create mode 100644 laravel/session/drivers/sweeper.php
create mode 100644 laravel/session/payload.php
create mode 100644 laravel/str.php
create mode 100644 laravel/uri.php
create mode 100644 laravel/url.php
create mode 100644 laravel/validator.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Application.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Command/Command.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Command/HelpCommand.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Command/ListCommand.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Formatter/OutputFormatter.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Formatter/OutputFormatterInterface.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Formatter/OutputFormatterStyle.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Formatter/OutputFormatterStyleInterface.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Helper/DialogHelper.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Helper/FormatterHelper.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Helper/Helper.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Helper/HelperInterface.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Helper/HelperSet.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Input/ArgvInput.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Input/ArrayInput.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Input/Input.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Input/InputArgument.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Input/InputDefinition.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Input/InputInterface.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Input/InputOption.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Input/StringInput.php
create mode 100644 laravel/vendor/Symfony/Component/Console/LICENSE
create mode 100644 laravel/vendor/Symfony/Component/Console/Output/ConsoleOutput.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Output/ConsoleOutputInterface.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Output/NullOutput.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Output/Output.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Output/OutputInterface.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Output/StreamOutput.php
create mode 100644 laravel/vendor/Symfony/Component/Console/README.md
create mode 100644 laravel/vendor/Symfony/Component/Console/Shell.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Tester/ApplicationTester.php
create mode 100644 laravel/vendor/Symfony/Component/Console/Tester/CommandTester.php
create mode 100644 laravel/vendor/Symfony/Component/Console/composer.json
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/ApacheRequest.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Cookie.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/File/Exception/AccessDeniedException.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/File/Exception/FileException.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/File/Exception/FileNotFoundException.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/File/Exception/UnexpectedTypeException.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/File/Exception/UploadException.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/File/File.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/File/MimeType/ExtensionGuesser.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/File/MimeType/ExtensionGuesserInterface.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/File/MimeType/FileBinaryMimeTypeGuesser.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/File/MimeType/FileinfoMimeTypeGuesser.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/File/MimeType/MimeTypeExtensionGuesser.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/File/MimeType/MimeTypeGuesser.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/File/MimeType/MimeTypeGuesserInterface.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/File/UploadedFile.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/FileBag.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/HeaderBag.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/JsonResponse.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/LICENSE
create mode 100644 laravel/vendor/Symfony/Component/HttpFoundation/LaravelRequest.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/ParameterBag.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/README.md
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/RedirectResponse.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Request.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/RequestMatcher.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/RequestMatcherInterface.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Resources/stubs/SessionHandlerInterface.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Response.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/ResponseHeaderBag.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/ServerBag.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBag.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Session/Attribute/AttributeBagInterface.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Session/Attribute/NamespacedAttributeBag.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Session/Flash/AutoExpireFlashBag.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Session/Flash/FlashBag.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Session/Flash/FlashBagInterface.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Session/Session.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Session/SessionBagInterface.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Session/SessionInterface.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcacheSessionHandler.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Session/Storage/Handler/MemcachedSessionHandler.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeFileSessionHandler.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeMemcacheSessionHandler.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeMemcachedSessionHandler.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeSessionHandler.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Session/Storage/Handler/NativeSqliteSessionHandler.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Session/Storage/Handler/NullSessionHandler.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Session/Storage/Handler/PdoSessionHandler.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Session/Storage/MockArraySessionStorage.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Session/Storage/MockFileSessionStorage.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Session/Storage/NativeSessionStorage.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Session/Storage/Proxy/AbstractProxy.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Session/Storage/Proxy/NativeProxy.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Session/Storage/Proxy/SessionHandlerProxy.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/Session/Storage/SessionStorageInterface.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/StreamedResponse.php
create mode 100755 laravel/vendor/Symfony/Component/HttpFoundation/composer.json
create mode 100644 laravel/view.php
create mode 100644 license.txt
create mode 100644 paths.php
create mode 100644 public/.htaccess
create mode 100644 public/bundles/.gitignore
create mode 100644 public/css/.gitignore
create mode 100644 public/favicon.ico
create mode 100644 public/img/.gitignore
create mode 100644 public/index.php
create mode 100644 public/js/.gitignore
create mode 100755 public/laravel/css/style.css
create mode 100755 public/laravel/img/logoback.png
create mode 100755 public/laravel/js/modernizr-2.5.3.min.js
create mode 100755 public/laravel/js/prettify.js
create mode 100644 public/laravel/js/scroll.js
create mode 100644 readme.md
create mode 100644 storage/cache/.gitignore
create mode 100644 storage/database/.gitignore
create mode 100644 storage/logs/.gitignore
create mode 100644 storage/sessions/.gitignore
create mode 100644 storage/views/.gitignore
create mode 100644 storage/work/.gitignore
diff --git a/application/bundles.php b/application/bundles.php
new file mode 100644
index 0000000..e8b8f26
--- /dev/null
+++ b/application/bundles.php
@@ -0,0 +1,40 @@
+ array(
+| 'location' => 'admin',
+| 'handles' => 'admin',
+| ),
+|
+| Note that the "location" is relative to the "bundles" directory.
+| Now the bundle will be recognized by Laravel and will be able
+| to respond to requests beginning with "admin"!
+|
+| Have a bundle that lives in the root of the bundle directory
+| and doesn't respond to any requests? Just add the bundle
+| name to the array and we'll take care of the rest.
+|
+*/
+
+return array(
+
+ 'docs' => array('handles' => 'docs'),
+
+);
\ No newline at end of file
diff --git a/application/config/.gitignore b/application/config/.gitignore
new file mode 100644
index 0000000..aa5195c
--- /dev/null
+++ b/application/config/.gitignore
@@ -0,0 +1 @@
+local/*
\ No newline at end of file
diff --git a/application/config/application.php b/application/config/application.php
new file mode 100755
index 0000000..9f59795
--- /dev/null
+++ b/application/config/application.php
@@ -0,0 +1,185 @@
+ '',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Asset URL
+ |--------------------------------------------------------------------------
+ |
+ | The base URL used for your application's asset files. This is useful if
+ | you are serving your assets through a different server or a CDN. If it
+ | is not set, we'll default to the application URL above.
+ |
+ */
+
+ 'asset_url' => '',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Application Index
+ |--------------------------------------------------------------------------
+ |
+ | If you are including the "index.php" in your URLs, you can ignore this.
+ | However, if you are using mod_rewrite to get cleaner URLs, just set
+ | this option to an empty string and we'll take care of the rest.
+ |
+ */
+
+ 'index' => 'index.php',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Application Key
+ |--------------------------------------------------------------------------
+ |
+ | This key is used by the encryption and cookie classes to generate secure
+ | encrypted strings and hashes. It is extremely important that this key
+ | remain secret and should not be shared with anyone. Make it about 32
+ | characters of random gibberish.
+ |
+ */
+
+ 'key' => 'YourSecretKeyGoesHere!',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Profiler Toolbar
+ |--------------------------------------------------------------------------
+ |
+ | Laravel includes a beautiful profiler toolbar that gives you a heads
+ | up display of the queries and logs performed by your application.
+ | This is wonderful for development, but, of course, you should
+ | disable the toolbar for production applications..
+ |
+ */
+
+ 'profiler' => false,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Application Character Encoding
+ |--------------------------------------------------------------------------
+ |
+ | The default character encoding used by your application. This encoding
+ | will be used by the Str, Text, Form, and any other classes that need
+ | to know what type of encoding to use for your awesome application.
+ |
+ */
+
+ 'encoding' => 'UTF-8',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Application Language
+ |--------------------------------------------------------------------------
+ |
+ | The default language of your application. This language will be used by
+ | Lang library as the default language when doing string localization.
+ |
+ */
+
+ 'language' => 'en',
+
+ /*
+ |--------------------------------------------------------------------------
+ | SSL Link Generation
+ |--------------------------------------------------------------------------
+ |
+ | Many sites use SSL to protect their users data. However, you may not be
+ | able to use SSL on your development machine, meaning all HTTPS will be
+ | broken during development.
+ |
+ | For this reason, you may wish to disable the generation of HTTPS links
+ | throughout your application. This option does just that. All attempts
+ | to generate HTTPS links will generate regular HTTP links instead.
+ |
+ */
+
+ 'ssl' => true,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Application Timezone
+ |--------------------------------------------------------------------------
+ |
+ | The default timezone of your application. The timezone will be used when
+ | Laravel needs a date, such as when writing to a log file or travelling
+ | to a distant star at warp speed.
+ |
+ */
+
+ 'timezone' => 'UTC',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Class Aliases
+ |--------------------------------------------------------------------------
+ |
+ | Here, you can specify any class aliases that you would like registered
+ | when Laravel loads. Aliases are lazy-loaded, so feel free to add!
+ |
+ | Aliases make it more convenient to use namespaced classes. Instead of
+ | referring to the class using its full namespace, you may simply use
+ | the alias defined here.
+ |
+ */
+
+ 'aliases' => array(
+ 'Auth' => 'Laravel\\Auth',
+ 'Authenticator' => 'Laravel\\Auth\\Drivers\\Driver',
+ 'Asset' => 'Laravel\\Asset',
+ 'Autoloader' => 'Laravel\\Autoloader',
+ 'Blade' => 'Laravel\\Blade',
+ 'Bundle' => 'Laravel\\Bundle',
+ 'Cache' => 'Laravel\\Cache',
+ 'Config' => 'Laravel\\Config',
+ 'Controller' => 'Laravel\\Routing\\Controller',
+ 'Cookie' => 'Laravel\\Cookie',
+ 'Crypter' => 'Laravel\\Crypter',
+ 'DB' => 'Laravel\\Database',
+ 'Eloquent' => 'Laravel\\Database\\Eloquent\\Model',
+ 'Event' => 'Laravel\\Event',
+ 'File' => 'Laravel\\File',
+ 'Filter' => 'Laravel\\Routing\\Filter',
+ 'Form' => 'Laravel\\Form',
+ 'Hash' => 'Laravel\\Hash',
+ 'HTML' => 'Laravel\\HTML',
+ 'Input' => 'Laravel\\Input',
+ 'IoC' => 'Laravel\\IoC',
+ 'Lang' => 'Laravel\\Lang',
+ 'Log' => 'Laravel\\Log',
+ 'Memcached' => 'Laravel\\Memcached',
+ 'Paginator' => 'Laravel\\Paginator',
+ 'Profiler' => 'Laravel\\Profiling\\Profiler',
+ 'URL' => 'Laravel\\URL',
+ 'Redirect' => 'Laravel\\Redirect',
+ 'Redis' => 'Laravel\\Redis',
+ 'Request' => 'Laravel\\Request',
+ 'Response' => 'Laravel\\Response',
+ 'Route' => 'Laravel\\Routing\\Route',
+ 'Router' => 'Laravel\\Routing\\Router',
+ 'Schema' => 'Laravel\\Database\\Schema',
+ 'Section' => 'Laravel\\Section',
+ 'Session' => 'Laravel\\Session',
+ 'Str' => 'Laravel\\Str',
+ 'Task' => 'Laravel\\CLI\\Tasks\\Task',
+ 'URI' => 'Laravel\\URI',
+ 'Validator' => 'Laravel\\Validator',
+ 'View' => 'Laravel\\View',
+ ),
+
+);
diff --git a/application/config/auth.php b/application/config/auth.php
new file mode 100644
index 0000000..d4a0dcb
--- /dev/null
+++ b/application/config/auth.php
@@ -0,0 +1,73 @@
+ 'eloquent',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Authentication Username
+ |--------------------------------------------------------------------------
+ |
+ | Here you may specify the database column that should be considered the
+ | "username" for your users. Typically, this will either be "username"
+ | or "email". Of course, you're free to change the value to anything.
+ |
+ */
+
+ 'username' => 'email',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Authentication Password
+ |--------------------------------------------------------------------------
+ |
+ | Here you may specify the database column that should be considered the
+ | "password" for your users. Typically, this will be "password" but,
+ | again, you're free to change the value to anything you see fit.
+ |
+ */
+
+ 'password' => 'password',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Authentication Model
+ |--------------------------------------------------------------------------
+ |
+ | When using the "eloquent" authentication driver, you may specify the
+ | model that should be considered the "User" model. This model will
+ | be used to authenticate and load the users of your application.
+ |
+ */
+
+ 'model' => 'User',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Authentication Table
+ |--------------------------------------------------------------------------
+ |
+ | When using the "fluent" authentication driver, the database table used
+ | to load users may be specified here. This table will be used in by
+ | the fluent query builder to authenticate and load your users.
+ |
+ */
+
+ 'table' => 'users',
+
+);
\ No newline at end of file
diff --git a/application/config/cache.php b/application/config/cache.php
new file mode 100644
index 0000000..a507ff6
--- /dev/null
+++ b/application/config/cache.php
@@ -0,0 +1,71 @@
+ 'file',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Cache Key
+ |--------------------------------------------------------------------------
+ |
+ | This key will be prepended to item keys stored using Memcached and APC
+ | to prevent collisions with other applications on the server. Since the
+ | memory based stores could be shared by other applications, we need to
+ | be polite and use a prefix to uniquely identifier our items.
+ |
+ */
+
+ 'key' => 'laravel',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Cache Database
+ |--------------------------------------------------------------------------
+ |
+ | When using the database cache driver, this database table will be used
+ | to store the cached item. You may also add a "connection" option to
+ | the array to specify which database connection should be used.
+ |
+ */
+
+ 'database' => array('table' => 'laravel_cache'),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Memcached Servers
+ |--------------------------------------------------------------------------
+ |
+ | The Memcached servers used by your application. Memcached is a free and
+ | open source, high-performance, distributed memory caching system. It is
+ | generic in nature but intended for use in speeding up web applications
+ | by alleviating database load.
+ |
+ | For more information, check out: http://memcached.org
+ |
+ */
+
+ 'memcached' => array(
+
+ array('host' => '127.0.0.1', 'port' => 11211, 'weight' => 100),
+
+ ),
+
+);
\ No newline at end of file
diff --git a/application/config/database.php b/application/config/database.php
new file mode 100644
index 0000000..d5e6ac1
--- /dev/null
+++ b/application/config/database.php
@@ -0,0 +1,124 @@
+ true,
+
+ /*
+ |--------------------------------------------------------------------------
+ | PDO Fetch Style
+ |--------------------------------------------------------------------------
+ |
+ | By default, database results will be returned as instances of the PHP
+ | stdClass object; however, you may wish to retrieve records as arrays
+ | instead of objects. Here you can control the PDO fetch style of the
+ | database queries run by your application.
+ |
+ */
+
+ 'fetch' => PDO::FETCH_CLASS,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Default Database Connection
+ |--------------------------------------------------------------------------
+ |
+ | The name of your default database connection. This connection will used
+ | as the default for all database operations unless a different name is
+ | given when performing said operation. This connection name should be
+ | listed in the array of connections below.
+ |
+ */
+
+ 'default' => 'mysql',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Database Connections
+ |--------------------------------------------------------------------------
+ |
+ | All of the database connections used by your application. Many of your
+ | applications will no doubt only use one connection; however, you have
+ | the freedom to specify as many connections as you can handle.
+ |
+ | All database work in Laravel is done through the PHP's PDO facilities,
+ | so make sure you have the PDO drivers for your particlar database of
+ | choice installed on your machine.
+ |
+ */
+
+ 'connections' => array(
+
+ 'sqlite' => array(
+ 'driver' => 'sqlite',
+ 'database' => 'application',
+ 'prefix' => '',
+ ),
+
+ 'mysql' => array(
+ 'driver' => 'mysql',
+ 'host' => 'localhost',
+ 'database' => 'database',
+ 'username' => 'root',
+ 'password' => '',
+ 'charset' => 'utf8',
+ 'prefix' => '',
+ ),
+
+ 'pgsql' => array(
+ 'driver' => 'pgsql',
+ 'host' => 'localhost',
+ 'database' => 'database',
+ 'username' => 'root',
+ 'password' => '',
+ 'charset' => 'utf8',
+ 'prefix' => '',
+ ),
+
+ 'sqlsrv' => array(
+ 'driver' => 'sqlsrv',
+ 'host' => 'localhost',
+ 'database' => 'database',
+ 'username' => 'root',
+ 'password' => '',
+ 'prefix' => '',
+ ),
+
+ ),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Redis Databases
+ |--------------------------------------------------------------------------
+ |
+ | Redis is an open source, fast, and advanced key-value store. However, it
+ | provides a richer set of commands than a typical key-value store such as
+ | APC or memcached. All the cool kids are using it.
+ |
+ | To get the scoop on Redis, check out: http://redis.io
+ |
+ */
+
+ 'redis' => array(
+
+ 'default' => array(
+ 'host' => '127.0.0.1',
+ 'port' => 6379,
+ 'database' => 0
+ ),
+
+ ),
+
+);
\ No newline at end of file
diff --git a/application/config/error.php b/application/config/error.php
new file mode 100644
index 0000000..1713afc
--- /dev/null
+++ b/application/config/error.php
@@ -0,0 +1,69 @@
+ array(),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Error Detail
+ |--------------------------------------------------------------------------
+ |
+ | Detailed error messages contain information about the file in which an
+ | error occurs, as well as a PHP stack trace containing the call stack.
+ | You'll want them when you're trying to debug your application.
+ |
+ | If your application is in production, you'll want to turn off the error
+ | details for enhanced security and user experience since the exception
+ | stack trace could contain sensitive information.
+ |
+ */
+
+ 'detail' => true,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Error Logging
+ |--------------------------------------------------------------------------
+ |
+ | When error logging is enabled, the "logger" Closure defined below will
+ | be called for every error in your application. You are free to log the
+ | errors however you want. Enjoy the flexibility.
+ |
+ */
+
+ 'log' => false,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Error Logger
+ |--------------------------------------------------------------------------
+ |
+ | Because of the various ways of managing error logging, you get complete
+ | flexibility to manage error logging as you see fit. This function will
+ | be called anytime an error occurs within your application and error
+ | logging is enabled.
+ |
+ | You may log the error message however you like; however, a simple log
+ | solution has been setup for you which will log all error messages to
+ | text files within the application storage directory.
+ |
+ */
+
+ 'logger' => function($exception)
+ {
+ Log::exception($exception);
+ },
+
+);
\ No newline at end of file
diff --git a/application/config/mimes.php b/application/config/mimes.php
new file mode 100644
index 0000000..e2bd4fb
--- /dev/null
+++ b/application/config/mimes.php
@@ -0,0 +1,97 @@
+ 'application/mac-binhex40',
+ 'cpt' => 'application/mac-compactpro',
+ 'csv' => array('text/x-comma-separated-values', 'text/comma-separated-values', 'application/octet-stream'),
+ 'bin' => 'application/macbinary',
+ 'dms' => 'application/octet-stream',
+ 'lha' => 'application/octet-stream',
+ 'lzh' => 'application/octet-stream',
+ 'exe' => array('application/octet-stream', 'application/x-msdownload'),
+ 'class' => 'application/octet-stream',
+ 'psd' => 'application/x-photoshop',
+ 'so' => 'application/octet-stream',
+ 'sea' => 'application/octet-stream',
+ 'dll' => 'application/octet-stream',
+ 'oda' => 'application/oda',
+ 'pdf' => array('application/pdf', 'application/x-download'),
+ 'ai' => 'application/postscript',
+ 'eps' => 'application/postscript',
+ 'ps' => 'application/postscript',
+ 'smi' => 'application/smil',
+ 'smil' => 'application/smil',
+ 'mif' => 'application/vnd.mif',
+ 'xls' => array('application/excel', 'application/vnd.ms-excel', 'application/msexcel'),
+ 'ppt' => array('application/powerpoint', 'application/vnd.ms-powerpoint'),
+ 'wbxml' => 'application/wbxml',
+ 'wmlc' => 'application/wmlc',
+ 'dcr' => 'application/x-director',
+ 'dir' => 'application/x-director',
+ 'dxr' => 'application/x-director',
+ 'dvi' => 'application/x-dvi',
+ 'gtar' => 'application/x-gtar',
+ 'gz' => 'application/x-gzip',
+ 'php' => array('application/x-httpd-php', 'text/x-php'),
+ 'php4' => 'application/x-httpd-php',
+ 'php3' => 'application/x-httpd-php',
+ 'phtml' => 'application/x-httpd-php',
+ 'phps' => 'application/x-httpd-php-source',
+ 'js' => 'application/x-javascript',
+ 'swf' => 'application/x-shockwave-flash',
+ 'sit' => 'application/x-stuffit',
+ 'tar' => 'application/x-tar',
+ 'tgz' => array('application/x-tar', 'application/x-gzip-compressed'),
+ 'xhtml' => 'application/xhtml+xml',
+ 'xht' => 'application/xhtml+xml',
+ 'zip' => array('application/x-zip', 'application/zip', 'application/x-zip-compressed'),
+ 'mid' => 'audio/midi',
+ 'midi' => 'audio/midi',
+ 'mpga' => 'audio/mpeg',
+ 'mp2' => 'audio/mpeg',
+ 'mp3' => array('audio/mpeg', 'audio/mpg', 'audio/mpeg3', 'audio/mp3'),
+ 'aif' => 'audio/x-aiff',
+ 'aiff' => 'audio/x-aiff',
+ 'aifc' => 'audio/x-aiff',
+ 'ram' => 'audio/x-pn-realaudio',
+ 'rm' => 'audio/x-pn-realaudio',
+ 'rpm' => 'audio/x-pn-realaudio-plugin',
+ 'ra' => 'audio/x-realaudio',
+ 'rv' => 'video/vnd.rn-realvideo',
+ 'wav' => 'audio/x-wav',
+ 'bmp' => 'image/bmp',
+ 'gif' => 'image/gif',
+ 'jpeg' => array('image/jpeg', 'image/pjpeg'),
+ 'jpg' => array('image/jpeg', 'image/pjpeg'),
+ 'jpe' => array('image/jpeg', 'image/pjpeg'),
+ 'png' => 'image/png',
+ 'tiff' => 'image/tiff',
+ 'tif' => 'image/tiff',
+ 'css' => 'text/css',
+ 'html' => 'text/html',
+ 'htm' => 'text/html',
+ 'shtml' => 'text/html',
+ 'txt' => 'text/plain',
+ 'text' => 'text/plain',
+ 'log' => array('text/plain', 'text/x-log'),
+ 'rtx' => 'text/richtext',
+ 'rtf' => 'text/rtf',
+ 'xml' => 'text/xml',
+ 'xsl' => 'text/xml',
+ 'mpeg' => 'video/mpeg',
+ 'mpg' => 'video/mpeg',
+ 'mpe' => 'video/mpeg',
+ 'qt' => 'video/quicktime',
+ 'mov' => 'video/quicktime',
+ 'avi' => 'video/x-msvideo',
+ 'movie' => 'video/x-sgi-movie',
+ 'doc' => 'application/msword',
+ 'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
+ 'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
+ 'word' => array('application/msword', 'application/octet-stream'),
+ 'xl' => 'application/excel',
+ 'eml' => 'message/rfc822',
+ 'json' => array('application/json', 'text/json'),
+
+);
\ No newline at end of file
diff --git a/application/config/session.php b/application/config/session.php
new file mode 100644
index 0000000..ea686f8
--- /dev/null
+++ b/application/config/session.php
@@ -0,0 +1,117 @@
+ 'cookie',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Session Database
+ |--------------------------------------------------------------------------
+ |
+ | The database table on which the session should be stored. It probably
+ | goes without saying that this option only matters if you are using
+ | the super slick database session driver.
+ |
+ */
+
+ 'table' => 'sessions',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Session Garbage Collection Probability
+ |--------------------------------------------------------------------------
+ |
+ | Some session drivers require the manual clean-up of expired sessions.
+ | This option specifies the probability of session garbage collection
+ | occuring for any given request to the application.
+ |
+ | For example, the default value states that garbage collection has a
+ | 2% chance of occuring for any given request to the application.
+ | Feel free to tune this to your requirements.
+ |
+ */
+
+ 'sweepage' => array(2, 100),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Session Lifetime
+ |--------------------------------------------------------------------------
+ |
+ | The number of minutes a session can be idle before expiring.
+ |
+ */
+
+ 'lifetime' => 60,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Session Expiration On Close
+ |--------------------------------------------------------------------------
+ |
+ | Determines if the session should expire when the user's web browser closes.
+ |
+ */
+
+ 'expire_on_close' => false,
+
+ /*
+ |--------------------------------------------------------------------------
+ | Session Cookie Name
+ |--------------------------------------------------------------------------
+ |
+ | The name that should be given to the session cookie.
+ |
+ */
+
+ 'cookie' => 'laravel_session',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Session Cookie Path
+ |--------------------------------------------------------------------------
+ |
+ | The path for which the session cookie is available.
+ |
+ */
+
+ 'path' => '/',
+
+ /*
+ |--------------------------------------------------------------------------
+ | Session Cookie Domain
+ |--------------------------------------------------------------------------
+ |
+ | The domain for which the session cookie is available.
+ |
+ */
+
+ 'domain' => null,
+
+ /*
+ |--------------------------------------------------------------------------
+ | HTTPS Only Session Cookie
+ |--------------------------------------------------------------------------
+ |
+ | Determines if the cookie should only be sent over HTTPS.
+ |
+ */
+
+ 'secure' => false,
+
+);
\ No newline at end of file
diff --git a/application/config/strings.php b/application/config/strings.php
new file mode 100644
index 0000000..5d94f81
--- /dev/null
+++ b/application/config/strings.php
@@ -0,0 +1,188 @@
+ array(
+ '/(quiz)$/i' => "$1zes",
+ '/^(ox)$/i' => "$1en",
+ '/([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",
+ '/(shea|lea|loa|thie)f$/i' => "$1ves",
+ '/sis$/i' => "ses",
+ '/([ti])um$/i' => "$1a",
+ '/(tomat|potat|ech|her|vet)o$/i' => "$1oes",
+ '/(bu)s$/i' => "$1ses",
+ '/(alias)$/i' => "$1es",
+ '/(octop)us$/i' => "$1i",
+ '/(ax|test)is$/i' => "$1es",
+ '/(us)$/i' => "$1es",
+ '/s$/i' => "s",
+ '/$/' => "s"
+ ),
+
+ 'singular' => array(
+ '/(quiz)zes$/i' => "$1",
+ '/(matr)ices$/i' => "$1ix",
+ '/(vert|ind)ices$/i' => "$1ex",
+ '/^(ox)en$/i' => "$1",
+ '/(alias)es$/i' => "$1",
+ '/(octop|vir)i$/i' => "$1us",
+ '/(cris|ax|test)es$/i' => "$1is",
+ '/(shoe)s$/i' => "$1",
+ '/(o)es$/i' => "$1",
+ '/(bus)es$/i' => "$1",
+ '/([m|l])ice$/i' => "$1ouse",
+ '/(x|ch|ss|sh)es$/i' => "$1",
+ '/(m)ovies$/i' => "$1ovie",
+ '/(s)eries$/i' => "$1eries",
+ '/([^aeiouy]|qu)ies$/i' => "$1y",
+ '/([lr])ves$/i' => "$1f",
+ '/(tive)s$/i' => "$1",
+ '/(hive)s$/i' => "$1",
+ '/(li|wi|kni)ves$/i' => "$1fe",
+ '/(shea|loa|lea|thie)ves$/i' => "$1f",
+ '/(^analy)ses$/i' => "$1sis",
+ '/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i' => "$1$2sis",
+ '/([ti])a$/i' => "$1um",
+ '/(n)ews$/i' => "$1ews",
+ '/(h|bl)ouses$/i' => "$1ouse",
+ '/(corpse)s$/i' => "$1",
+ '/(us)es$/i' => "$1",
+ '/(us|ss)$/i' => "$1",
+ '/s$/i' => "",
+ ),
+
+ 'irregular' => array(
+ 'child' => 'children',
+ 'foot' => 'feet',
+ 'goose' => 'geese',
+ 'man' => 'men',
+ 'move' => 'moves',
+ 'person' => 'people',
+ 'sex' => 'sexes',
+ 'tooth' => 'teeth',
+ ),
+
+ 'uncountable' => array(
+ 'audio',
+ 'equipment',
+ 'deer',
+ 'fish',
+ 'gold',
+ 'information',
+ 'money',
+ 'rice',
+ 'police',
+ 'series',
+ 'sheep',
+ 'species',
+ 'moose',
+ ),
+
+ /*
+ |--------------------------------------------------------------------------
+ | ASCII Characters
+ |--------------------------------------------------------------------------
+ |
+ | This array contains foreign characters and their 7-bit ASCII equivalents.
+ | The array is used by the "ascii" method on the Str class to get strings
+ | ready for inclusion in a URL slug.
+ |
+ | Of course, the "ascii" method may also be used by you for whatever your
+ | application requires. Feel free to add any characters we missed, and be
+ | sure to let us know about them!
+ |
+ */
+
+ 'ascii' => array(
+
+ '/æ|ǽ/' => 'ae',
+ '/œ/' => 'oe',
+ '/À|Á|Â|Ã|Ä|Å|Ǻ|Ā|Ă|Ą|Ǎ|А/' => 'A',
+ '/à|á|â|ã|ä|å|ǻ|ā|ă|ą|ǎ|ª|а/' => 'a',
+ '/Б/' => 'B',
+ '/б/' => 'b',
+ '/Ç|Ć|Ĉ|Ċ|Č|Ц/' => 'C',
+ '/ç|ć|ĉ|ċ|č|ц/' => 'c',
+ '/Ð|Ď|Đ|Д/' => 'Dj',
+ '/ð|ď|đ|д/' => 'dj',
+ '/È|É|Ê|Ë|Ē|Ĕ|Ė|Ę|Ě|Е|Ё|Э/' => 'E',
+ '/è|é|ê|ë|ē|ĕ|ė|ę|ě|е|ё|э/' => 'e',
+ '/Ф/' => 'F',
+ '/ƒ|ф/' => 'f',
+ '/Ĝ|Ğ|Ġ|Ģ|Г/' => 'G',
+ '/ĝ|ğ|ġ|ģ|г/' => 'g',
+ '/Ĥ|Ħ|Х/' => 'H',
+ '/ĥ|ħ|х/' => 'h',
+ '/Ì|Í|Î|Ï|Ĩ|Ī|Ĭ|Ǐ|Į|İ|И/' => 'I',
+ '/ì|í|î|ï|ĩ|ī|ĭ|ǐ|į|ı|и/' => 'i',
+ '/Ĵ|Й/' => 'J',
+ '/ĵ|й/' => 'j',
+ '/Ķ|К/' => 'K',
+ '/ķ|к/' => 'k',
+ '/Ĺ|Ļ|Ľ|Ŀ|Ł|Л/' => 'L',
+ '/ĺ|ļ|ľ|ŀ|ł|л/' => 'l',
+ '/М/' => 'M',
+ '/м/' => 'm',
+ '/Ñ|Ń|Ņ|Ň|Н/' => 'N',
+ '/ñ|ń|ņ|ň|ʼn|н/' => 'n',
+ '/Ö|Ò|Ó|Ô|Õ|Ō|Ŏ|Ǒ|Ő|Ơ|Ø|Ǿ|О/' => 'O',
+ '/ö|ò|ó|ô|õ|ō|ŏ|ǒ|ő|ơ|ø|ǿ|º|о/' => 'o',
+ '/П/' => 'P',
+ '/п/' => 'p',
+ '/Ŕ|Ŗ|Ř|Р/' => 'R',
+ '/ŕ|ŗ|ř|р/' => 'r',
+ '/Ś|Ŝ|Ş|Ș|Š|С/' => 'S',
+ '/ś|ŝ|ş|ș|š|ſ|с/' => 's',
+ '/Ţ|Ț|Ť|Ŧ|Т/' => 'T',
+ '/ţ|ț|ť|ŧ|т/' => 't',
+ '/Ù|Ú|Û|Ũ|Ū|Ŭ|Ů|Ü|Ű|Ų|Ư|Ǔ|Ǖ|Ǘ|Ǚ|Ǜ|У/' => 'U',
+ '/ù|ú|û|ũ|ū|ŭ|ů|ü|ű|ų|ư|ǔ|ǖ|ǘ|ǚ|ǜ|у/' => 'u',
+ '/В/' => 'V',
+ '/в/' => 'v',
+ '/Ý|Ÿ|Ŷ|Ы/' => 'Y',
+ '/ý|ÿ|ŷ|ы/' => 'y',
+ '/Ŵ/' => 'W',
+ '/ŵ/' => 'w',
+ '/Ź|Ż|Ž|З/' => 'Z',
+ '/ź|ż|ž|з/' => 'z',
+ '/Æ|Ǽ/' => 'AE',
+ '/ß/'=> 'ss',
+ '/IJ/' => 'IJ',
+ '/ij/' => 'ij',
+ '/Œ/' => 'OE',
+ '/Ч/' => 'Ch',
+ '/ч/' => 'ch',
+ '/Ю/' => 'Ju',
+ '/ю/' => 'ju',
+ '/Я/' => 'Ja',
+ '/я/' => 'ja',
+ '/Ш/' => 'Sh',
+ '/ш/' => 'sh',
+ '/Щ/' => 'Shch',
+ '/щ/' => 'shch',
+ '/Ж/' => 'Zh',
+ '/ж/' => 'zh',
+
+ ),
+
+);
\ No newline at end of file
diff --git a/application/controllers/base.php b/application/controllers/base.php
new file mode 100644
index 0000000..177d887
--- /dev/null
+++ b/application/controllers/base.php
@@ -0,0 +1,17 @@
+ '« Previous',
+ 'next' => 'Next »',
+
+);
\ No newline at end of file
diff --git a/application/language/en/validation.php b/application/language/en/validation.php
new file mode 100644
index 0000000..aade5ed
--- /dev/null
+++ b/application/language/en/validation.php
@@ -0,0 +1,99 @@
+ "The :attribute must be accepted.",
+ "active_url" => "The :attribute is not a valid URL.",
+ "after" => "The :attribute must be a date after :date.",
+ "alpha" => "The :attribute may only contain letters.",
+ "alpha_dash" => "The :attribute may only contain letters, numbers, and dashes.",
+ "alpha_num" => "The :attribute may only contain letters and numbers.",
+ "before" => "The :attribute must be a date before :date.",
+ "between" => array(
+ "numeric" => "The :attribute must be between :min - :max.",
+ "file" => "The :attribute must be between :min - :max kilobytes.",
+ "string" => "The :attribute must be between :min - :max characters.",
+ ),
+ "confirmed" => "The :attribute confirmation does not match.",
+ "different" => "The :attribute and :other must be different.",
+ "email" => "The :attribute format is invalid.",
+ "exists" => "The selected :attribute is invalid.",
+ "image" => "The :attribute must be an image.",
+ "in" => "The selected :attribute is invalid.",
+ "integer" => "The :attribute must be an integer.",
+ "ip" => "The :attribute must be a valid IP address.",
+ "match" => "The :attribute format is invalid.",
+ "max" => array(
+ "numeric" => "The :attribute must be less than :max.",
+ "file" => "The :attribute must be less than :max kilobytes.",
+ "string" => "The :attribute must be less than :max characters.",
+ ),
+ "mimes" => "The :attribute must be a file of type: :values.",
+ "min" => array(
+ "numeric" => "The :attribute must be at least :min.",
+ "file" => "The :attribute must be at least :min kilobytes.",
+ "string" => "The :attribute must be at least :min characters.",
+ ),
+ "not_in" => "The selected :attribute is invalid.",
+ "numeric" => "The :attribute must be a number.",
+ "required" => "The :attribute field is required.",
+ "same" => "The :attribute and :other must match.",
+ "size" => array(
+ "numeric" => "The :attribute must be :size.",
+ "file" => "The :attribute must be :size kilobyte.",
+ "string" => "The :attribute must be :size characters.",
+ ),
+ "unique" => "The :attribute has already been taken.",
+ "url" => "The :attribute format is invalid.",
+
+ /*
+ |--------------------------------------------------------------------------
+ | Custom Validation Language Lines
+ |--------------------------------------------------------------------------
+ |
+ | Here you may specify custom validation messages for attributes using the
+ | convention "attribute_rule" to name the lines. This helps keep your
+ | custom validation clean and tidy.
+ |
+ | So, say you want to use a custom validation message when validating that
+ | the "email" attribute is unique. Just add "email_unique" to this array
+ | with your custom message. The Validator will handle the rest!
+ |
+ */
+
+ 'custom' => array(),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Validation Attributes
+ |--------------------------------------------------------------------------
+ |
+ | The following language lines are used to swap attribute place-holders
+ | with something more reader friendly such as "E-Mail Address" instead
+ | of "email". Your users will thank you.
+ |
+ | The Validator class will automatically search this array of lines it
+ | is attempting to replace the :attribute place-holder in messages.
+ | It's pretty slick. We think you'll like it.
+ |
+ */
+
+ 'attributes' => array(),
+
+);
\ No newline at end of file
diff --git a/application/language/nl/pagination.php b/application/language/nl/pagination.php
new file mode 100644
index 0000000..003e13d
--- /dev/null
+++ b/application/language/nl/pagination.php
@@ -0,0 +1,8 @@
+ '« Vorige',
+ 'next' => 'Volgende »',
+
+);
\ No newline at end of file
diff --git a/application/language/nl/validation.php b/application/language/nl/validation.php
new file mode 100644
index 0000000..51e2a0b
--- /dev/null
+++ b/application/language/nl/validation.php
@@ -0,0 +1,90 @@
+ "Het :attribute moet geaccepteerd zijn.",
+ "active_url" => "Het :attribute is geen geldig URL.",
+ "after" => "Het :attribute moet een datum na :date zijn.",
+ "alpha" => "Het :attribute mag alleen letters bevatten.",
+ "alpha_dash" => "Het :attribute mag alleen letters, nummers, onderstreep(_) en strepen(-) bevatten.",
+ "alpha_num" => "Het :attribute mag alleen letters en nummers",
+ "before" => "Het :attribute moet een datum voor :date zijn.",
+ "between" => array(
+ "numeric" => "Het :attribute moet tussen :min en :max zijn.",
+ "file" => "Het :attribute moet tussen :min en :max kilobytes zijn.",
+ "string" => "Het :attribute moet tussen :min en :max tekens zijn.",
+ ),
+ "confirmed" => "Het :attribute bevestiging komt niet overeen.",
+ "different" => "Het :attribute en :other moeten verschillend zijn.",
+ "email" => "Het :attribute formaat is ongeldig.",
+ "exists" => "Het gekozen :attribute is al ingebruik.",
+ "image" => "Het :attribute moet een afbeelding zijn.",
+ "in" => "Het gekozen :attribute is ongeldig.",
+ "integer" => "Het :attribute moet een getal zijn.",
+ "ip" => "Het :attribute moet een geldig IP adres bevatten.",
+ "match" => "Het :attribute formaat is ongeldig.",
+ "max" => array(
+ "numeric" => "Het :attribute moet minder dan :max zijn.",
+ "file" => "Het :attribute moet minder dan :max kilobytes zijn.",
+ "string" => "Het :attribute moet minder dan :max tekens zijn.",
+ ),
+ "mimes" => "Het :attribute moet een bestand zijn van het bestandstype :values.",
+ "min" => array(
+ "numeric" => "Het :attribute moet minimaal :min zijn.",
+ "file" => "Het :attribute moet minimaal :min kilobytes zijn.",
+ "string" => "Het :attribute moet minimaal :min characters zijn.",
+ ),
+ "not_in" => "Het :attribute formaat is ongeldig.",
+ "numeric" => "Het :attribute moet een nummer zijn.",
+ "required" => "Het :attribute veld is verplicht.",
+ "same" => "Het :attribute en :other moeten overeenkomen.",
+ "size" => array(
+ "numeric" => "Het :attribute moet :size zijn.",
+ "file" => "Het :attribute moet :size kilobyte zijn.",
+ "string" => "Het :attribute moet :size characters zijn.",
+ ),
+ "unique" => "Het :attribute is al in gebruik.",
+ "url" => "Het :attribute formaat is ongeldig.",
+
+ /*
+ |--------------------------------------------------------------------------
+ | Custom Validation Language Lines
+ |--------------------------------------------------------------------------
+ |
+ | Here you may specify custom validation messages for attributes using the
+ | convention "attribute_rule" to name the lines. This helps keep your
+ | custom validation clean and tidy.
+ |
+ | So, say you want to use a custom validation message when validating that
+ | the "email" attribute is unique. Just add "email_unique" to this array
+ | with your custom message. The Validator will handle the rest!
+ |
+ */
+
+ 'custom' => array(),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Validation Attributes
+ |--------------------------------------------------------------------------
+ |
+ | The following language lines are used to swap attribute place-holders
+ | with something more reader friendly such as "E-Mail Address" instead
+ | of "email". Your users will thank you.
+ |
+ | The Validator class will automatically search this array of lines it
+ | is attempting to replace the :attribute place-holder in messages.
+ | It's pretty slick. We think you'll like it.
+ |
+ */
+
+ 'attributes' => array(),
+
+);
\ No newline at end of file
diff --git a/application/language/ru/pagination.php b/application/language/ru/pagination.php
new file mode 100644
index 0000000..0ac9e0a
--- /dev/null
+++ b/application/language/ru/pagination.php
@@ -0,0 +1,19 @@
+ '← Назад',
+ 'next' => 'Вперёд →',
+
+);
\ No newline at end of file
diff --git a/application/language/ru/validation.php b/application/language/ru/validation.php
new file mode 100644
index 0000000..e8ee3a1
--- /dev/null
+++ b/application/language/ru/validation.php
@@ -0,0 +1,99 @@
+ "Вы должны принять :attribute.",
+ "active_url" => "Поле :attribute должно быть полным URL.",
+ "after" => "Поле :attribute должно быть датой после :date.",
+ "alpha" => "Поле :attribute может содержать только буквы.",
+ "alpha_dash" => "Поле :attribute может содержать только буквы, цифры и тире.",
+ "alpha_num" => "Поле :attribute может содержать только буквы и цифры.",
+ "before" => "Поле :attribute должно быть датой перед :date.",
+ "between" => array(
+ "numeric" => "Поле :attribute должно быть между :min и :max.",
+ "file" => "Поле :attribute должно быть от :min до :max Килобайт.",
+ "string" => "Поле :attribute должно быть от :min до :max символов.",
+ ),
+ "confirmed" => "Поле :attribute не совпадает с подтверждением.",
+ "different" => "Поля :attribute и :other должны различаться.",
+ "email" => "Поле :attribute имеет неверный формат.",
+ "exists" => "Выбранное значение для :attribute уже существует.",
+ "image" => "Поле :attribute должно быть картинкой.",
+ "in" => "Выбранное значение для :attribute не верно.",
+ "integer" => "Поле :attribute должно быть целым числом.",
+ "ip" => "Поле :attribute должно быть полным IP-адресом.",
+ "match" => "Поле :attribute имеет неверный формат.",
+ "max" => array(
+ "numeric" => "Поле :attribute должно быть меньше :max.",
+ "file" => "Поле :attribute должно быть меньше :max Килобайт.",
+ "string" => "Поле :attribute должно быть короче :max символов.",
+ ),
+ "mimes" => "Поле :attribute должно быть файлом одного из типов: :values.",
+ "min" => array(
+ "numeric" => "Поле :attribute должно быть не менее :min.",
+ "file" => "Поле :attribute должно быть не менее :min Килобайт.",
+ "string" => "Поле :attribute должно быть не короче :min символов.",
+ ),
+ "not_in" => "Выбранное значение для :attribute не верно.",
+ "numeric" => "Поле :attribute должно быть числом.",
+ "required" => "Поле :attribute обязательно для заполнения.",
+ "same" => "Значение :attribute должно совпадать с :other.",
+ "size" => array(
+ "numeric" => "Поле :attribute должно быть :size.",
+ "file" => "Поле :attribute должно быть :size Килобайт.",
+ "string" => "Поле :attribute должно быть длиной :size символов.",
+ ),
+ "unique" => "Такое значение поля :attribute уже существует.",
+ "url" => "Поле :attribute имеет неверный формат.",
+
+ /*
+ |--------------------------------------------------------------------------
+ | Custom Validation Language Lines
+ |--------------------------------------------------------------------------
+ |
+ | Here you may specify custom validation messages for attributes using the
+ | convention "attribute_rule" to name the lines. This helps keep your
+ | custom validation clean and tidy.
+ |
+ | So, say you want to use a custom validation message when validating that
+ | the "email" attribute is unique. Just add "email_unique" to this array
+ | with your custom message. The Validator will handle the rest!
+ |
+ */
+
+ 'custom' => array(),
+
+ /*
+ |--------------------------------------------------------------------------
+ | Validation Attributes
+ |--------------------------------------------------------------------------
+ |
+ | The following language lines are used to swap attribute place-holders
+ | with something more reader friendly such as "E-Mail Address" instead
+ | of "email". Your users will thank you.
+ |
+ | The Validator class will automatically search this array of lines it
+ | is attempting to replace the :attribute place-holder in messages.
+ | It's pretty slick. We think you'll like it.
+ |
+ */
+
+ 'attributes' => array(),
+
+);
\ No newline at end of file
diff --git a/application/libraries/.gitignore b/application/libraries/.gitignore
new file mode 100644
index 0000000..e69de29
diff --git a/application/migrations/.gitignore b/application/migrations/.gitignore
new file mode 100644
index 0000000..e69de29
diff --git a/application/models/.gitignore b/application/models/.gitignore
new file mode 100644
index 0000000..e69de29
diff --git a/application/routes.php b/application/routes.php
new file mode 100644
index 0000000..2135969
--- /dev/null
+++ b/application/routes.php
@@ -0,0 +1,111 @@
+ 'filter', function()
+| {
+| return 'Hello World!';
+| }));
+|
+*/
+
+Route::filter('before', function()
+{
+ // Do stuff before every request to your application...
+});
+
+Route::filter('after', function($response)
+{
+ // Do stuff after every request to your application...
+});
+
+Route::filter('csrf', function()
+{
+ if (Request::forged()) return Response::error('500');
+});
+
+Route::filter('auth', function()
+{
+ if (Auth::guest()) return Redirect::to('login');
+});
\ No newline at end of file
diff --git a/application/start.php b/application/start.php
new file mode 100755
index 0000000..6bb648b
--- /dev/null
+++ b/application/start.php
@@ -0,0 +1,173 @@
+ path('app').'controllers/base.php',
+));
+
+/*
+|--------------------------------------------------------------------------
+| Auto-Loader Directories
+|--------------------------------------------------------------------------
+|
+| The Laravel auto-loader can search directories for files using the PSR-0
+| naming convention. This convention basically organizes classes by using
+| the class namespace to indicate the directory structure.
+|
+*/
+
+Autoloader::directories(array(
+ path('app').'models',
+ path('app').'libraries',
+));
+
+/*
+|--------------------------------------------------------------------------
+| Laravel View Loader
+|--------------------------------------------------------------------------
+|
+| The Laravel view loader is responsible for returning the full file path
+| for the given bundle and view. Of course, a default implementation is
+| provided to load views according to typical Laravel conventions but
+| you may change this to customize how your views are organized.
+|
+*/
+
+Event::listen(View::loader, function($bundle, $view)
+{
+ return View::file($bundle, $view, Bundle::path($bundle).'views');
+});
+
+/*
+|--------------------------------------------------------------------------
+| Laravel Language Loader
+|--------------------------------------------------------------------------
+|
+| The Laravel language loader is responsible for returning the array of
+| language lines for a given bundle, language, and "file". A default
+| implementation has been provided which uses the default language
+| directories included with Laravel.
+|
+*/
+
+Event::listen(Lang::loader, function($bundle, $language, $file)
+{
+ return Lang::file($bundle, $language, $file);
+});
+
+/*
+|--------------------------------------------------------------------------
+| Attach The Laravel Profiler
+|--------------------------------------------------------------------------
+|
+| If the profiler is enabled, we will attach it to the Laravel events
+| for both queries and logs. This allows the profiler to intercept
+| any of the queries or logs performed by the application.
+|
+*/
+
+if (Config::get('application.profiler'))
+{
+ Profiler::attach();
+}
+
+/*
+|--------------------------------------------------------------------------
+| Enable The Blade View Engine
+|--------------------------------------------------------------------------
+|
+| The Blade view engine provides a clean, beautiful templating language
+| for your application, including syntax for echoing data and all of
+| the typical PHP control structures. We'll simply enable it here.
+|
+*/
+
+Blade::sharpen();
+
+/*
+|--------------------------------------------------------------------------
+| Set The Default Timezone
+|--------------------------------------------------------------------------
+|
+| We need to set the default timezone for the application. This controls
+| the timezone that will be used by any of the date methods and classes
+| utilized by Laravel or your application. The timezone may be set in
+| your application configuration file.
+|
+*/
+
+date_default_timezone_set(Config::get('application.timezone'));
+
+/*
+|--------------------------------------------------------------------------
+| Start / Load The User Session
+|--------------------------------------------------------------------------
+|
+| Sessions allow the web, which is stateless, to simulate state. In other
+| words, sessions allow you to store information about the current user
+| and state of your application. Here we'll just fire up the session
+| if a session driver has been configured.
+|
+*/
+
+if ( ! Request::cli() and Config::get('session.driver') !== '')
+{
+ Session::load();
+}
\ No newline at end of file
diff --git a/application/tasks/.gitignore b/application/tasks/.gitignore
new file mode 100644
index 0000000..e69de29
diff --git a/application/tests/example.test.php b/application/tests/example.test.php
new file mode 100644
index 0000000..d9b330c
--- /dev/null
+++ b/application/tests/example.test.php
@@ -0,0 +1,15 @@
+assertTrue(true);
+ }
+
+}
\ No newline at end of file
diff --git a/application/views/error/404.php b/application/views/error/404.php
new file mode 100644
index 0000000..ade2026
--- /dev/null
+++ b/application/views/error/404.php
@@ -0,0 +1,125 @@
+
+
+
+
+
+ Error 404 - Not Found
+
+
+
+
+
+
+
+
+
+
+
+
Server Error: 404 (Not Found)
+
+
+
+
What does this mean?
+
+
+ We couldn't find the page you requested on our servers. We're really sorry
+ about that. It's our fault, not yours. We'll work hard to get this page
+ back online as soon as possible.
+
+
+
+ Perhaps you would like to go to our ?
+
+
+
+
+
\ No newline at end of file
diff --git a/application/views/error/500.php b/application/views/error/500.php
new file mode 100644
index 0000000..4ce7c06
--- /dev/null
+++ b/application/views/error/500.php
@@ -0,0 +1,125 @@
+
+
+
+
+
+ Error 500 - Internal Server Error
+
+
+
+
+
+
+
+
+
+
+
+
Server Error: 500 (Internal Server Error)
+
+
+
+
What does this mean?
+
+
+ Something went wrong on our servers while we were processing your request.
+ We're really sorry about this, and will work hard to get this resolved as
+ soon as possible.
+
+
+
+ Perhaps you would like to go to our ?
+
+
+
+
+
\ No newline at end of file
diff --git a/application/views/home/index.blade.php b/application/views/home/index.blade.php
new file mode 100644
index 0000000..ec7973d
--- /dev/null
+++ b/application/views/home/index.blade.php
@@ -0,0 +1,57 @@
+
+
+
+
+
+ Laravel: A Framework For Web Artisans
+
+ {{ HTML::style('laravel/css/style.css') }}
+
+
+
+
+
Laravel
+
A Framework For Web Artisans
+
+
+
+
+
+
+
Learn the terrain.
+
+
+ You've landed yourself on our default home page. The route that
+ is generating this page lives at:
+
+
+
{{ path('app') }}routes.php
+
+
And the view sitting before you can be found at:
+
+
{{ path('app') }}views/home/index.php
+
+
Grow in knowledge.
+
+
+ Learning to use Laravel is amazingly simple thanks to
+ its {{ HTML::link('docs', 'wonderful documentation') }}.
+
+
+
Create something beautiful.
+
+
+ Now that you're up and running, it's time to start creating!
+ Here are some links to help you get started:
+
", $text);
+ }
+ return $text;
+ }
+
+ function mdwp_strip_p($t) { return preg_replace('{?p>}i', '', $t); }
+
+ function mdwp_hide_tags($text) {
+ global $mdwp_hidden_tags, $mdwp_placeholders;
+ return str_replace($mdwp_hidden_tags, $mdwp_placeholders, $text);
+ }
+ function mdwp_show_tags($text) {
+ global $mdwp_hidden_tags, $mdwp_placeholders;
+ return str_replace($mdwp_placeholders, $mdwp_hidden_tags, $text);
+ }
+}
+
+
+### bBlog Plugin Info ###
+
+function identify_modifier_markdown() {
+ return array(
+ 'name' => 'markdown',
+ 'type' => 'modifier',
+ 'nicename' => 'PHP Markdown Extra',
+ 'description' => 'A text-to-HTML conversion tool for web writers',
+ 'authors' => 'Michel Fortin and John Gruber',
+ 'licence' => 'GPL',
+ 'version' => MARKDOWNEXTRA_VERSION,
+ 'help' => 'Markdown syntax allows you to write using an easy-to-read, easy-to-write plain text format. Based on the original Perl version by John Gruber. More...',
+ );
+}
+
+
+### Smarty Modifier Interface ###
+
+function smarty_modifier_markdown($text) {
+ return Markdown($text);
+}
+
+
+### Textile Compatibility Mode ###
+
+# Rename this file to "classTextile.php" and it can replace Textile everywhere.
+
+if (strcasecmp(substr(__FILE__, -16), "classTextile.php") == 0) {
+ # Try to include PHP SmartyPants. Should be in the same directory.
+ @include_once 'smartypants.php';
+ # Fake Textile class. It calls Markdown instead.
+ class Textile {
+ function TextileThis($text, $lite='', $encode='') {
+ if ($lite == '' && $encode == '') $text = Markdown($text);
+ if (function_exists('SmartyPants')) $text = SmartyPants($text);
+ return $text;
+ }
+ # Fake restricted version: restrictions are not supported for now.
+ function TextileRestricted($text, $lite='', $noimage='') {
+ return $this->TextileThis($text, $lite);
+ }
+ # Workaround to ensure compatibility with TextPattern 4.0.3.
+ function blockLite($text) { return $text; }
+ }
+}
+
+
+
+#
+# Markdown Parser Class
+#
+
+class Markdown_Parser {
+
+ # Regex to match balanced [brackets].
+ # Needed to insert a maximum bracked depth while converting to PHP.
+ var $nested_brackets_depth = 6;
+ var $nested_brackets_re;
+
+ var $nested_url_parenthesis_depth = 4;
+ var $nested_url_parenthesis_re;
+
+ # Table of hash values for escaped characters:
+ var $escape_chars = '\`*_{}[]()>#+-.!';
+ var $escape_chars_re;
+
+ # Change to ">" for HTML output.
+ var $empty_element_suffix = MARKDOWN_EMPTY_ELEMENT_SUFFIX;
+ var $tab_width = MARKDOWN_TAB_WIDTH;
+
+ # Change to `true` to disallow markup or entities.
+ var $no_markup = false;
+ var $no_entities = false;
+
+ # Predefined urls and titles for reference links and images.
+ var $predef_urls = array();
+ var $predef_titles = array();
+
+
+ function Markdown_Parser() {
+ #
+ # Constructor function. Initialize appropriate member variables.
+ #
+ $this->_initDetab();
+ $this->prepareItalicsAndBold();
+
+ $this->nested_brackets_re =
+ str_repeat('(?>[^\[\]]+|\[', $this->nested_brackets_depth).
+ str_repeat('\])*', $this->nested_brackets_depth);
+
+ $this->nested_url_parenthesis_re =
+ str_repeat('(?>[^()\s]+|\(', $this->nested_url_parenthesis_depth).
+ str_repeat('(?>\)))*', $this->nested_url_parenthesis_depth);
+
+ $this->escape_chars_re = '['.preg_quote($this->escape_chars).']';
+
+ # Sort document, block, and span gamut in ascendent priority order.
+ asort($this->document_gamut);
+ asort($this->block_gamut);
+ asort($this->span_gamut);
+ }
+
+
+ # Internal hashes used during transformation.
+ var $urls = array();
+ var $titles = array();
+ var $html_hashes = array();
+
+ # Status flag to avoid invalid nesting.
+ var $in_anchor = false;
+
+
+ function setup() {
+ #
+ # Called before the transformation process starts to setup parser
+ # states.
+ #
+ # Clear global hashes.
+ $this->urls = $this->predef_urls;
+ $this->titles = $this->predef_titles;
+ $this->html_hashes = array();
+
+ $in_anchor = false;
+ }
+
+ function teardown() {
+ #
+ # Called after the transformation process to clear any variable
+ # which may be taking up memory unnecessarly.
+ #
+ $this->urls = array();
+ $this->titles = array();
+ $this->html_hashes = array();
+ }
+
+
+ function transform($text) {
+ #
+ # Main function. Performs some preprocessing on the input text
+ # and pass it through the document gamut.
+ #
+ $this->setup();
+
+ # Remove UTF-8 BOM and marker character in input, if present.
+ $text = preg_replace('{^\xEF\xBB\xBF|\x1A}', '', $text);
+
+ # Standardize line endings:
+ # DOS to Unix and Mac to Unix
+ $text = preg_replace('{\r\n?}', "\n", $text);
+
+ # Make sure $text ends with a couple of newlines:
+ $text .= "\n\n";
+
+ # Convert all tabs to spaces.
+ $text = $this->detab($text);
+
+ # Turn block-level HTML blocks into hash entries
+ $text = $this->hashHTMLBlocks($text);
+
+ # Strip any lines consisting only of spaces and tabs.
+ # This makes subsequent regexen easier to write, because we can
+ # match consecutive blank lines with /\n+/ instead of something
+ # contorted like /[ ]*\n+/ .
+ $text = preg_replace('/^[ ]+$/m', '', $text);
+
+ # Run document gamut methods.
+ foreach ($this->document_gamut as $method => $priority) {
+ $text = $this->$method($text);
+ }
+
+ $this->teardown();
+
+ return $text . "\n";
+ }
+
+ var $document_gamut = array(
+ # Strip link definitions, store in hashes.
+ "stripLinkDefinitions" => 20,
+
+ "runBasicBlockGamut" => 30,
+ );
+
+
+ function stripLinkDefinitions($text) {
+ #
+ # Strips link definitions from text, stores the URLs and titles in
+ # hash references.
+ #
+ $less_than_tab = $this->tab_width - 1;
+
+ # Link defs are in the form: ^[id]: url "optional title"
+ $text = preg_replace_callback('{
+ ^[ ]{0,'.$less_than_tab.'}\[(.+)\][ ]?: # id = $1
+ [ ]*
+ \n? # maybe *one* newline
+ [ ]*
+ (?:
+ <(.+?)> # url = $2
+ |
+ (\S+?) # url = $3
+ )
+ [ ]*
+ \n? # maybe one newline
+ [ ]*
+ (?:
+ (?<=\s) # lookbehind for whitespace
+ ["(]
+ (.*?) # title = $4
+ [")]
+ [ ]*
+ )? # title is optional
+ (?:\n+|\Z)
+ }xm',
+ array(&$this, '_stripLinkDefinitions_callback'),
+ $text);
+ return $text;
+ }
+ function _stripLinkDefinitions_callback($matches) {
+ $link_id = strtolower($matches[1]);
+ $url = $matches[2] == '' ? $matches[3] : $matches[2];
+ $this->urls[$link_id] = $url;
+ $this->titles[$link_id] =& $matches[4];
+ return ''; # String that will replace the block
+ }
+
+
+ function hashHTMLBlocks($text) {
+ if ($this->no_markup) return $text;
+
+ $less_than_tab = $this->tab_width - 1;
+
+ # Hashify HTML blocks:
+ # We only want to do this for block-level HTML tags, such as headers,
+ # lists, and tables. That's because we still want to wrap
s around
+ # "paragraphs" that are wrapped in non-block-level tags, such as anchors,
+ # phrase emphasis, and spans. The list of tags we're looking for is
+ # hard-coded:
+ #
+ # * List "a" is made of tags which can be both inline or block-level.
+ # These will be treated block-level when the start tag is alone on
+ # its line, otherwise they're not matched here and will be taken as
+ # inline later.
+ # * List "b" is made of tags which are always block-level;
+ #
+ $block_tags_a_re = 'ins|del';
+ $block_tags_b_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|'.
+ 'script|noscript|form|fieldset|iframe|math';
+
+ # Regular expression for the content of a block tag.
+ $nested_tags_level = 4;
+ $attr = '
+ (?> # optional tag attributes
+ \s # starts with whitespace
+ (?>
+ [^>"/]+ # text outside quotes
+ |
+ /+(?!>) # slash not followed by ">"
+ |
+ "[^"]*" # text inside double quotes (tolerate ">")
+ |
+ \'[^\']*\' # text inside single quotes (tolerate ">")
+ )*
+ )?
+ ';
+ $content =
+ str_repeat('
+ (?>
+ [^<]+ # content without tag
+ |
+ <\2 # nested opening tag
+ '.$attr.' # attributes
+ (?>
+ />
+ |
+ >', $nested_tags_level). # end of opening tag
+ '.*?'. # last level nested tag content
+ str_repeat('
+ \2\s*> # closing nested tag
+ )
+ |
+ <(?!/\2\s*> # other tags with a different name
+ )
+ )*',
+ $nested_tags_level);
+ $content2 = str_replace('\2', '\3', $content);
+
+ # First, look for nested blocks, e.g.:
+ #
+ #
+ # tags for inner block must be indented.
+ #
+ #
+ #
+ # The outermost tags must start at the left margin for this to match, and
+ # the inner nested divs must be indented.
+ # We need to do this before the next, more liberal match, because the next
+ # match will start at the first `
` and stop at the first `
`.
+ $text = preg_replace_callback('{(?>
+ (?>
+ (?<=\n\n) # Starting after a blank line
+ | # or
+ \A\n? # the beginning of the doc
+ )
+ ( # save in $1
+
+ # Match from `\n` to `\n`, handling nested tags
+ # in between.
+
+ [ ]{0,'.$less_than_tab.'}
+ <('.$block_tags_b_re.')# start tag = $2
+ '.$attr.'> # attributes followed by > and \n
+ '.$content.' # content, support nesting
+ \2> # the matching end tag
+ [ ]* # trailing spaces/tabs
+ (?=\n+|\Z) # followed by a newline or end of document
+
+ | # Special version for tags of group a.
+
+ [ ]{0,'.$less_than_tab.'}
+ <('.$block_tags_a_re.')# start tag = $3
+ '.$attr.'>[ ]*\n # attributes followed by >
+ '.$content2.' # content, support nesting
+ \3> # the matching end tag
+ [ ]* # trailing spaces/tabs
+ (?=\n+|\Z) # followed by a newline or end of document
+
+ | # Special case just for . It was easier to make a special
+ # case than to make the other regex more complicated.
+
+ [ ]{0,'.$less_than_tab.'}
+ <(hr) # start tag = $2
+ '.$attr.' # attributes
+ /?> # the matching end tag
+ [ ]*
+ (?=\n{2,}|\Z) # followed by a blank line or end of document
+
+ | # Special case for standalone HTML comments:
+
+ [ ]{0,'.$less_than_tab.'}
+ (?s:
+
+ )
+ [ ]*
+ (?=\n{2,}|\Z) # followed by a blank line or end of document
+
+ | # PHP and ASP-style processor instructions ( and <%)
+
+ [ ]{0,'.$less_than_tab.'}
+ (?s:
+ <([?%]) # $2
+ .*?
+ \2>
+ )
+ [ ]*
+ (?=\n{2,}|\Z) # followed by a blank line or end of document
+
+ )
+ )}Sxmi',
+ array(&$this, '_hashHTMLBlocks_callback'),
+ $text);
+
+ return $text;
+ }
+ function _hashHTMLBlocks_callback($matches) {
+ $text = $matches[1];
+ $key = $this->hashBlock($text);
+ return "\n\n$key\n\n";
+ }
+
+
+ function hashPart($text, $boundary = 'X') {
+ #
+ # Called whenever a tag must be hashed when a function insert an atomic
+ # element in the text stream. Passing $text to through this function gives
+ # a unique text-token which will be reverted back when calling unhash.
+ #
+ # The $boundary argument specify what character should be used to surround
+ # the token. By convension, "B" is used for block elements that needs not
+ # to be wrapped into paragraph tags at the end, ":" is used for elements
+ # that are word separators and "X" is used in the general case.
+ #
+ # Swap back any tag hash found in $text so we do not have to `unhash`
+ # multiple times at the end.
+ $text = $this->unhash($text);
+
+ # Then hash the block.
+ static $i = 0;
+ $key = "$boundary\x1A" . ++$i . $boundary;
+ $this->html_hashes[$key] = $text;
+ return $key; # String that will replace the tag.
+ }
+
+
+ function hashBlock($text) {
+ #
+ # Shortcut function for hashPart with block-level boundaries.
+ #
+ return $this->hashPart($text, 'B');
+ }
+
+
+ var $block_gamut = array(
+ #
+ # These are all the transformations that form block-level
+ # tags like paragraphs, headers, and list items.
+ #
+ "doHeaders" => 10,
+ "doHorizontalRules" => 20,
+
+ "doLists" => 40,
+ "doCodeBlocks" => 50,
+ "doBlockQuotes" => 60,
+ );
+
+ function runBlockGamut($text) {
+ #
+ # Run block gamut tranformations.
+ #
+ # We need to escape raw HTML in Markdown source before doing anything
+ # else. This need to be done for each block, and not only at the
+ # begining in the Markdown function since hashed blocks can be part of
+ # list items and could have been indented. Indented blocks would have
+ # been seen as a code block in a previous pass of hashHTMLBlocks.
+ $text = $this->hashHTMLBlocks($text);
+
+ return $this->runBasicBlockGamut($text);
+ }
+
+ function runBasicBlockGamut($text) {
+ #
+ # Run block gamut tranformations, without hashing HTML blocks. This is
+ # useful when HTML blocks are known to be already hashed, like in the first
+ # whole-document pass.
+ #
+ foreach ($this->block_gamut as $method => $priority) {
+ $text = $this->$method($text);
+ }
+
+ # Finally form paragraph and restore hashed blocks.
+ $text = $this->formParagraphs($text);
+
+ return $text;
+ }
+
+
+ function doHorizontalRules($text) {
+ # Do Horizontal Rules:
+ return preg_replace(
+ '{
+ ^[ ]{0,3} # Leading space
+ ([-*_]) # $1: First marker
+ (?> # Repeated marker group
+ [ ]{0,2} # Zero, one, or two spaces.
+ \1 # Marker character
+ ){2,} # Group repeated at least twice
+ [ ]* # Tailing spaces
+ $ # End of line.
+ }mx',
+ "\n".$this->hashBlock("empty_element_suffix")."\n",
+ $text);
+ }
+
+
+ var $span_gamut = array(
+ #
+ # These are all the transformations that occur *within* block-level
+ # tags like paragraphs, headers, and list items.
+ #
+ # Process character escapes, code spans, and inline HTML
+ # in one shot.
+ "parseSpan" => -30,
+
+ # Process anchor and image tags. Images must come first,
+ # because ![foo][f] looks like an anchor.
+ "doImages" => 10,
+ "doAnchors" => 20,
+
+ # Make links out of things like ``
+ # Must come after doAnchors, because you can use < and >
+ # delimiters in inline links like [this]().
+ "doAutoLinks" => 30,
+ "encodeAmpsAndAngles" => 40,
+
+ "doItalicsAndBold" => 50,
+ "doHardBreaks" => 60,
+ );
+
+ function runSpanGamut($text) {
+ #
+ # Run span gamut tranformations.
+ #
+ foreach ($this->span_gamut as $method => $priority) {
+ $text = $this->$method($text);
+ }
+
+ return $text;
+ }
+
+
+ function doHardBreaks($text) {
+ # Do hard breaks:
+ return preg_replace_callback('/ {2,}\n/',
+ array(&$this, '_doHardBreaks_callback'), $text);
+ }
+ function _doHardBreaks_callback($matches) {
+ return $this->hashPart(" empty_element_suffix\n");
+ }
+
+
+ function doAnchors($text) {
+ #
+ # Turn Markdown link shortcuts into XHTML tags.
+ #
+ if ($this->in_anchor) return $text;
+ $this->in_anchor = true;
+
+ #
+ # First, handle reference-style links: [link text] [id]
+ #
+ $text = preg_replace_callback('{
+ ( # wrap whole match in $1
+ \[
+ ('.$this->nested_brackets_re.') # link text = $2
+ \]
+
+ [ ]? # one optional space
+ (?:\n[ ]*)? # one optional newline followed by spaces
+
+ \[
+ (.*?) # id = $3
+ \]
+ )
+ }xs',
+ array(&$this, '_doAnchors_reference_callback'), $text);
+
+ #
+ # Next, inline-style links: [link text](url "optional title")
+ #
+ $text = preg_replace_callback('{
+ ( # wrap whole match in $1
+ \[
+ ('.$this->nested_brackets_re.') # link text = $2
+ \]
+ \( # literal paren
+ [ \n]*
+ (?:
+ <(.+?)> # href = $3
+ |
+ ('.$this->nested_url_parenthesis_re.') # href = $4
+ )
+ [ \n]*
+ ( # $5
+ ([\'"]) # quote char = $6
+ (.*?) # Title = $7
+ \6 # matching quote
+ [ \n]* # ignore any spaces/tabs between closing quote and )
+ )? # title is optional
+ \)
+ )
+ }xs',
+ array(&$this, '_doAnchors_inline_callback'), $text);
+
+ #
+ # Last, handle reference-style shortcuts: [link text]
+ # These must come last in case you've also got [link text][1]
+ # or [link text](/foo)
+ #
+ $text = preg_replace_callback('{
+ ( # wrap whole match in $1
+ \[
+ ([^\[\]]+) # link text = $2; can\'t contain [ or ]
+ \]
+ )
+ }xs',
+ array(&$this, '_doAnchors_reference_callback'), $text);
+
+ $this->in_anchor = false;
+ return $text;
+ }
+ function _doAnchors_reference_callback($matches) {
+ $whole_match = $matches[1];
+ $link_text = $matches[2];
+ $link_id =& $matches[3];
+
+ if ($link_id == "") {
+ # for shortcut links like [this][] or [this].
+ $link_id = $link_text;
+ }
+
+ # lower-case and turn embedded newlines into spaces
+ $link_id = strtolower($link_id);
+ $link_id = preg_replace('{[ ]?\n}', ' ', $link_id);
+
+ if (isset($this->urls[$link_id])) {
+ $url = $this->urls[$link_id];
+ $url = URL::to($url);
+ $url = $this->encodeAttribute($url);
+
+ $result = "titles[$link_id] ) ) {
+ $title = $this->titles[$link_id];
+ $title = $this->encodeAttribute($title);
+ $result .= " title=\"$title\"";
+ }
+
+ $link_text = $this->runSpanGamut($link_text);
+ $result .= ">$link_text";
+ $result = $this->hashPart($result);
+ }
+ else {
+ $result = $whole_match;
+ }
+ return $result;
+ }
+ function _doAnchors_inline_callback($matches) {
+ $whole_match = $matches[1];
+ $link_text = $this->runSpanGamut($matches[2]);
+ $url = $matches[3] == '' ? $matches[4] : $matches[3];
+ $title =& $matches[7];
+
+ $url = URL::to($url);
+ $url = $this->encodeAttribute($url);
+
+ $result = "encodeAttribute($title);
+ $result .= " title=\"$title\"";
+ }
+
+ $link_text = $this->runSpanGamut($link_text);
+ $result .= ">$link_text";
+
+ return $this->hashPart($result);
+ }
+
+
+ function doImages($text) {
+ #
+ # Turn Markdown image shortcuts into tags.
+ #
+ #
+ # First, handle reference-style labeled images: ![alt text][id]
+ #
+ $text = preg_replace_callback('{
+ ( # wrap whole match in $1
+ !\[
+ ('.$this->nested_brackets_re.') # alt text = $2
+ \]
+
+ [ ]? # one optional space
+ (?:\n[ ]*)? # one optional newline followed by spaces
+
+ \[
+ (.*?) # id = $3
+ \]
+
+ )
+ }xs',
+ array(&$this, '_doImages_reference_callback'), $text);
+
+ #
+ # Next, handle inline images: ![alt text](url "optional title")
+ # Don't forget: encode * and _
+ #
+ $text = preg_replace_callback('{
+ ( # wrap whole match in $1
+ !\[
+ ('.$this->nested_brackets_re.') # alt text = $2
+ \]
+ \s? # One optional whitespace character
+ \( # literal paren
+ [ \n]*
+ (?:
+ <(\S*)> # src url = $3
+ |
+ ('.$this->nested_url_parenthesis_re.') # src url = $4
+ )
+ [ \n]*
+ ( # $5
+ ([\'"]) # quote char = $6
+ (.*?) # title = $7
+ \6 # matching quote
+ [ \n]*
+ )? # title is optional
+ \)
+ )
+ }xs',
+ array(&$this, '_doImages_inline_callback'), $text);
+
+ return $text;
+ }
+ function _doImages_reference_callback($matches) {
+ $whole_match = $matches[1];
+ $alt_text = $matches[2];
+ $link_id = strtolower($matches[3]);
+
+ if ($link_id == "") {
+ $link_id = strtolower($alt_text); # for shortcut links like ![this][].
+ }
+
+ $alt_text = $this->encodeAttribute($alt_text);
+ if (isset($this->urls[$link_id])) {
+ $url = $this->encodeAttribute($this->urls[$link_id]);
+ $result = "titles[$link_id])) {
+ $title = $this->titles[$link_id];
+ $title = $this->encodeAttribute($title);
+ $result .= " title=\"$title\"";
+ }
+ $result .= $this->empty_element_suffix;
+ $result = $this->hashPart($result);
+ }
+ else {
+ # If there's no such link ID, leave intact:
+ $result = $whole_match;
+ }
+
+ return $result;
+ }
+ function _doImages_inline_callback($matches) {
+ $whole_match = $matches[1];
+ $alt_text = $matches[2];
+ $url = $matches[3] == '' ? $matches[4] : $matches[3];
+ $title =& $matches[7];
+
+ $alt_text = $this->encodeAttribute($alt_text);
+ $url = $this->encodeAttribute($url);
+ $result = "encodeAttribute($title);
+ $result .= " title=\"$title\""; # $title already quoted
+ }
+ $result .= $this->empty_element_suffix;
+
+ return $this->hashPart($result);
+ }
+
+
+ function doHeaders($text) {
+ # Setext-style headers:
+ # Header 1
+ # ========
+ #
+ # Header 2
+ # --------
+ #
+ $text = preg_replace_callback('{ ^(.+?)[ ]*\n(=+|-+)[ ]*\n+ }mx',
+ array(&$this, '_doHeaders_callback_setext'), $text);
+
+ # atx-style headers:
+ # # Header 1
+ # ## Header 2
+ # ## Header 2 with closing hashes ##
+ # ...
+ # ###### Header 6
+ #
+ $text = preg_replace_callback('{
+ ^(\#{1,6}) # $1 = string of #\'s
+ [ ]*
+ (.+?) # $2 = Header text
+ [ ]*
+ \#* # optional closing #\'s (not counted)
+ \n+
+ }xm',
+ array(&$this, '_doHeaders_callback_atx'), $text);
+
+ return $text;
+ }
+ function _doHeaders_callback_setext($matches) {
+ # Terrible hack to check we haven't found an empty list item.
+ if ($matches[2] == '-' && preg_match('{^-(?: |$)}', $matches[1]))
+ return $matches[0];
+
+ $level = $matches[2]{0} == '=' ? 1 : 2;
+ $block = "".$this->runSpanGamut($matches[1])."";
+ return "\n" . $this->hashBlock($block) . "\n\n";
+ }
+ function _doHeaders_callback_atx($matches) {
+ $level = strlen($matches[1]);
+ $block = "".$this->runSpanGamut($matches[2])."";
+ return "\n" . $this->hashBlock($block) . "\n\n";
+ }
+
+
+ function doLists($text) {
+ #
+ # Form HTML ordered (numbered) and unordered (bulleted) lists.
+ #
+ $less_than_tab = $this->tab_width - 1;
+
+ # Re-usable patterns to match list item bullets and number markers:
+ $marker_ul_re = '[*+-]';
+ $marker_ol_re = '\d+[\.]';
+ $marker_any_re = "(?:$marker_ul_re|$marker_ol_re)";
+
+ $markers_relist = array(
+ $marker_ul_re => $marker_ol_re,
+ $marker_ol_re => $marker_ul_re,
+ );
+
+ foreach ($markers_relist as $marker_re => $other_marker_re) {
+ # Re-usable pattern to match any entirel ul or ol list:
+ $whole_list_re = '
+ ( # $1 = whole list
+ ( # $2
+ ([ ]{0,'.$less_than_tab.'}) # $3 = number of spaces
+ ('.$marker_re.') # $4 = first list item marker
+ [ ]+
+ )
+ (?s:.+?)
+ ( # $5
+ \z
+ |
+ \n{2,}
+ (?=\S)
+ (?! # Negative lookahead for another list item marker
+ [ ]*
+ '.$marker_re.'[ ]+
+ )
+ |
+ (?= # Lookahead for another kind of list
+ \n
+ \3 # Must have the same indentation
+ '.$other_marker_re.'[ ]+
+ )
+ )
+ )
+ '; // mx
+
+ # We use a different prefix before nested lists than top-level lists.
+ # See extended comment in _ProcessListItems().
+
+ if ($this->list_level) {
+ $text = preg_replace_callback('{
+ ^
+ '.$whole_list_re.'
+ }mx',
+ array(&$this, '_doLists_callback'), $text);
+ }
+ else {
+ $text = preg_replace_callback('{
+ (?:(?<=\n)\n|\A\n?) # Must eat the newline
+ '.$whole_list_re.'
+ }mx',
+ array(&$this, '_doLists_callback'), $text);
+ }
+ }
+
+ return $text;
+ }
+ function _doLists_callback($matches) {
+ # Re-usable patterns to match list item bullets and number markers:
+ $marker_ul_re = '[*+-]';
+ $marker_ol_re = '\d+[\.]';
+ $marker_any_re = "(?:$marker_ul_re|$marker_ol_re)";
+
+ $list = $matches[1];
+ $list_type = preg_match("/$marker_ul_re/", $matches[4]) ? "ul" : "ol";
+
+ $marker_any_re = ( $list_type == "ul" ? $marker_ul_re : $marker_ol_re );
+
+ $list .= "\n";
+ $result = $this->processListItems($list, $marker_any_re);
+
+ $result = $this->hashBlock("<$list_type>\n" . $result . "$list_type>");
+ return "\n". $result ."\n\n";
+ }
+
+ var $list_level = 0;
+
+ function processListItems($list_str, $marker_any_re) {
+ #
+ # Process the contents of a single ordered or unordered list, splitting it
+ # into individual list items.
+ #
+ # The $this->list_level global keeps track of when we're inside a list.
+ # Each time we enter a list, we increment it; when we leave a list,
+ # we decrement. If it's zero, we're not in a list anymore.
+ #
+ # We do this because when we're not inside a list, we want to treat
+ # something like this:
+ #
+ # I recommend upgrading to version
+ # 8. Oops, now this line is treated
+ # as a sub-list.
+ #
+ # As a single paragraph, despite the fact that the second line starts
+ # with a digit-period-space sequence.
+ #
+ # Whereas when we're inside a list (or sub-list), that line will be
+ # treated as the start of a sub-list. What a kludge, huh? This is
+ # an aspect of Markdown's syntax that's hard to parse perfectly
+ # without resorting to mind-reading. Perhaps the solution is to
+ # change the syntax rules such that sub-lists must start with a
+ # starting cardinal number; e.g. "1." or "a.".
+
+ $this->list_level++;
+
+ # trim trailing blank lines:
+ $list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str);
+
+ $list_str = preg_replace_callback('{
+ (\n)? # leading line = $1
+ (^[ ]*) # leading whitespace = $2
+ ('.$marker_any_re.' # list marker and space = $3
+ (?:[ ]+|(?=\n)) # space only required if item is not empty
+ )
+ ((?s:.*?)) # list item text = $4
+ (?:(\n+(?=\n))|\n) # tailing blank line = $5
+ (?= \n* (\z | \2 ('.$marker_any_re.') (?:[ ]+|(?=\n))))
+ }xm',
+ array(&$this, '_processListItems_callback'), $list_str);
+
+ $this->list_level--;
+ return $list_str;
+ }
+ function _processListItems_callback($matches) {
+ $item = $matches[4];
+ $leading_line =& $matches[1];
+ $leading_space =& $matches[2];
+ $marker_space = $matches[3];
+ $tailing_blank_line =& $matches[5];
+
+ if ($leading_line || $tailing_blank_line ||
+ preg_match('/\n{2,}/', $item))
+ {
+ # Replace marker with the appropriate whitespace indentation
+ $item = $leading_space . str_repeat(' ', strlen($marker_space)) . $item;
+ $item = $this->runBlockGamut($this->outdent($item)."\n");
+ }
+ else {
+ # Recursion for sub-lists:
+ $item = $this->doLists($this->outdent($item));
+ $item = preg_replace('/\n+$/', '', $item);
+ $item = $this->runSpanGamut($item);
+ }
+
+ return "
" . $item . "
\n";
+ }
+
+
+ function doCodeBlocks($text) {
+ #
+ # Process Markdown `
` blocks.
+ #
+ $text = preg_replace_callback('{
+ (?:\n\n|\A\n?)
+ ( # $1 = the code block -- one or more lines, starting with a space/tab
+ (?>
+ [ ]{'.$this->tab_width.'} # Lines must start with a tab or a tab-width of spaces
+ .*\n+
+ )+
+ )
+ ((?=^[ ]{0,'.$this->tab_width.'}\S)|\Z) # Lookahead for non-space at line-start, or end of doc
+ }xm',
+ array(&$this, '_doCodeBlocks_callback'), $text);
+
+ return $text;
+ }
+ function _doCodeBlocks_callback($matches) {
+ $codeblock = $matches[1];
+
+ $codeblock = $this->outdent($codeblock);
+ $codeblock = htmlspecialchars($codeblock, ENT_NOQUOTES);
+
+ # trim leading newlines and trailing newlines
+ $codeblock = preg_replace('/\A\n+|\n+\z/', '', $codeblock);
+
+ $codeblock = "
$codeblock\n
";
+ return "\n\n".$this->hashBlock($codeblock)."\n\n";
+ }
+
+
+ function makeCodeSpan($code) {
+ #
+ # Create a code span markup for $code. Called from handleSpanToken.
+ #
+ $code = htmlspecialchars(trim($code), ENT_NOQUOTES);
+ return $this->hashPart("$code");
+ }
+
+
+ var $em_relist = array(
+ '' => '(?:(? '(?<=\S|^)(? '(?<=\S|^)(? '(?:(? '(?<=\S|^)(? '(?<=\S|^)(? '(?:(? '(?<=\S|^)(? '(?<=\S|^)(?em_relist as $em => $em_re) {
+ foreach ($this->strong_relist as $strong => $strong_re) {
+ # Construct list of allowed token expressions.
+ $token_relist = array();
+ if (isset($this->em_strong_relist["$em$strong"])) {
+ $token_relist[] = $this->em_strong_relist["$em$strong"];
+ }
+ $token_relist[] = $em_re;
+ $token_relist[] = $strong_re;
+
+ # Construct master expression from list.
+ $token_re = '{('. implode('|', $token_relist) .')}';
+ $this->em_strong_prepared_relist["$em$strong"] = $token_re;
+ }
+ }
+ }
+
+ function doItalicsAndBold($text) {
+ $token_stack = array('');
+ $text_stack = array('');
+ $em = '';
+ $strong = '';
+ $tree_char_em = false;
+
+ while (1) {
+ #
+ # Get prepared regular expression for seraching emphasis tokens
+ # in current context.
+ #
+ $token_re = $this->em_strong_prepared_relist["$em$strong"];
+
+ #
+ # Each loop iteration search for the next emphasis token.
+ # Each token is then passed to handleSpanToken.
+ #
+ $parts = preg_split($token_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
+ $text_stack[0] .= $parts[0];
+ $token =& $parts[1];
+ $text =& $parts[2];
+
+ if (empty($token)) {
+ # Reached end of text span: empty stack without emitting.
+ # any more emphasis.
+ while ($token_stack[0]) {
+ $text_stack[1] .= array_shift($token_stack);
+ $text_stack[0] .= array_shift($text_stack);
+ }
+ break;
+ }
+
+ $token_len = strlen($token);
+ if ($tree_char_em) {
+ # Reached closing marker while inside a three-char emphasis.
+ if ($token_len == 3) {
+ # Three-char closing marker, close em and strong.
+ array_shift($token_stack);
+ $span = array_shift($text_stack);
+ $span = $this->runSpanGamut($span);
+ $span = "$span";
+ $text_stack[0] .= $this->hashPart($span);
+ $em = '';
+ $strong = '';
+ } else {
+ # Other closing marker: close one em or strong and
+ # change current token state to match the other
+ $token_stack[0] = str_repeat($token{0}, 3-$token_len);
+ $tag = $token_len == 2 ? "strong" : "em";
+ $span = $text_stack[0];
+ $span = $this->runSpanGamut($span);
+ $span = "<$tag>$span$tag>";
+ $text_stack[0] = $this->hashPart($span);
+ $$tag = ''; # $$tag stands for $em or $strong
+ }
+ $tree_char_em = false;
+ } else if ($token_len == 3) {
+ if ($em) {
+ # Reached closing marker for both em and strong.
+ # Closing strong marker:
+ for ($i = 0; $i < 2; ++$i) {
+ $shifted_token = array_shift($token_stack);
+ $tag = strlen($shifted_token) == 2 ? "strong" : "em";
+ $span = array_shift($text_stack);
+ $span = $this->runSpanGamut($span);
+ $span = "<$tag>$span$tag>";
+ $text_stack[0] .= $this->hashPart($span);
+ $$tag = ''; # $$tag stands for $em or $strong
+ }
+ } else {
+ # Reached opening three-char emphasis marker. Push on token
+ # stack; will be handled by the special condition above.
+ $em = $token{0};
+ $strong = "$em$em";
+ array_unshift($token_stack, $token);
+ array_unshift($text_stack, '');
+ $tree_char_em = true;
+ }
+ } else if ($token_len == 2) {
+ if ($strong) {
+ # Unwind any dangling emphasis marker:
+ if (strlen($token_stack[0]) == 1) {
+ $text_stack[1] .= array_shift($token_stack);
+ $text_stack[0] .= array_shift($text_stack);
+ }
+ # Closing strong marker:
+ array_shift($token_stack);
+ $span = array_shift($text_stack);
+ $span = $this->runSpanGamut($span);
+ $span = "$span";
+ $text_stack[0] .= $this->hashPart($span);
+ $strong = '';
+ } else {
+ array_unshift($token_stack, $token);
+ array_unshift($text_stack, '');
+ $strong = $token;
+ }
+ } else {
+ # Here $token_len == 1
+ if ($em) {
+ if (strlen($token_stack[0]) == 1) {
+ # Closing emphasis marker:
+ array_shift($token_stack);
+ $span = array_shift($text_stack);
+ $span = $this->runSpanGamut($span);
+ $span = "$span";
+ $text_stack[0] .= $this->hashPart($span);
+ $em = '';
+ } else {
+ $text_stack[0] .= $token;
+ }
+ } else {
+ array_unshift($token_stack, $token);
+ array_unshift($text_stack, '');
+ $em = $token;
+ }
+ }
+ }
+ return $text_stack[0];
+ }
+
+
+ function doBlockQuotes($text) {
+ $text = preg_replace_callback('/
+ ( # Wrap whole match in $1
+ (?>
+ ^[ ]*>[ ]? # ">" at the start of a line
+ .+\n # rest of the first line
+ (.+\n)* # subsequent consecutive lines
+ \n* # blanks
+ )+
+ )
+ /xm',
+ array(&$this, '_doBlockQuotes_callback'), $text);
+
+ return $text;
+ }
+ function _doBlockQuotes_callback($matches) {
+ $bq = $matches[1];
+ # trim one level of quoting - trim whitespace-only lines
+ $bq = preg_replace('/^[ ]*>[ ]?|^[ ]+$/m', '', $bq);
+ $bq = $this->runBlockGamut($bq); # recurse
+
+ $bq = preg_replace('/^/m', " ", $bq);
+ # These leading spaces cause problem with
content,
+ # so we need to fix that:
+ $bq = preg_replace_callback('{(\s*
+ #
+ # Based by a filter by Matthew Wickline, posted to BBEdit-Talk.
+ # With some optimizations by Milian Wolff.
+ #
+ $addr = "mailto:" . $addr;
+ $chars = preg_split('/(? $char) {
+ $ord = ord($char);
+ # Ignore non-ascii chars.
+ if ($ord < 128) {
+ $r = ($seed * (1 + $key)) % 100; # Pseudo-random function.
+ # roughly 10% raw, 45% hex, 45% dec
+ # '@' *must* be encoded. I insist.
+ if ($r > 90 && $char != '@') /* do nothing */;
+ else if ($r < 45) $chars[$key] = ''.dechex($ord).';';
+ else $chars[$key] = ''.$ord.';';
+ }
+ }
+
+ $addr = implode('', $chars);
+ $text = implode('', array_slice($chars, 7)); # text without `mailto:`
+ $addr = "$text";
+
+ return $addr;
+ }
+
+
+ function parseSpan($str) {
+ #
+ # Take the string $str and parse it into tokens, hashing embeded HTML,
+ # escaped characters and handling code spans.
+ #
+ $output = '';
+
+ $span_re = '{
+ (
+ \\\\'.$this->escape_chars_re.'
+ |
+ (?no_markup ? '' : '
+ |
+ # comment
+ |
+ <\?.*?\?> | <%.*?%> # processing instruction
+ |
+ <[/!$]?[-a-zA-Z0-9:_]+ # regular tags
+ (?>
+ \s
+ (?>[^"\'>]+|"[^"]*"|\'[^\']*\')*
+ )?
+ >
+ ').'
+ )
+ }xs';
+
+ while (1) {
+ #
+ # Each loop iteration seach for either the next tag, the next
+ # openning code span marker, or the next escaped character.
+ # Each token is then passed to handleSpanToken.
+ #
+ $parts = preg_split($span_re, $str, 2, PREG_SPLIT_DELIM_CAPTURE);
+
+ # Create token from text preceding tag.
+ if ($parts[0] != "") {
+ $output .= $parts[0];
+ }
+
+ # Check if we reach the end.
+ if (isset($parts[1])) {
+ $output .= $this->handleSpanToken($parts[1], $parts[2]);
+ $str = $parts[2];
+ }
+ else {
+ break;
+ }
+ }
+
+ return $output;
+ }
+
+
+ function handleSpanToken($token, &$str) {
+ #
+ # Handle $token provided by parseSpan by determining its nature and
+ # returning the corresponding value that should replace it.
+ #
+ switch ($token{0}) {
+ case "\\":
+ return $this->hashPart("". ord($token{1}). ";");
+ case "`":
+ # Search for end marker in remaining text.
+ if (preg_match('/^(.*?[^`])'.preg_quote($token).'(?!`)(.*)$/sm',
+ $str, $matches))
+ {
+ $str = $matches[2];
+ $codespan = $this->makeCodeSpan($matches[1]);
+ return $this->hashPart($codespan);
+ }
+ return $token; // return as text since no ending marker found.
+ default:
+ return $this->hashPart($token);
+ }
+ }
+
+
+ function outdent($text) {
+ #
+ # Remove one level of line-leading tabs or spaces
+ #
+ return preg_replace('/^(\t|[ ]{1,'.$this->tab_width.'})/m', '', $text);
+ }
+
+
+ # String length function for detab. `_initDetab` will create a function to
+ # hanlde UTF-8 if the default function does not exist.
+ var $utf8_strlen = 'mb_strlen';
+
+ function detab($text) {
+ #
+ # Replace tabs with the appropriate amount of space.
+ #
+ # For each line we separate the line in blocks delemited by
+ # tab characters. Then we reconstruct every line by adding the
+ # appropriate number of space between each blocks.
+
+ $text = preg_replace_callback('/^.*\t.*$/m',
+ array(&$this, '_detab_callback'), $text);
+
+ return $text;
+ }
+ function _detab_callback($matches) {
+ $line = $matches[0];
+ $strlen = $this->utf8_strlen; # strlen function for UTF-8.
+
+ # Split in blocks.
+ $blocks = explode("\t", $line);
+ # Add each blocks to the line.
+ $line = $blocks[0];
+ unset($blocks[0]); # Do not add first block twice.
+ foreach ($blocks as $block) {
+ # Calculate amount of space, insert spaces, insert block.
+ $amount = $this->tab_width -
+ $strlen($line, 'UTF-8') % $this->tab_width;
+ $line .= str_repeat(" ", $amount) . $block;
+ }
+ return $line;
+ }
+ function _initDetab() {
+ #
+ # Check for the availability of the function in the `utf8_strlen` property
+ # (initially `mb_strlen`). If the function is not available, create a
+ # function that will loosely count the number of UTF-8 characters with a
+ # regular expression.
+ #
+ if (function_exists($this->utf8_strlen)) return;
+ $this->utf8_strlen = create_function('$text', 'return preg_match_all(
+ "/[\\\\x00-\\\\xBF]|[\\\\xC0-\\\\xFF][\\\\x80-\\\\xBF]*/",
+ $text, $m);');
+ }
+
+
+ function unhash($text) {
+ #
+ # Swap back in all the tags hashed by _HashHTMLBlocks.
+ #
+ return preg_replace_callback('/(.)\x1A[0-9]+\1/',
+ array(&$this, '_unhash_callback'), $text);
+ }
+ function _unhash_callback($matches) {
+ return $this->html_hashes[$matches[0]];
+ }
+
+}
+
+
+#
+# Markdown Extra Parser Class
+#
+
+class MarkdownExtra_Parser extends Markdown_Parser {
+
+ # Prefix for footnote ids.
+ var $fn_id_prefix = "";
+
+ # Optional title attribute for footnote links and backlinks.
+ var $fn_link_title = MARKDOWN_FN_LINK_TITLE;
+ var $fn_backlink_title = MARKDOWN_FN_BACKLINK_TITLE;
+
+ # Optional class attribute for footnote links and backlinks.
+ var $fn_link_class = MARKDOWN_FN_LINK_CLASS;
+ var $fn_backlink_class = MARKDOWN_FN_BACKLINK_CLASS;
+
+ # Predefined abbreviations.
+ var $predef_abbr = array();
+
+
+ function MarkdownExtra_Parser() {
+ #
+ # Constructor function. Initialize the parser object.
+ #
+ # Add extra escapable characters before parent constructor
+ # initialize the table.
+ $this->escape_chars .= ':|';
+
+ # Insert extra document, block, and span transformations.
+ # Parent constructor will do the sorting.
+ $this->document_gamut += array(
+ "doFencedCodeBlocks" => 5,
+ "stripFootnotes" => 15,
+ "stripAbbreviations" => 25,
+ "appendFootnotes" => 50,
+ );
+ $this->block_gamut += array(
+ "doFencedCodeBlocks" => 5,
+ "doTables" => 15,
+ "doDefLists" => 45,
+ );
+ $this->span_gamut += array(
+ "doFootnotes" => 5,
+ "doAbbreviations" => 70,
+ );
+
+ parent::Markdown_Parser();
+ }
+
+
+ # Extra variables used during extra transformations.
+ var $footnotes = array();
+ var $footnotes_ordered = array();
+ var $abbr_desciptions = array();
+ var $abbr_word_re = '';
+
+ # Give the current footnote number.
+ var $footnote_counter = 1;
+
+
+ function setup() {
+ #
+ # Setting up Extra-specific variables.
+ #
+ parent::setup();
+
+ $this->footnotes = array();
+ $this->footnotes_ordered = array();
+ $this->abbr_desciptions = array();
+ $this->abbr_word_re = '';
+ $this->footnote_counter = 1;
+
+ foreach ($this->predef_abbr as $abbr_word => $abbr_desc) {
+ if ($this->abbr_word_re)
+ $this->abbr_word_re .= '|';
+ $this->abbr_word_re .= preg_quote($abbr_word);
+ $this->abbr_desciptions[$abbr_word] = trim($abbr_desc);
+ }
+ }
+
+ function teardown() {
+ #
+ # Clearing Extra-specific variables.
+ #
+ $this->footnotes = array();
+ $this->footnotes_ordered = array();
+ $this->abbr_desciptions = array();
+ $this->abbr_word_re = '';
+
+ parent::teardown();
+ }
+
+
+ ### HTML Block Parser ###
+
+ # Tags that are always treated as block tags:
+ var $block_tags_re = 'p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|address|form|fieldset|iframe|hr|legend';
+
+ # Tags treated as block tags only if the opening tag is alone on it's line:
+ var $context_block_tags_re = 'script|noscript|math|ins|del';
+
+ # Tags where markdown="1" default to span mode:
+ var $contain_span_tags_re = 'p|h[1-6]|li|dd|dt|td|th|legend|address';
+
+ # Tags which must not have their contents modified, no matter where
+ # they appear:
+ var $clean_tags_re = 'script|math';
+
+ # Tags that do not need to be closed.
+ var $auto_close_tags_re = 'hr|img';
+
+
+ function hashHTMLBlocks($text) {
+ #
+ # Hashify HTML Blocks and "clean tags".
+ #
+ # We only want to do this for block-level HTML tags, such as headers,
+ # lists, and tables. That's because we still want to wrap
s around
+ # "paragraphs" that are wrapped in non-block-level tags, such as anchors,
+ # phrase emphasis, and spans. The list of tags we're looking for is
+ # hard-coded.
+ #
+ # This works by calling _HashHTMLBlocks_InMarkdown, which then calls
+ # _HashHTMLBlocks_InHTML when it encounter block tags. When the markdown="1"
+ # attribute is found whitin a tag, _HashHTMLBlocks_InHTML calls back
+ # _HashHTMLBlocks_InMarkdown to handle the Markdown syntax within the tag.
+ # These two functions are calling each other. It's recursive!
+ #
+ #
+ # Call the HTML-in-Markdown hasher.
+ #
+ list($text, ) = $this->_hashHTMLBlocks_inMarkdown($text);
+
+ return $text;
+ }
+ function _hashHTMLBlocks_inMarkdown($text, $indent = 0,
+ $enclosing_tag_re = '', $span = false)
+ {
+ #
+ # Parse markdown text, calling _HashHTMLBlocks_InHTML for block tags.
+ #
+ # * $indent is the number of space to be ignored when checking for code
+ # blocks. This is important because if we don't take the indent into
+ # account, something like this (which looks right) won't work as expected:
+ #
+ #
+ #
+ # Hello World. <-- Is this a Markdown code block or text?
+ #
<-- Is this a Markdown code block or a real tag?
+ #
+ #
+ # If you don't like this, just don't indent the tag on which
+ # you apply the markdown="1" attribute.
+ #
+ # * If $enclosing_tag_re is not empty, stops at the first unmatched closing
+ # tag with that name. Nested tags supported.
+ #
+ # * If $span is true, text inside must treated as span. So any double
+ # newline will be replaced by a single newline so that it does not create
+ # paragraphs.
+ #
+ # Returns an array of that form: ( processed text , remaining text )
+ #
+ if ($text === '') return array('', '');
+
+ # Regex to check for the presense of newlines around a block tag.
+ $newline_before_re = '/(?:^\n?|\n\n)*$/';
+ $newline_after_re =
+ '{
+ ^ # Start of text following the tag.
+ (?>[ ]*)? # Optional comment.
+ [ ]*\n # Must be followed by newline.
+ }xs';
+
+ # Regex to match any tag.
+ $block_tag_re =
+ '{
+ ( # $2: Capture hole tag.
+ ? # Any opening or closing tag.
+ (?> # Tag name.
+ '.$this->block_tags_re.' |
+ '.$this->context_block_tags_re.' |
+ '.$this->clean_tags_re.' |
+ (?!\s)'.$enclosing_tag_re.'
+ )
+ (?:
+ (?=[\s"\'/a-zA-Z0-9]) # Allowed characters after tag name.
+ (?>
+ ".*?" | # Double quotes (can contain `>`)
+ \'.*?\' | # Single quotes (can contain `>`)
+ .+? # Anything but quotes and `>`.
+ )*?
+ )?
+ > # End of tag.
+ |
+ # HTML Comment
+ |
+ <\?.*?\?> | <%.*?%> # Processing instruction
+ |
+ # CData Block
+ |
+ # Code span marker
+ `+
+ '. ( !$span ? ' # If not in span.
+ |
+ # Indented code block
+ (?: ^[ ]*\n | ^ | \n[ ]*\n )
+ [ ]{'.($indent+4).'}[^\n]* \n
+ (?>
+ (?: [ ]{'.($indent+4).'}[^\n]* | [ ]* ) \n
+ )*
+ |
+ # Fenced code block marker
+ (?> ^ | \n )
+ [ ]{0,'.($indent).'}~~~+[ ]*\n
+ ' : '' ). ' # End (if not is span).
+ )
+ }xs';
+
+
+ $depth = 0; # Current depth inside the tag tree.
+ $parsed = ""; # Parsed text that will be returned.
+
+ #
+ # Loop through every tag until we find the closing tag of the parent
+ # or loop until reaching the end of text if no parent tag specified.
+ #
+ do {
+ #
+ # Split the text using the first $tag_match pattern found.
+ # Text before pattern will be first in the array, text after
+ # pattern will be at the end, and between will be any catches made
+ # by the pattern.
+ #
+ $parts = preg_split($block_tag_re, $text, 2,
+ PREG_SPLIT_DELIM_CAPTURE);
+
+ # If in Markdown span mode, add a empty-string span-level hash
+ # after each newline to prevent triggering any block element.
+ if ($span) {
+ $void = $this->hashPart("", ':');
+ $newline = "$void\n";
+ $parts[0] = $void . str_replace("\n", $newline, $parts[0]) . $void;
+ }
+
+ $parsed .= $parts[0]; # Text before current tag.
+
+ # If end of $text has been reached. Stop loop.
+ if (count($parts) < 3) {
+ $text = "";
+ break;
+ }
+
+ $tag = $parts[1]; # Tag to handle.
+ $text = $parts[2]; # Remaining text after current tag.
+ $tag_re = preg_quote($tag); # For use in a regular expression.
+
+ #
+ # Check for: Code span marker
+ #
+ if ($tag{0} == "`") {
+ # Find corresponding end marker.
+ $tag_re = preg_quote($tag);
+ if (preg_match('{^(?>.+?|\n(?!\n))*?(?.*\n)+?[ ]{0,'.($indent).'}'.$tag_re.'[ ]*\n}', $text,
+ $matches))
+ {
+ # End marker found: pass text unchanged until marker.
+ $parsed .= $tag . $matches[0];
+ $text = substr($text, strlen($matches[0]));
+ }
+ else {
+ # No end marker: just skip it.
+ $parsed .= $tag;
+ }
+ }
+ #
+ # Check for: Indented code block.
+ #
+ else if ($tag{0} == "\n" || $tag{0} == " ") {
+ # Indented code block: pass it unchanged, will be handled
+ # later.
+ $parsed .= $tag;
+ }
+ #
+ # Check for: Opening Block level tag or
+ # Opening Context Block tag (like ins and del)
+ # used as a block tag (tag is alone on it's line).
+ #
+ else if (preg_match('{^<(?:'.$this->block_tags_re.')\b}', $tag) ||
+ ( preg_match('{^<(?:'.$this->context_block_tags_re.')\b}', $tag) &&
+ preg_match($newline_before_re, $parsed) &&
+ preg_match($newline_after_re, $text) )
+ )
+ {
+ # Need to parse tag and following text using the HTML parser.
+ list($block_text, $text) =
+ $this->_hashHTMLBlocks_inHTML($tag . $text, "hashBlock", true);
+
+ # Make sure it stays outside of any paragraph by adding newlines.
+ $parsed .= "\n\n$block_text\n\n";
+ }
+ #
+ # Check for: Clean tag (like script, math)
+ # HTML Comments, processing instructions.
+ #
+ else if (preg_match('{^<(?:'.$this->clean_tags_re.')\b}', $tag) ||
+ $tag{1} == '!' || $tag{1} == '?')
+ {
+ # Need to parse tag and following text using the HTML parser.
+ # (don't check for markdown attribute)
+ list($block_text, $text) =
+ $this->_hashHTMLBlocks_inHTML($tag . $text, "hashClean", false);
+
+ $parsed .= $block_text;
+ }
+ #
+ # Check for: Tag with same name as enclosing tag.
+ #
+ else if ($enclosing_tag_re !== '' &&
+ # Same name as enclosing tag.
+ preg_match('{^?(?:'.$enclosing_tag_re.')\b}', $tag))
+ {
+ #
+ # Increase/decrease nested tag count.
+ #
+ if ($tag{1} == '/') $depth--;
+ else if ($tag{strlen($tag)-2} != '/') $depth++;
+
+ if ($depth < 0) {
+ #
+ # Going out of parent element. Clean up and break so we
+ # return to the calling function.
+ #
+ $text = $tag . $text;
+ break;
+ }
+
+ $parsed .= $tag;
+ }
+ else {
+ $parsed .= $tag;
+ }
+ } while ($depth >= 0);
+
+ return array($parsed, $text);
+ }
+ function _hashHTMLBlocks_inHTML($text, $hash_method, $md_attr) {
+ #
+ # Parse HTML, calling _HashHTMLBlocks_InMarkdown for block tags.
+ #
+ # * Calls $hash_method to convert any blocks.
+ # * Stops when the first opening tag closes.
+ # * $md_attr indicate if the use of the `markdown="1"` attribute is allowed.
+ # (it is not inside clean tags)
+ #
+ # Returns an array of that form: ( processed text , remaining text )
+ #
+ if ($text === '') return array('', '');
+
+ # Regex to match `markdown` attribute inside of a tag.
+ $markdown_attr_re = '
+ {
+ \s* # Eat whitespace before the `markdown` attribute
+ markdown
+ \s*=\s*
+ (?>
+ (["\']) # $1: quote delimiter
+ (.*?) # $2: attribute value
+ \1 # matching delimiter
+ |
+ ([^\s>]*) # $3: unquoted attribute value
+ )
+ () # $4: make $3 always defined (avoid warnings)
+ }xs';
+
+ # Regex to match any tag.
+ $tag_re = '{
+ ( # $2: Capture hole tag.
+ ? # Any opening or closing tag.
+ [\w:$]+ # Tag name.
+ (?:
+ (?=[\s"\'/a-zA-Z0-9]) # Allowed characters after tag name.
+ (?>
+ ".*?" | # Double quotes (can contain `>`)
+ \'.*?\' | # Single quotes (can contain `>`)
+ .+? # Anything but quotes and `>`.
+ )*?
+ )?
+ > # End of tag.
+ |
+ # HTML Comment
+ |
+ <\?.*?\?> | <%.*?%> # Processing instruction
+ |
+ # CData Block
+ )
+ }xs';
+
+ $original_text = $text; # Save original text in case of faliure.
+
+ $depth = 0; # Current depth inside the tag tree.
+ $block_text = ""; # Temporary text holder for current text.
+ $parsed = ""; # Parsed text that will be returned.
+
+ #
+ # Get the name of the starting tag.
+ # (This pattern makes $base_tag_name_re safe without quoting.)
+ #
+ if (preg_match('/^<([\w:$]*)\b/', $text, $matches))
+ $base_tag_name_re = $matches[1];
+
+ #
+ # Loop through every tag until we find the corresponding closing tag.
+ #
+ do {
+ #
+ # Split the text using the first $tag_match pattern found.
+ # Text before pattern will be first in the array, text after
+ # pattern will be at the end, and between will be any catches made
+ # by the pattern.
+ #
+ $parts = preg_split($tag_re, $text, 2, PREG_SPLIT_DELIM_CAPTURE);
+
+ if (count($parts) < 3) {
+ #
+ # End of $text reached with unbalenced tag(s).
+ # In that case, we return original text unchanged and pass the
+ # first character as filtered to prevent an infinite loop in the
+ # parent function.
+ #
+ return array($original_text{0}, substr($original_text, 1));
+ }
+
+ $block_text .= $parts[0]; # Text before current tag.
+ $tag = $parts[1]; # Tag to handle.
+ $text = $parts[2]; # Remaining text after current tag.
+
+ #
+ # Check for: Auto-close tag (like )
+ # Comments and Processing Instructions.
+ #
+ if (preg_match('{^?(?:'.$this->auto_close_tags_re.')\b}', $tag) ||
+ $tag{1} == '!' || $tag{1} == '?')
+ {
+ # Just add the tag to the block as if it was text.
+ $block_text .= $tag;
+ }
+ else {
+ #
+ # Increase/decrease nested tag count. Only do so if
+ # the tag's name match base tag's.
+ #
+ if (preg_match('{^?'.$base_tag_name_re.'\b}', $tag)) {
+ if ($tag{1} == '/') $depth--;
+ else if ($tag{strlen($tag)-2} != '/') $depth++;
+ }
+
+ #
+ # Check for `markdown="1"` attribute and handle it.
+ #
+ if ($md_attr &&
+ preg_match($markdown_attr_re, $tag, $attr_m) &&
+ preg_match('/^1|block|span$/', $attr_m[2] . $attr_m[3]))
+ {
+ # Remove `markdown` attribute from opening tag.
+ $tag = preg_replace($markdown_attr_re, '', $tag);
+
+ # Check if text inside this tag must be parsed in span mode.
+ $this->mode = $attr_m[2] . $attr_m[3];
+ $span_mode = $this->mode == 'span' || $this->mode != 'block' &&
+ preg_match('{^<(?:'.$this->contain_span_tags_re.')\b}', $tag);
+
+ # Calculate indent before tag.
+ if (preg_match('/(?:^|\n)( *?)(?! ).*?$/', $block_text, $matches)) {
+ $strlen = $this->utf8_strlen;
+ $indent = $strlen($matches[1], 'UTF-8');
+ } else {
+ $indent = 0;
+ }
+
+ # End preceding block with this tag.
+ $block_text .= $tag;
+ $parsed .= $this->$hash_method($block_text);
+
+ # Get enclosing tag name for the ParseMarkdown function.
+ # (This pattern makes $tag_name_re safe without quoting.)
+ preg_match('/^<([\w:$]*)\b/', $tag, $matches);
+ $tag_name_re = $matches[1];
+
+ # Parse the content using the HTML-in-Markdown parser.
+ list ($block_text, $text)
+ = $this->_hashHTMLBlocks_inMarkdown($text, $indent,
+ $tag_name_re, $span_mode);
+
+ # Outdent markdown text.
+ if ($indent > 0) {
+ $block_text = preg_replace("/^[ ]{1,$indent}/m", "",
+ $block_text);
+ }
+
+ # Append tag content to parsed text.
+ if (!$span_mode) $parsed .= "\n\n$block_text\n\n";
+ else $parsed .= "$block_text";
+
+ # Start over a new block.
+ $block_text = "";
+ }
+ else $block_text .= $tag;
+ }
+
+ } while ($depth > 0);
+
+ #
+ # Hash last block text that wasn't processed inside the loop.
+ #
+ $parsed .= $this->$hash_method($block_text);
+
+ return array($parsed, $text);
+ }
+
+
+ function hashClean($text) {
+ #
+ # Called whenever a tag must be hashed when a function insert a "clean" tag
+ # in $text, it pass through this function and is automaticaly escaped,
+ # blocking invalid nested overlap.
+ #
+ return $this->hashPart($text, 'C');
+ }
+
+
+ function doHeaders($text) {
+ #
+ # Redefined to add id attribute support.
+ #
+ # Setext-style headers:
+ # Header 1 {#header1}
+ # ========
+ #
+ # Header 2 {#header2}
+ # --------
+ #
+ $text = preg_replace_callback(
+ '{
+ (^.+?) # $1: Header text
+ (?:[ ]+\{\#([-_:a-zA-Z0-9]+)\})? # $2: Id attribute
+ [ ]*\n(=+|-+)[ ]*\n+ # $3: Header footer
+ }mx',
+ array(&$this, '_doHeaders_callback_setext'), $text);
+
+ # atx-style headers:
+ # # Header 1 {#header1}
+ # ## Header 2 {#header2}
+ # ## Header 2 with closing hashes ## {#header3}
+ # ...
+ # ###### Header 6 {#header2}
+ #
+ $text = preg_replace_callback('{
+ ^(\#{1,6}) # $1 = string of #\'s
+ [ ]*
+ (.+?) # $2 = Header text
+ [ ]*
+ \#* # optional closing #\'s (not counted)
+ (?:[ ]+\{\#([-_:a-zA-Z0-9]+)\})? # id attribute
+ [ ]*
+ \n+
+ }xm',
+ array(&$this, '_doHeaders_callback_atx'), $text);
+
+ return $text;
+ }
+ function _doHeaders_attr($attr) {
+ if (empty($attr)) return "";
+ return " id=\"$attr\"";
+ }
+ function _doHeaders_callback_setext($matches) {
+ if ($matches[3] == '-' && preg_match('{^- }', $matches[1]))
+ return $matches[0];
+ $level = $matches[3]{0} == '=' ? 1 : 2;
+ $attr = $this->_doHeaders_attr($id =& $matches[2]);
+ $block = "".$this->runSpanGamut($matches[1])."";
+ return "\n" . $this->hashBlock($block) . "\n\n";
+ }
+ function _doHeaders_callback_atx($matches) {
+ $level = strlen($matches[1]);
+ $attr = $this->_doHeaders_attr($id =& $matches[3]);
+ $block = "".$this->runSpanGamut($matches[2])."";
+ return "\n" . $this->hashBlock($block) . "\n\n";
+ }
+
+
+ function doTables($text) {
+ #
+ # Form HTML tables.
+ #
+ $less_than_tab = $this->tab_width - 1;
+ #
+ # Find tables with leading pipe.
+ #
+ # | Header 1 | Header 2
+ # | -------- | --------
+ # | Cell 1 | Cell 2
+ # | Cell 3 | Cell 4
+ #
+ $text = preg_replace_callback('
+ {
+ ^ # Start of a line
+ [ ]{0,'.$less_than_tab.'} # Allowed whitespace.
+ [|] # Optional leading pipe (present)
+ (.+) \n # $1: Header row (at least one pipe)
+
+ [ ]{0,'.$less_than_tab.'} # Allowed whitespace.
+ [|] ([ ]*[-:]+[-| :]*) \n # $2: Header underline
+
+ ( # $3: Cells
+ (?>
+ [ ]* # Allowed whitespace.
+ [|] .* \n # Row content.
+ )*
+ )
+ (?=\n|\Z) # Stop at final double newline.
+ }xm',
+ array(&$this, '_doTable_leadingPipe_callback'), $text);
+
+ #
+ # Find tables without leading pipe.
+ #
+ # Header 1 | Header 2
+ # -------- | --------
+ # Cell 1 | Cell 2
+ # Cell 3 | Cell 4
+ #
+ $text = preg_replace_callback('
+ {
+ ^ # Start of a line
+ [ ]{0,'.$less_than_tab.'} # Allowed whitespace.
+ (\S.*[|].*) \n # $1: Header row (at least one pipe)
+
+ [ ]{0,'.$less_than_tab.'} # Allowed whitespace.
+ ([-:]+[ ]*[|][-| :]*) \n # $2: Header underline
+
+ ( # $3: Cells
+ (?>
+ .* [|] .* \n # Row content
+ )*
+ )
+ (?=\n|\Z) # Stop at final double newline.
+ }xm',
+ array(&$this, '_DoTable_callback'), $text);
+
+ return $text;
+ }
+ function _doTable_leadingPipe_callback($matches) {
+ $head = $matches[1];
+ $underline = $matches[2];
+ $content = $matches[3];
+
+ # Remove leading pipe for each row.
+ $content = preg_replace('/^ *[|]/m', '', $content);
+
+ return $this->_doTable_callback(array($matches[0], $head, $underline, $content));
+ }
+ function _doTable_callback($matches) {
+ $head = $matches[1];
+ $underline = $matches[2];
+ $content = $matches[3];
+
+ # Remove any tailing pipes for each line.
+ $head = preg_replace('/[|] *$/m', '', $head);
+ $underline = preg_replace('/[|] *$/m', '', $underline);
+ $content = preg_replace('/[|] *$/m', '', $content);
+
+ # Reading alignement from header underline.
+ $separators = preg_split('/ *[|] */', $underline);
+ foreach ($separators as $n => $s) {
+ if (preg_match('/^ *-+: *$/', $s)) $attr[$n] = ' align="right"';
+ else if (preg_match('/^ *:-+: *$/', $s))$attr[$n] = ' align="center"';
+ else if (preg_match('/^ *:-+ *$/', $s)) $attr[$n] = ' align="left"';
+ else $attr[$n] = '';
+ }
+
+ # Parsing span elements, including code spans, character escapes,
+ # and inline HTML tags, so that pipes inside those gets ignored.
+ $head = $this->parseSpan($head);
+ $headers = preg_split('/ *[|] */', $head);
+ $col_count = count($headers);
+
+ # Write column headers.
+ $text = "
";
+
+ return $this->hashBlock($text) . "\n";
+ }
+
+
+ function doDefLists($text) {
+ #
+ # Form HTML definition lists.
+ #
+ $less_than_tab = $this->tab_width - 1;
+
+ # Re-usable pattern to match any entire dl list:
+ $whole_list_re = '(?>
+ ( # $1 = whole list
+ ( # $2
+ [ ]{0,'.$less_than_tab.'}
+ ((?>.*\S.*\n)+) # $3 = defined term
+ \n?
+ [ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition
+ )
+ (?s:.+?)
+ ( # $4
+ \z
+ |
+ \n{2,}
+ (?=\S)
+ (?! # Negative lookahead for another term
+ [ ]{0,'.$less_than_tab.'}
+ (?: \S.*\n )+? # defined term
+ \n?
+ [ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition
+ )
+ (?! # Negative lookahead for another definition
+ [ ]{0,'.$less_than_tab.'}:[ ]+ # colon starting definition
+ )
+ )
+ )
+ )'; // mx
+
+ $text = preg_replace_callback('{
+ (?>\A\n?|(?<=\n\n))
+ '.$whole_list_re.'
+ }mx',
+ array(&$this, '_doDefLists_callback'), $text);
+
+ return $text;
+ }
+ function _doDefLists_callback($matches) {
+ # Re-usable patterns to match list item bullets and number markers:
+ $list = $matches[1];
+
+ # Turn double returns into triple returns, so that we can make a
+ # paragraph for the last item in a list, if necessary:
+ $result = trim($this->processDefListItems($list));
+ $result = "
\n" . $result . "\n
";
+ return $this->hashBlock($result) . "\n\n";
+ }
+
+
+ function processDefListItems($list_str) {
+ #
+ # Process the contents of a single definition list, splitting it
+ # into individual term and definition list items.
+ #
+ $less_than_tab = $this->tab_width - 1;
+
+ # trim trailing blank lines:
+ $list_str = preg_replace("/\n{2,}\\z/", "\n", $list_str);
+
+ # Process definition terms.
+ $list_str = preg_replace_callback('{
+ (?>\A\n?|\n\n+) # leading line
+ ( # definition terms = $1
+ [ ]{0,'.$less_than_tab.'} # leading whitespace
+ (?![:][ ]|[ ]) # negative lookahead for a definition
+ # mark (colon) or more whitespace.
+ (?> \S.* \n)+? # actual term (not whitespace).
+ )
+ (?=\n?[ ]{0,3}:[ ]) # lookahead for following line feed
+ # with a definition mark.
+ }xm',
+ array(&$this, '_processDefListItems_callback_dt'), $list_str);
+
+ # Process actual definitions.
+ $list_str = preg_replace_callback('{
+ \n(\n+)? # leading line = $1
+ ( # marker space = $2
+ [ ]{0,'.$less_than_tab.'} # whitespace before colon
+ [:][ ]+ # definition mark (colon)
+ )
+ ((?s:.+?)) # definition text = $3
+ (?= \n+ # stop at next definition mark,
+ (?: # next term or end of text
+ [ ]{0,'.$less_than_tab.'} [:][ ] |
+
";
+ return "\n\n".$this->hashBlock($codeblock)."\n\n";
+ }
+ function _doFencedCodeBlocks_newlines($matches) {
+ return str_repeat(" empty_element_suffix",
+ strlen($matches[0]));
+ }
+
+
+ #
+ # Redefining emphasis markers so that emphasis by underscore does not
+ # work in the middle of a word.
+ #
+ var $em_relist = array(
+ '' => '(?:(? '(?<=\S|^)(? '(?<=\S|^)(? '(?:(? '(?<=\S|^)(? '(?<=\S|^)(? '(?:(? '(?<=\S|^)(? '(?<=\S|^)(? tags
+ #
+ # Strip leading and trailing lines:
+ $text = preg_replace('/\A\n+|\n+\z/', '', $text);
+
+ $grafs = preg_split('/\n{2,}/', $text, -1, PREG_SPLIT_NO_EMPTY);
+
+ #
+ # Wrap
tags and unhashify HTML blocks
+ #
+ foreach ($grafs as $key => $value) {
+ $value = trim($this->runSpanGamut($value));
+
+ # Check if this should be enclosed in a paragraph.
+ # Clean tag hashes & block tag hashes are left alone.
+ $is_p = !preg_match('/^B\x1A[0-9]+B|^C\x1A[0-9]+C$/', $value);
+
+ if ($is_p) {
+ $value = "
$value
";
+ }
+ $grafs[$key] = $value;
+ }
+
+ # Join grafs in one text, then unhash HTML tags.
+ $text = implode("\n\n", $grafs);
+
+ # Finish by removing any tag hashes still present in $text.
+ $text = $this->unhash($text);
+
+ return $text;
+ }
+
+
+ ### Footnotes
+
+ function stripFootnotes($text) {
+ #
+ # Strips link definitions from text, stores the URLs and titles in
+ # hash references.
+ #
+ $less_than_tab = $this->tab_width - 1;
+
+ # Link defs are in the form: [^id]: url "optional title"
+ $text = preg_replace_callback('{
+ ^[ ]{0,'.$less_than_tab.'}\[\^(.+?)\][ ]?: # note_id = $1
+ [ ]*
+ \n? # maybe *one* newline
+ ( # text = $2 (no blank lines allowed)
+ (?:
+ .+ # actual text
+ |
+ \n # newlines but
+ (?!\[\^.+?\]:\s)# negative lookahead for footnote marker.
+ (?!\n+[ ]{0,3}\S)# ensure line is not blank and followed
+ # by non-indented content
+ )*
+ )
+ }xm',
+ array(&$this, '_stripFootnotes_callback'),
+ $text);
+ return $text;
+ }
+ function _stripFootnotes_callback($matches) {
+ $note_id = $this->fn_id_prefix . $matches[1];
+ $this->footnotes[$note_id] = $this->outdent($matches[2]);
+ return ''; # String that will replace the block
+ }
+
+
+ function doFootnotes($text) {
+ #
+ # Replace footnote references in $text [^id] with a special text-token
+ # which will be replaced by the actual footnote marker in appendFootnotes.
+ #
+ if (!$this->in_anchor) {
+ $text = preg_replace('{\[\^(.+?)\]}', "F\x1Afn:\\1\x1A:", $text);
+ }
+ return $text;
+ }
+
+
+ function appendFootnotes($text) {
+ #
+ # Append footnote list to text.
+ #
+ $text = preg_replace_callback('{F\x1Afn:(.*?)\x1A:}',
+ array(&$this, '_appendFootnotes_callback'), $text);
+
+ if (!empty($this->footnotes_ordered)) {
+ $text .= "\n\n";
+ $text .= "
";
+ }
+ return $text;
+ }
+ function _appendFootnotes_callback($matches) {
+ $node_id = $this->fn_id_prefix . $matches[1];
+
+ # Create footnote marker only if it has a corresponding footnote *and*
+ # the footnote hasn't been used by another marker.
+ if (isset($this->footnotes[$node_id])) {
+ # Transfert footnote content to the ordered list.
+ $this->footnotes_ordered[$node_id] = $this->footnotes[$node_id];
+ unset($this->footnotes[$node_id]);
+
+ $num = $this->footnote_counter++;
+ $attr = " rel=\"footnote\"";
+ if ($this->fn_link_class != "") {
+ $class = $this->fn_link_class;
+ $class = $this->encodeAttribute($class);
+ $attr .= " class=\"$class\"";
+ }
+ if ($this->fn_link_title != "") {
+ $title = $this->fn_link_title;
+ $title = $this->encodeAttribute($title);
+ $attr .= " title=\"$title\"";
+ }
+
+ $attr = str_replace("%%", $num, $attr);
+ $node_id = $this->encodeAttribute($node_id);
+
+ return
+ "".
+ "$num".
+ "";
+ }
+
+ return "[^".$matches[1]."]";
+ }
+
+
+ ### Abbreviations ###
+
+ function stripAbbreviations($text) {
+ #
+ # Strips abbreviations from text, stores titles in hash references.
+ #
+ $less_than_tab = $this->tab_width - 1;
+
+ # Link defs are in the form: [id]*: url "optional title"
+ $text = preg_replace_callback('{
+ ^[ ]{0,'.$less_than_tab.'}\*\[(.+?)\][ ]?: # abbr_id = $1
+ (.*) # text = $2 (no blank lines allowed)
+ }xm',
+ array(&$this, '_stripAbbreviations_callback'),
+ $text);
+ return $text;
+ }
+ function _stripAbbreviations_callback($matches) {
+ $abbr_word = $matches[1];
+ $abbr_desc = $matches[2];
+ if ($this->abbr_word_re)
+ $this->abbr_word_re .= '|';
+ $this->abbr_word_re .= preg_quote($abbr_word);
+ $this->abbr_desciptions[$abbr_word] = trim($abbr_desc);
+ return ''; # String that will replace the block
+ }
+
+
+ function doAbbreviations($text) {
+ #
+ # Find defined abbreviations in text and wrap them in elements.
+ #
+ if ($this->abbr_word_re) {
+ // cannot use the /x modifier because abbr_word_re may
+ // contain significant spaces:
+ $text = preg_replace_callback('{'.
+ '(?abbr_word_re.')'.
+ '(?![\w\x1A])'.
+ '}',
+ array(&$this, '_doAbbreviations_callback'), $text);
+ }
+ return $text;
+ }
+ function _doAbbreviations_callback($matches) {
+ $abbr = $matches[0];
+ if (isset($this->abbr_desciptions[$abbr])) {
+ $desc = $this->abbr_desciptions[$abbr];
+ if (empty($desc)) {
+ return $this->hashPart("$abbr");
+ } else {
+ $desc = $this->encodeAttribute($desc);
+ return $this->hashPart("$abbr");
+ }
+ } else {
+ return $matches[0];
+ }
+ }
+
+}
+
+
+/*
+
+PHP Markdown Extra
+==================
+
+Description
+-----------
+
+This is a PHP port of the original Markdown formatter written in Perl
+by John Gruber. This special "Extra" version of PHP Markdown features
+further enhancements to the syntax for making additional constructs
+such as tables and definition list.
+
+Markdown is a text-to-HTML filter; it translates an easy-to-read /
+easy-to-write structured text format into HTML. Markdown's text format
+is most similar to that of plain text email, and supports features such
+as headers, *emphasis*, code blocks, blockquotes, and links.
+
+Markdown's syntax is designed not as a generic markup language, but
+specifically to serve as a front-end to (X)HTML. You can use span-level
+HTML tags anywhere in a Markdown document, and you can use block level
+HTML tags (like
and
as well).
+
+For more information about Markdown's syntax, see:
+
+
+
+
+Bugs
+----
+
+To file bug reports please send email to:
+
+
+
+Please include with your report: (1) the example input; (2) the output you
+expected; (3) the output Markdown actually produced.
+
+
+Version History
+---------------
+
+See the readme file for detailed release notes for this version.
+
+
+Copyright and License
+---------------------
+
+PHP Markdown & Extra
+Copyright (c) 2004-2009 Michel Fortin
+
+All rights reserved.
+
+Based on Markdown
+Copyright (c) 2003-2006 John Gruber
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are
+met:
+
+* Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+
+* Neither the name "Markdown" nor the names of its contributors may
+ be used to endorse or promote products derived from this software
+ without specific prior written permission.
+
+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.
+
+*/
+?>
\ No newline at end of file
diff --git a/bundles/docs/routes.php b/bundles/docs/routes.php
new file mode 100644
index 0000000..334c652
--- /dev/null
+++ b/bundles/docs/routes.php
@@ -0,0 +1,85 @@
+with('sidebar', document('contents'));
+});
+
+/**
+ * Handle the documentation homepage.
+ *
+ * This page contains the "introduction" to Laravel.
+ */
+Route::get('(:bundle)', function()
+{
+ return View::make('docs::page')->with('content', document('home'));
+});
+
+/**
+ * Handle documentation routes for sections and pages.
+ *
+ * @param string $section
+ * @param string $page
+ * @return mixed
+ */
+Route::get('(:bundle)/(:any)/(:any?)', function($section, $page = null)
+{
+ $file = rtrim(implode('/', func_get_args()), '/');
+
+ // If no page was specified, but a "home" page exists for the section,
+ // we'll set the file to the home page so that the proper page is
+ // display back out to the client for the requested doc page.
+ if (is_null($page) and document_exists($file.'/home'))
+ {
+ $file .= '/home';
+ }
+
+ if (document_exists($file))
+ {
+ return View::make('docs::page')->with('content', document($file));
+ }
+ else
+ {
+ return Response::error('404');
+ }
+});
\ No newline at end of file
diff --git a/bundles/docs/views/page.blade.php b/bundles/docs/views/page.blade.php
new file mode 100644
index 0000000..1309e90
--- /dev/null
+++ b/bundles/docs/views/page.blade.php
@@ -0,0 +1,5 @@
+@layout('docs::template')
+
+@section('content')
+ {{ $content }}
+@endsection
\ No newline at end of file
diff --git a/bundles/docs/views/template.blade.php b/bundles/docs/views/template.blade.php
new file mode 100644
index 0000000..20bf601
--- /dev/null
+++ b/bundles/docs/views/template.blade.php
@@ -0,0 +1,34 @@
+
+
+
+
+
+ Laravel: A Framework For Web Artisans
+
+
+ {{ HTML::style('laravel/css/style.css') }}
+ {{ HTML::style('laravel/js/modernizr-2.5.3.min.js') }}
+
+
+
+
+
Laravel
+
A Framework For Web Artisans
+
+
+
+
+
+
+
+ @yield('content')
+
+
+
+ {{ HTML::script('http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js') }}
+ {{ HTML::script('laravel/js/prettify.js') }}
+ {{ HTML::script('laravel/js/scroll.js') }}
+
+
\ No newline at end of file
diff --git a/laravel/asset.php b/laravel/asset.php
new file mode 100644
index 0000000..6bc3647
--- /dev/null
+++ b/laravel/asset.php
@@ -0,0 +1,356 @@
+
+ * // Get the default asset container
+ * $container = Asset::container();
+ *
+ * // Get a named asset container
+ * $container = Asset::container('footer');
+ *
+ *
+ * @param string $container
+ * @return Asset_Container
+ */
+ public static function container($container = 'default')
+ {
+ if ( ! isset(static::$containers[$container]))
+ {
+ static::$containers[$container] = new Asset_Container($container);
+ }
+
+ return static::$containers[$container];
+ }
+
+ /**
+ * Magic Method for calling methods on the default container.
+ *
+ *
+ * // Call the "styles" method on the default container
+ * echo Asset::styles();
+ *
+ * // Call the "add" method on the default container
+ * Asset::add('jquery', 'js/jquery.js');
+ *
+ */
+ public static function __callStatic($method, $parameters)
+ {
+ return call_user_func_array(array(static::container(), $method), $parameters);
+ }
+
+}
+
+class Asset_Container {
+
+ /**
+ * The asset container name.
+ *
+ * @var string
+ */
+ public $name;
+
+ /**
+ * The bundle that the assets belong to.
+ *
+ * @var string
+ */
+ public $bundle = DEFAULT_BUNDLE;
+
+ /**
+ * All of the registered assets.
+ *
+ * @var array
+ */
+ public $assets = array();
+
+ /**
+ * Create a new asset container instance.
+ *
+ * @param string $name
+ * @return void
+ */
+ public function __construct($name)
+ {
+ $this->name = $name;
+ }
+
+ /**
+ * Add an asset to the container.
+ *
+ * The extension of the asset source will be used to determine the type of
+ * asset being registered (CSS or JavaScript). When using a non-standard
+ * extension, the style/script methods may be used to register assets.
+ *
+ *
+ * // Add an asset to the container
+ * Asset::container()->add('jquery', 'js/jquery.js');
+ *
+ * // Add an asset that has dependencies on other assets
+ * Asset::add('jquery', 'js/jquery.js', 'jquery-ui');
+ *
+ * // Add an asset that should have attributes applied to its tags
+ * Asset::add('jquery', 'js/jquery.js', null, array('defer'));
+ *
+ *
+ * @param string $name
+ * @param string $source
+ * @param array $dependencies
+ * @param array $attributes
+ * @return void
+ */
+ public function add($name, $source, $dependencies = array(), $attributes = array())
+ {
+ $type = (pathinfo($source, PATHINFO_EXTENSION) == 'css') ? 'style' : 'script';
+
+ return $this->$type($name, $source, $dependencies, $attributes);
+ }
+
+ /**
+ * Add a CSS file to the registered assets.
+ *
+ * @param string $name
+ * @param string $source
+ * @param array $dependencies
+ * @param array $attributes
+ * @return Asset_Container
+ */
+ public function style($name, $source, $dependencies = array(), $attributes = array())
+ {
+ if ( ! array_key_exists('media', $attributes))
+ {
+ $attributes['media'] = 'all';
+ }
+
+ $this->register('style', $name, $source, $dependencies, $attributes);
+
+ return $this;
+ }
+
+ /**
+ * Add a JavaScript file to the registered assets.
+ *
+ * @param string $name
+ * @param string $source
+ * @param array $dependencies
+ * @param array $attributes
+ * @return Asset_Container
+ */
+ public function script($name, $source, $dependencies = array(), $attributes = array())
+ {
+ $this->register('script', $name, $source, $dependencies, $attributes);
+
+ return $this;
+ }
+
+ /**
+ * Returns the full-path for an asset.
+ *
+ * @param string $source
+ * @return string
+ */
+ public function path($source)
+ {
+ return Bundle::assets($this->bundle).$source;
+ }
+
+ /**
+ * Set the bundle that the container's assets belong to.
+ *
+ * @param string $bundle
+ * @return Asset_Container
+ */
+ public function bundle($bundle)
+ {
+ $this->bundle = $bundle;
+ return $this;
+ }
+
+ /**
+ * Add an asset to the array of registered assets.
+ *
+ * @param string $type
+ * @param string $name
+ * @param string $source
+ * @param array $dependencies
+ * @param array $attributes
+ * @return void
+ */
+ protected function register($type, $name, $source, $dependencies, $attributes)
+ {
+ $dependencies = (array) $dependencies;
+
+ $attributes = (array) $attributes;
+
+ $this->assets[$type][$name] = compact('source', 'dependencies', 'attributes');
+ }
+
+ /**
+ * Get the links to all of the registered CSS assets.
+ *
+ * @return string
+ */
+ public function styles()
+ {
+ return $this->group('style');
+ }
+
+ /**
+ * Get the links to all of the registered JavaScript assets.
+ *
+ * @return string
+ */
+ public function scripts()
+ {
+ return $this->group('script');
+ }
+
+ /**
+ * Get all of the registered assets for a given type / group.
+ *
+ * @param string $group
+ * @return string
+ */
+ protected function group($group)
+ {
+ if ( ! isset($this->assets[$group]) or count($this->assets[$group]) == 0) return '';
+
+ $assets = '';
+
+ foreach ($this->arrange($this->assets[$group]) as $name => $data)
+ {
+ $assets .= $this->asset($group, $name);
+ }
+
+ return $assets;
+ }
+
+ /**
+ * Get the HTML link to a registered asset.
+ *
+ * @param string $group
+ * @param string $name
+ * @return string
+ */
+ protected function asset($group, $name)
+ {
+ if ( ! isset($this->assets[$group][$name])) return '';
+
+ $asset = $this->assets[$group][$name];
+
+ // If the bundle source is not a complete URL, we will go ahead and prepend
+ // the bundle's asset path to the source provided with the asset. This will
+ // ensure that we attach the correct path to the asset.
+ if (filter_var($asset['source'], FILTER_VALIDATE_URL) === false)
+ {
+ $asset['source'] = $this->path($asset['source']);
+ }
+
+ return HTML::$group($asset['source'], $asset['attributes']);
+ }
+
+ /**
+ * Sort and retrieve assets based on their dependencies
+ *
+ * @param array $assets
+ * @return array
+ */
+ protected function arrange($assets)
+ {
+ list($original, $sorted) = array($assets, array());
+
+ while (count($assets) > 0)
+ {
+ foreach ($assets as $asset => $value)
+ {
+ $this->evaluate_asset($asset, $value, $original, $sorted, $assets);
+ }
+ }
+
+ return $sorted;
+ }
+
+ /**
+ * Evaluate an asset and its dependencies.
+ *
+ * @param string $asset
+ * @param string $value
+ * @param array $original
+ * @param array $sorted
+ * @param array $assets
+ * @return void
+ */
+ protected function evaluate_asset($asset, $value, $original, &$sorted, &$assets)
+ {
+ // If the asset has no more dependencies, we can add it to the sorted list
+ // and remove it from the array of assets. Otherwise, we will not verify
+ // the asset's dependencies and determine if they've been sorted.
+ if (count($assets[$asset]['dependencies']) == 0)
+ {
+ $sorted[$asset] = $value;
+
+ unset($assets[$asset]);
+ }
+ else
+ {
+ foreach ($assets[$asset]['dependencies'] as $key => $dependency)
+ {
+ if ( ! $this->dependency_is_valid($asset, $dependency, $original, $assets))
+ {
+ unset($assets[$asset]['dependencies'][$key]);
+
+ continue;
+ }
+
+ // If the dependency has not yet been added to the sorted list, we can not
+ // remove it from this asset's array of dependencies. We'll try again on
+ // the next trip through the loop.
+ if ( ! isset($sorted[$dependency])) continue;
+
+ unset($assets[$asset]['dependencies'][$key]);
+ }
+ }
+ }
+
+ /**
+ * Verify that an asset's dependency is valid.
+ *
+ * A dependency is considered valid if it exists, is not a circular reference, and is
+ * not a reference to the owning asset itself. If the dependency doesn't exist, no
+ * error or warning will be given. For the other cases, an exception is thrown.
+ *
+ * @param string $asset
+ * @param string $dependency
+ * @param array $original
+ * @param array $assets
+ * @return bool
+ */
+ protected function dependency_is_valid($asset, $dependency, $original, $assets)
+ {
+ if ( ! isset($original[$dependency]))
+ {
+ return false;
+ }
+ elseif ($dependency === $asset)
+ {
+ throw new \Exception("Asset [$asset] is dependent on itself.");
+ }
+ elseif (isset($assets[$dependency]) and in_array($asset, $assets[$dependency]['dependencies']))
+ {
+ throw new \Exception("Assets [$asset] and [$dependency] have a circular dependency.");
+ }
+
+ return true;
+ }
+
+}
diff --git a/laravel/auth.php b/laravel/auth.php
new file mode 100644
index 0000000..ad4869c
--- /dev/null
+++ b/laravel/auth.php
@@ -0,0 +1,93 @@
+
+ * // Call the "user" method on the default auth driver
+ * $user = Auth::user();
+ *
+ * // Call the "check" method on the default auth driver
+ * Auth::check();
+ *
+ */
+ public static function __callStatic($method, $parameters)
+ {
+ return call_user_func_array(array(static::driver(), $method), $parameters);
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/auth/drivers/driver.php b/laravel/auth/drivers/driver.php
new file mode 100644
index 0000000..4a272ba
--- /dev/null
+++ b/laravel/auth/drivers/driver.php
@@ -0,0 +1,224 @@
+token = Session::get($this->token());
+ }
+
+ // If a token did not exist in the session for the user, we will attempt
+ // to load the value of a "remember me" cookie for the driver, which
+ // serves as a long-lived client side authenticator for the user.
+ if (is_null($this->token))
+ {
+ $this->token = $this->recall();
+ }
+ }
+
+ /**
+ * Determine if the user of the application is not logged in.
+ *
+ * This method is the inverse of the "check" method.
+ *
+ * @return bool
+ */
+ public function guest()
+ {
+ return ! $this->check();
+ }
+
+ /**
+ * Determine if the user is logged in.
+ *
+ * @return bool
+ */
+ public function check()
+ {
+ return ! is_null($this->user());
+ }
+
+ /**
+ * Get the current user of the application.
+ *
+ * If the user is a guest, null should be returned.
+ *
+ * @return mixed|null
+ */
+ public function user()
+ {
+ if ( ! is_null($this->user)) return $this->user;
+
+ return $this->user = $this->retrieve($this->token);
+ }
+
+ /**
+ * Get the a given application user by ID.
+ *
+ * @param int $id
+ * @return mixed
+ */
+ abstract public function retrieve($id);
+
+ /**
+ * Attempt to log a user into the application.
+ *
+ * @param array $arguments
+ * @return void
+ */
+ abstract public function attempt($arguments = array());
+
+ /**
+ * Login the user assigned to the given token.
+ *
+ * The token is typically a numeric ID for the user.
+ *
+ * @param string $token
+ * @param bool $remember
+ * @return bool
+ */
+ public function login($token, $remember = false)
+ {
+ $this->token = $token;
+
+ $this->store($token);
+
+ if ($remember) $this->remember($token);
+
+ return true;
+ }
+
+ /**
+ * Log the user out of the driver's auth context.
+ *
+ * @return void
+ */
+ public function logout()
+ {
+ $this->user = null;
+
+ $this->cookie($this->recaller(), null, -2000);
+
+ Session::forget($this->token());
+ }
+
+ /**
+ * Store a user's token in the session.
+ *
+ * @param string $token
+ * @return void
+ */
+ protected function store($token)
+ {
+ Session::put($this->token(), $token);
+ }
+
+ /**
+ * Store a user's token in a long-lived cookie.
+ *
+ * @param string $token
+ * @return void
+ */
+ protected function remember($token)
+ {
+ $token = Crypter::encrypt($token.'|'.Str::random(40));
+
+ $this->cookie($this->recaller(), $token, Cookie::forever);
+ }
+
+ /**
+ * Attempt to find a "remember me" cookie for the user.
+ *
+ * @return string|null
+ */
+ protected function recall()
+ {
+ $cookie = Cookie::get($this->recaller());
+
+ // By default, "remember me" cookies are encrypted and contain the user
+ // token as well as a random string. If it exists, we'll decrypt it
+ // and return the first segment, which is the user's ID token.
+ if ( ! is_null($cookie))
+ {
+ return head(explode('|', Crypter::decrypt($cookie)));
+ }
+ }
+
+ /**
+ * Store an authentication cookie.
+ *
+ * @param string $name
+ * @param string $value
+ * @param int $minutes
+ * @return void
+ */
+ protected function cookie($name, $value, $minutes)
+ {
+ // When setting the default implementation of an authentication
+ // cookie we'll use the same settings as the session cookie.
+ // This typically makes sense as they both are sensitive.
+ $config = Config::get('session');
+
+ extract($config);
+
+ Cookie::put($name, $value, $minutes, $path, $domain, $secure);
+ }
+
+ /**
+ * Get session key name used to store the token.
+ *
+ * @return string
+ */
+ protected function token()
+ {
+ return $this->name().'_login';
+ }
+
+ /**
+ * Get the name used for the "remember me" cookie.
+ *
+ * @return string
+ */
+ protected function recaller()
+ {
+ return $this->name().'_remember';
+ }
+
+ /**
+ * Get the name of the driver in a storage friendly format.
+ *
+ * @return string
+ */
+ protected function name()
+ {
+ return strtolower(str_replace('\\', '_', get_class($this)));
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/auth/drivers/eloquent.php b/laravel/auth/drivers/eloquent.php
new file mode 100644
index 0000000..8c1c6a8
--- /dev/null
+++ b/laravel/auth/drivers/eloquent.php
@@ -0,0 +1,60 @@
+model()->find($id);
+ }
+ }
+
+ /**
+ * Attempt to log a user into the application.
+ *
+ * @param array $arguments
+ * @return void
+ */
+ public function attempt($arguments = array())
+ {
+ $username = Config::get('auth.username');
+
+ $user = $this->model()->where($username, '=', $arguments['username'])->first();
+
+ // This driver uses a basic username and password authentication scheme
+ // so if the credentials match what is in the database we will just
+ // log the user into the application and remember them if asked.
+ $password = $arguments['password'];
+
+ $password_field = Config::get('auth.password', 'password');
+
+ if ( ! is_null($user) and Hash::check($password, $user->get_attribute($password_field)))
+ {
+ return $this->login($user->id, array_get($arguments, 'remember'));
+ }
+
+ return false;
+ }
+
+ /**
+ * Get a fresh model instance.
+ *
+ * @return Eloquent
+ */
+ protected function model()
+ {
+ $model = Config::get('auth.model');
+
+ return new $model;
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/auth/drivers/fluent.php b/laravel/auth/drivers/fluent.php
new file mode 100644
index 0000000..4c23468
--- /dev/null
+++ b/laravel/auth/drivers/fluent.php
@@ -0,0 +1,65 @@
+find($id);
+ }
+ }
+
+ /**
+ * Attempt to log a user into the application.
+ *
+ * @param array $arguments
+ * @return void
+ */
+ public function attempt($arguments = array())
+ {
+ $user = $this->get_user($arguments['username']);
+
+ // This driver uses a basic username and password authentication scheme
+ // so if the credentials match what is in the database we will just
+ // log the user into the application and remember them if asked.
+ $password = $arguments['password'];
+
+ $password_field = Config::get('auth.password', 'password');
+
+ if ( ! is_null($user) and Hash::check($password, $user->{$password_field}))
+ {
+ return $this->login($user->id, array_get($arguments, 'remember'));
+ }
+
+ return false;
+ }
+
+ /**
+ * Get the user from the database table by username.
+ *
+ * @param mixed $value
+ * @return mixed
+ */
+ protected function get_user($value)
+ {
+ $table = Config::get('auth.table');
+
+ $username = Config::get('auth.username');
+
+ return DB::table($table)->where($username, '=', $value)->first();
+ }
+
+}
diff --git a/laravel/autoloader.php b/laravel/autoloader.php
new file mode 100644
index 0000000..68e423d
--- /dev/null
+++ b/laravel/autoloader.php
@@ -0,0 +1,229 @@
+ $directory)
+ {
+ if (starts_with($class, $namespace))
+ {
+ return static::load_namespaced($class, $namespace, $directory);
+ }
+ }
+
+ static::load_psr($class);
+ }
+
+ /**
+ * Load a namespaced class from a given directory.
+ *
+ * @param string $class
+ * @param string $namespace
+ * @param string $directory
+ * @return void
+ */
+ protected static function load_namespaced($class, $namespace, $directory)
+ {
+ return static::load_psr(substr($class, strlen($namespace)), $directory);
+ }
+
+ /**
+ * Attempt to resolve a class using the PSR-0 standard.
+ *
+ * @param string $class
+ * @param string $directory
+ * @return void
+ */
+ protected static function load_psr($class, $directory = null)
+ {
+ // The PSR-0 standard indicates that class namespaces and underscores
+ // should be used to indcate the directory tree in which the class
+ // resides, so we'll convert them to slashes.
+ $file = str_replace(array('\\', '_'), '/', $class);
+
+ $directories = $directory ?: static::$directories;
+
+ $lower = strtolower($file);
+
+ // Once we have formatted the class name, we'll simply spin through
+ // the registered PSR-0 directories and attempt to locate and load
+ // the class file into the script.
+ foreach ((array) $directories as $directory)
+ {
+ if (file_exists($path = $directory.$lower.EXT))
+ {
+ return require $path;
+ }
+ elseif (file_exists($path = $directory.$file.EXT))
+ {
+ return require $path;
+ }
+ }
+ }
+
+ /**
+ * Register an array of class to path mappings.
+ *
+ * @param array $mappings
+ * @return void
+ */
+ public static function map($mappings)
+ {
+ static::$mappings = array_merge(static::$mappings, $mappings);
+ }
+
+ /**
+ * Register a class alias with the auto-loader.
+ *
+ * @param string $class
+ * @param string $alias
+ * @return void
+ */
+ public static function alias($class, $alias)
+ {
+ static::$aliases[$alias] = $class;
+ }
+
+ /**
+ * Register directories to be searched as a PSR-0 library.
+ *
+ * @param string|array $directory
+ * @return void
+ */
+ public static function directories($directory)
+ {
+ $directories = static::format($directory);
+
+ static::$directories = array_unique(array_merge(static::$directories, $directories));
+ }
+
+ /**
+ * Map namespaces to directories.
+ *
+ * @param array $mappings
+ * @param string $append
+ * @return void
+ */
+ public static function namespaces($mappings, $append = '\\')
+ {
+ $mappings = static::format_mappings($mappings, $append);
+
+ static::$namespaces = array_merge($mappings, static::$namespaces);
+ }
+
+ /**
+ * Register underscored "namespaces" to directory mappings.
+ *
+ * @param array $mappings
+ * @return void
+ */
+ public static function underscored($mappings)
+ {
+ static::namespaces($mappings, '_');
+ }
+
+ /**
+ * Format an array of namespace to directory mappings.
+ *
+ * @param array $mappings
+ * @param string $append
+ * @return array
+ */
+ protected static function format_mappings($mappings, $append)
+ {
+ foreach ($mappings as $namespace => $directory)
+ {
+ // When adding new namespaces to the mappings, we will unset the previously
+ // mapped value if it existed. This allows previously registered spaces to
+ // be mapped to new directories on the fly.
+ $namespace = trim($namespace, $append).$append;
+
+ unset(static::$namespaces[$namespace]);
+
+ $namespaces[$namespace] = head(static::format($directory));
+ }
+
+ return $namespaces;
+ }
+
+ /**
+ * Format an array of directories with the proper trailing slashes.
+ *
+ * @param array $directories
+ * @return array
+ */
+ protected static function format($directories)
+ {
+ return array_map(function($directory)
+ {
+ return rtrim($directory, DS).DS;
+
+ }, (array) $directories);
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/blade.php b/laravel/blade.php
new file mode 100644
index 0000000..c362d57
--- /dev/null
+++ b/laravel/blade.php
@@ -0,0 +1,453 @@
+path, BLADE_EXT))
+ {
+ return;
+ }
+
+ $compiled = Blade::compiled($view->path);
+
+ // If the view doesn't exist or has been modified since the last time it
+ // was compiled, we will recompile the view into pure PHP from it's
+ // Blade representation, writing it to cached storage.
+ if ( ! file_exists($compiled) or Blade::expired($view->view, $view->path))
+ {
+ file_put_contents($compiled, Blade::compile($view));
+ }
+
+ $view->path = $compiled;
+
+ // Once the view has been compiled, we can simply set the path to the
+ // compiled view on the view instance and call the typical "get"
+ // method on the view to evaluate the compiled PHP view.
+ return $view->get();
+ });
+ }
+
+ /**
+ * Register a custom Blade compiler.
+ *
+ *
+ * Blade::extend(function($view)
+ * {
+ * return str_replace('foo', 'bar', $view);
+ * });
+ *
+ *
+ * @param Closure $compiler
+ * @return void
+ */
+ public static function extend(Closure $compiler)
+ {
+ static::$extensions[] = $compiler;
+ }
+
+ /**
+ * Determine if a view is "expired" and needs to be re-compiled.
+ *
+ * @param string $view
+ * @param string $path
+ * @param string $compiled
+ * @return bool
+ */
+ public static function expired($view, $path)
+ {
+ return filemtime($path) > filemtime(static::compiled($path));
+ }
+
+ /**
+ * Compiles the specified file containing Blade pseudo-code into valid PHP.
+ *
+ * @param string $path
+ * @return string
+ */
+ public static function compile($view)
+ {
+ return static::compile_string(file_get_contents($view->path), $view);
+ }
+
+ /**
+ * Compiles the given string containing Blade pseudo-code into valid PHP.
+ *
+ * @param string $value
+ * @param View $view
+ * @return string
+ */
+ public static function compile_string($value, $view = null)
+ {
+ foreach (static::$compilers as $compiler)
+ {
+ $method = "compile_{$compiler}";
+
+ $value = static::$method($value, $view);
+ }
+
+ return $value;
+ }
+
+ /**
+ * Rewrites Blade "@layout" expressions into valid PHP.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected static function compile_layouts($value)
+ {
+ // If the Blade template is not using "layouts", we'll just return it
+ // unchanged since there is nothing to do with layouts and we will
+ // just let the other Blade compilers handle the rest.
+ if ( ! starts_with($value, '@layout'))
+ {
+ return $value;
+ }
+
+ // First we'll split out the lines of the template so we can get the
+ // layout from the top of the template. By convention it must be
+ // located on the first line of the template contents.
+ $lines = preg_split("/(\r?\n)/", $value);
+
+ $pattern = static::matcher('layout');
+
+ $lines[] = preg_replace($pattern, '$1@include$2', $lines[0]);
+
+ // We will add a "render" statement to the end of the templates and
+ // then slice off the "@layout" shortcut from the start so the
+ // sections register before the parent template renders.
+ return implode(CRLF, array_slice($lines, 1));
+ }
+
+ /**
+ * Extract a variable value out of a Blade expression.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected static function extract($value, $expression)
+ {
+ preg_match('/@layout(\s*\(.*\))(\s*)/', $value, $matches);
+
+ return str_replace(array("('", "')"), '', $matches[1]);
+ }
+
+ /**
+ * Rewrites Blade comments into PHP comments.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected static function compile_comments($value)
+ {
+ $value = preg_replace('/\{\{--(.+?)(--\}\})?\n/', "", $value);
+
+ return preg_replace('/\{\{--((.|\s)*?)--\}\}/', "\n", $value);
+ }
+
+ /**
+ * Rewrites Blade echo statements into PHP echo statements.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected static function compile_echos($value)
+ {
+ return preg_replace('/\{\{(.+?)\}\}/', '', $value);
+ }
+
+ /**
+ * Rewrites Blade "for else" statements into valid PHP.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected static function compile_forelse($value)
+ {
+ preg_match_all('/(\s*)@forelse(\s*\(.*\))(\s*)/', $value, $matches);
+
+ foreach ($matches[0] as $forelse)
+ {
+ preg_match('/\s*\(\s*(\S*)\s/', $forelse, $variable);
+
+ // Once we have extracted the variable being looped against, we can add
+ // an if statement to the start of the loop that checks if the count
+ // of the variable being looped against is greater than zero.
+ $if = " 0): ?>";
+
+ $search = '/(\s*)@forelse(\s*\(.*\))/';
+
+ $replace = '$1'.$if.'';
+
+ $blade = preg_replace($search, $replace, $forelse);
+
+ // Finally, once we have the check prepended to the loop we'll replace
+ // all instances of this forelse syntax in the view content of the
+ // view being compiled to Blade syntax with real PHP syntax.
+ $value = str_replace($forelse, $blade, $value);
+ }
+
+ return $value;
+ }
+
+ /**
+ * Rewrites Blade "empty" statements into valid PHP.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected static function compile_empty($value)
+ {
+ return str_replace('@empty', '', $value);
+ }
+
+ /**
+ * Rewrites Blade "forelse" endings into valid PHP.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected static function compile_endforelse($value)
+ {
+ return str_replace('@endforelse', '', $value);
+ }
+
+ /**
+ * Rewrites Blade structure openings into PHP structure openings.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected static function compile_structure_openings($value)
+ {
+ $pattern = '/(\s*)@(if|elseif|foreach|for|while)(\s*\(.*\))/';
+
+ return preg_replace($pattern, '$1', $value);
+ }
+
+ /**
+ * Rewrites Blade structure closings into PHP structure closings.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected static function compile_structure_closings($value)
+ {
+ $pattern = '/(\s*)@(endif|endforeach|endfor|endwhile)(\s*)/';
+
+ return preg_replace($pattern, '$1$3', $value);
+ }
+
+ /**
+ * Rewrites Blade else statements into PHP else statements.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected static function compile_else($value)
+ {
+ return preg_replace('/(\s*)@(else)(\s*)/', '$1$3', $value);
+ }
+
+ /**
+ * Rewrites Blade "unless" statements into valid PHP.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected static function compile_unless($value)
+ {
+ $pattern = '/(\s*)@unless(\s*\(.*\))/';
+
+ return preg_replace($pattern, '$1', $value);
+ }
+
+ /**
+ * Rewrites Blade "unless" endings into valid PHP.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected static function compile_endunless($value)
+ {
+ return str_replace('@endunless', '', $value);
+ }
+
+ /**
+ * Rewrites Blade @include statements into valid PHP.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected static function compile_includes($value)
+ {
+ $pattern = static::matcher('include');
+
+ return preg_replace($pattern, '$1with(get_defined_vars())->render(); ?>', $value);
+ }
+
+ /**
+ * Rewrites Blade @render statements into valid PHP.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected static function compile_render($value)
+ {
+ $pattern = static::matcher('render');
+
+ return preg_replace($pattern, '$1', $value);
+ }
+
+ /**
+ * Rewrites Blade @render_each statements into valid PHP.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected static function compile_render_each($value)
+ {
+ $pattern = static::matcher('render_each');
+
+ return preg_replace($pattern, '$1', $value);
+ }
+
+ /**
+ * Rewrites Blade @yield statements into Section statements.
+ *
+ * The Blade @yield statement is a shortcut to the Section::yield method.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected static function compile_yields($value)
+ {
+ $pattern = static::matcher('yield');
+
+ return preg_replace($pattern, '$1', $value);
+ }
+
+ /**
+ * Rewrites Blade yield section statements into valid PHP.
+ *
+ * @return string
+ */
+ protected static function compile_yield_sections($value)
+ {
+ $replace = '';
+
+ return str_replace('@yield_section', $replace, $value);
+ }
+
+ /**
+ * Rewrites Blade @section statements into Section statements.
+ *
+ * The Blade @section statement is a shortcut to the Section::start method.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected static function compile_section_start($value)
+ {
+ $pattern = static::matcher('section');
+
+ return preg_replace($pattern, '$1', $value);
+ }
+
+ /**
+ * Rewrites Blade @endsection statements into Section statements.
+ *
+ * The Blade @endsection statement is a shortcut to the Section::stop method.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected static function compile_section_end($value)
+ {
+ return preg_replace('/@endsection/', '', $value);
+ }
+
+ /**
+ * Execute user defined compilers.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected static function compile_extensions($value)
+ {
+ foreach (static::$extensions as $compiler)
+ {
+ $value = $compiler($value);
+ }
+
+ return $value;
+ }
+
+ /**
+ * Get the regular expression for a generic Blade function.
+ *
+ * @param string $function
+ * @return string
+ */
+ public static function matcher($function)
+ {
+ return '/(\s*)@'.$function.'(\s*\(.*\))/';
+ }
+
+ /**
+ * Get the fully qualified path for a compiled view.
+ *
+ * @param string $view
+ * @return string
+ */
+ public static function compiled($path)
+ {
+ return path('storage').'views/'.md5($path);
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/bundle.php b/laravel/bundle.php
new file mode 100644
index 0000000..2259228
--- /dev/null
+++ b/laravel/bundle.php
@@ -0,0 +1,464 @@
+ null, 'auto' => false);
+
+ // If the given configuration is actually a string, we will assume it is a
+ // location and set the bundle name to match it. This is common for most
+ // bundles who simply live in the root bundle directory.
+ if (is_string($config))
+ {
+ $bundle = $config;
+
+ $config = array('location' => $bundle);
+ }
+
+ // If no location is set, we will set the location to match the name of
+ // the bundle. This is for bundles who are installed to the root of
+ // the bundle directory so a location was not set.
+ if ( ! isset($config['location']))
+ {
+ $config['location'] = $bundle;
+ }
+
+ static::$bundles[$bundle] = array_merge($defaults, $config);
+
+ // It is possible for the developer to specify auto-loader mappings
+ // directly on the bundle registration. This provides a convenient
+ // way to register mappings withuot a bootstrap.
+ if (isset($config['autoloads']))
+ {
+ static::autoloads($bundle, $config);
+ }
+ }
+
+ /**
+ * Load a bundle by running it's start-up script.
+ *
+ * If the bundle has already been started, no action will be taken.
+ *
+ * @param string $bundle
+ * @return void
+ */
+ public static function start($bundle)
+ {
+ if (static::started($bundle)) return;
+
+ if ( ! static::exists($bundle))
+ {
+ throw new \Exception("Bundle [$bundle] has not been installed.");
+ }
+
+ // Each bundle may have a start script which is responsible for preparing
+ // the bundle for use by the application. The start script may register
+ // any classes the bundle uses with the auto-loader class, etc.
+ if ( ! is_null($starter = static::option($bundle, 'starter')))
+ {
+ $starter();
+ }
+ elseif (file_exists($path = static::path($bundle).'start'.EXT))
+ {
+ require $path;
+ }
+
+ // Each bundle may also have a "routes" file which is responsible for
+ // registering the bundle's routes. This is kept separate from the
+ // start script for reverse routing efficiency purposes.
+ static::routes($bundle);
+
+ Event::fire("laravel.started: {$bundle}");
+
+ static::$started[] = strtolower($bundle);
+ }
+
+ /**
+ * Load the "routes" file for a given bundle.
+ *
+ * @param string $bundle
+ * @return void
+ */
+ public static function routes($bundle)
+ {
+ if (static::routed($bundle)) return;
+
+ $path = static::path($bundle).'routes'.EXT;
+
+ // By setting the bundle property on the router the router knows what
+ // value to replace the (:bundle) place-holder with when the bundle
+ // routes are added, keeping the routes flexible.
+ Router::$bundle = static::option($bundle, 'handles');
+
+ if ( ! static::routed($bundle) and file_exists($path))
+ {
+ static::$routed[] = $bundle;
+
+ require $path;
+ }
+ }
+
+ /**
+ * Register the auto-loading configuration for a bundle.
+ *
+ * @param string $bundle
+ * @param array $config
+ * @return void
+ */
+ protected static function autoloads($bundle, $config)
+ {
+ $path = rtrim(Bundle::path($bundle), DS);
+
+ foreach ($config['autoloads'] as $type => $mappings)
+ {
+ // When registering each type of mapping we'll replace the (:bundle)
+ // place-holder with the path to the bundle's root directory, so
+ // the developer may dryly register the mappings.
+ $mappings = array_map(function($mapping) use ($path)
+ {
+ return str_replace('(:bundle)', $path, $mapping);
+
+ }, $mappings);
+
+ // Once the mappings are formatted, we will call the Autoloader
+ // function matching the mapping type and pass in the array of
+ // mappings so they can be registered and used.
+ Autoloader::$type($mappings);
+ }
+ }
+
+ /**
+ * Disable a bundle for the current request.
+ *
+ * @param string $bundle
+ * @return void
+ */
+ public static function disable($bundle)
+ {
+ unset(static::$bundles[$bundle]);
+ }
+
+ /**
+ * Determine which bundle handles the given URI.
+ *
+ * The default bundle is returned if no other bundle is assigned.
+ *
+ * @param string $uri
+ * @return string
+ */
+ public static function handles($uri)
+ {
+ $uri = rtrim($uri, '/').'/';
+
+ foreach (static::$bundles as $key => $value)
+ {
+ if (isset($value['handles']) and starts_with($uri, $value['handles'].'/'))
+ {
+ return $key;
+ }
+ }
+
+ return DEFAULT_BUNDLE;
+ }
+
+ /**
+ * Deteremine if a bundle exists within the bundles directory.
+ *
+ * @param string $bundle
+ * @return bool
+ */
+ public static function exists($bundle)
+ {
+ return $bundle == DEFAULT_BUNDLE or in_array(strtolower($bundle), static::names());
+ }
+
+ /**
+ * Determine if a given bundle has been started for the request.
+ *
+ * @param string $bundle
+ * @return void
+ */
+ public static function started($bundle)
+ {
+ return in_array(strtolower($bundle), static::$started);
+ }
+
+ /**
+ * Determine if a given bundle has its routes file loaded.
+ *
+ * @param string $bundle
+ * @return void
+ */
+ public static function routed($bundle)
+ {
+ return in_array(strtolower($bundle), static::$routed);
+ }
+
+ /**
+ * Get the identifier prefix for the bundle.
+ *
+ * @param string $bundle
+ * @return string
+ */
+ public static function prefix($bundle)
+ {
+ return ($bundle !== DEFAULT_BUNDLE) ? "{$bundle}::" : '';
+ }
+
+ /**
+ * Get the class prefix for a given bundle.
+ *
+ * @param string $bundle
+ * @return string
+ */
+ public static function class_prefix($bundle)
+ {
+ return ($bundle !== DEFAULT_BUNDLE) ? Str::classify($bundle).'_' : '';
+ }
+
+ /**
+ * Return the root bundle path for a given bundle.
+ *
+ *
+ * // Returns the bundle path for the "admin" bundle
+ * $path = Bundle::path('admin');
+ *
+ * // Returns the path('app') constant as the default bundle
+ * $path = Bundle::path('application');
+ *
+ *
+ * @param string $bundle
+ * @return string
+ */
+ public static function path($bundle)
+ {
+ if (is_null($bundle) or $bundle === DEFAULT_BUNDLE)
+ {
+ return path('app');
+ }
+ elseif ($location = array_get(static::$bundles, $bundle.'.location'))
+ {
+ // If the bundle location starts with "path: ", we will assume that a raw
+ // path has been specified and will simply return it. Otherwise, we'll
+ // prepend the bundle directory path onto the location and return.
+ if (starts_with($location, 'path: '))
+ {
+ return str_finish(substr($location, 6), DS);
+ }
+ else
+ {
+ return str_finish(path('bundle').$location, DS);
+ }
+ }
+ }
+
+ /**
+ * Return the root asset path for the given bundle.
+ *
+ * @param string $bundle
+ * @return string
+ */
+ public static function assets($bundle)
+ {
+ if (is_null($bundle)) return static::assets(DEFAULT_BUNDLE);
+
+ return ($bundle != DEFAULT_BUNDLE) ? "/bundles/{$bundle}/" : '/';
+ }
+
+ /**
+ * Get the bundle name from a given identifier.
+ *
+ *
+ * // Returns "admin" as the bundle name for the identifier
+ * $bundle = Bundle::name('admin::home.index');
+ *
+ *
+ * @param string $identifier
+ * @return string
+ */
+ public static function name($identifier)
+ {
+ list($bundle, $element) = static::parse($identifier);
+
+ return $bundle;
+ }
+
+ /**
+ * Get the element name from a given identifier.
+ *
+ *
+ * // Returns "home.index" as the element name for the identifier
+ * $bundle = Bundle::bundle('admin::home.index');
+ *
+ *
+ * @param string $identifier
+ * @return string
+ */
+ public static function element($identifier)
+ {
+ list($bundle, $element) = static::parse($identifier);
+
+ return $element;
+ }
+
+ /**
+ * Reconstruct an identifier from a given bundle and element.
+ *
+ *
+ * // Returns "admin::home.index"
+ * $identifier = Bundle::identifier('admin', 'home.index');
+ *
+ * // Returns "home.index"
+ * $identifier = Bundle::identifier('application', 'home.index');
+ *
+ *
+ * @param string $bundle
+ * @param string $element
+ * @return string
+ */
+ public static function identifier($bundle, $element)
+ {
+ return (is_null($bundle) or $bundle == DEFAULT_BUNDLE) ? $element : $bundle.'::'.$element;
+ }
+
+ /**
+ * Return the bundle name if it exists, else return the default bundle.
+ *
+ * @param string $bundle
+ * @return string
+ */
+ public static function resolve($bundle)
+ {
+ return (static::exists($bundle)) ? $bundle : DEFAULT_BUNDLE;
+ }
+
+ /**
+ * Parse a element identifier and return the bundle name and element.
+ *
+ *
+ * // Returns array(null, 'admin.user')
+ * $element = Bundle::parse('admin.user');
+ *
+ * // Parses "admin::user" and returns array('admin', 'user')
+ * $element = Bundle::parse('admin::user');
+ *
+ *
+ * @param string $identifier
+ * @return array
+ */
+ public static function parse($identifier)
+ {
+ // The parsed elements are cached so we don't have to reparse them on each
+ // subsequent request for the parsed element. So if we've already parsed
+ // the given element, we'll just return the cached copy as the value.
+ if (isset(static::$elements[$identifier]))
+ {
+ return static::$elements[$identifier];
+ }
+
+ if (strpos($identifier, '::') !== false)
+ {
+ $element = explode('::', strtolower($identifier));
+ }
+ // If no bundle is in the identifier, we will insert the default bundle
+ // since classes like Config and Lang organize their items by bundle.
+ // The application folder essentially behaves as a default bundle.
+ else
+ {
+ $element = array(DEFAULT_BUNDLE, strtolower($identifier));
+ }
+
+ return static::$elements[$identifier] = $element;
+ }
+
+ /**
+ * Get the information for a given bundle.
+ *
+ * @param string $bundle
+ * @return object
+ */
+ public static function get($bundle)
+ {
+ return array_get(static::$bundles, $bundle);
+ }
+
+ /**
+ * Get an option for a given bundle.
+ *
+ * @param string $bundle
+ * @param string $option
+ * @param mixed $default
+ * @return mixed
+ */
+ public static function option($bundle, $option, $default = null)
+ {
+ $bundle = static::get($bundle);
+
+ if (is_null($bundle))
+ {
+ return value($default);
+ }
+
+ return array_get($bundle, $option, $default);
+ }
+
+ /**
+ * Get all of the installed bundles for the application.
+ *
+ * @return array
+ */
+ public static function all()
+ {
+ return static::$bundles;
+ }
+
+ /**
+ * Get all of the installed bundle names.
+ *
+ * @return array
+ */
+ public static function names()
+ {
+ return array_keys(static::$bundles);
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/cache.php b/laravel/cache.php
new file mode 100644
index 0000000..02b86e4
--- /dev/null
+++ b/laravel/cache.php
@@ -0,0 +1,115 @@
+
+ * // Get the default cache driver instance
+ * $driver = Cache::driver();
+ *
+ * // Get a specific cache driver instance by name
+ * $driver = Cache::driver('memcached');
+ *
+ *
+ * @param string $driver
+ * @return Cache\Drivers\Driver
+ */
+ public static function driver($driver = null)
+ {
+ if (is_null($driver)) $driver = Config::get('cache.driver');
+
+ if ( ! isset(static::$drivers[$driver]))
+ {
+ static::$drivers[$driver] = static::factory($driver);
+ }
+
+ return static::$drivers[$driver];
+ }
+
+ /**
+ * Create a new cache driver instance.
+ *
+ * @param string $driver
+ * @return Cache\Drivers\Driver
+ */
+ protected static function factory($driver)
+ {
+ if (isset(static::$registrar[$driver]))
+ {
+ $resolver = static::$registrar[$driver];
+
+ return $resolver();
+ }
+
+ switch ($driver)
+ {
+ case 'apc':
+ return new Cache\Drivers\APC(Config::get('cache.key'));
+
+ case 'file':
+ return new Cache\Drivers\File(path('storage').'cache'.DS);
+
+ case 'memcached':
+ return new Cache\Drivers\Memcached(Memcached::connection(), Config::get('cache.key'));
+
+ case 'memory':
+ return new Cache\Drivers\Memory;
+
+ case 'redis':
+ return new Cache\Drivers\Redis(Redis::db());
+
+ case 'database':
+ return new Cache\Drivers\Database(Config::get('cache.key'));
+
+ default:
+ throw new \Exception("Cache driver {$driver} is not supported.");
+ }
+ }
+
+ /**
+ * Register a third-party cache driver.
+ *
+ * @param string $driver
+ * @param Closure $resolver
+ * @return void
+ */
+ public static function extend($driver, Closure $resolver)
+ {
+ static::$registrar[$driver] = $resolver;
+ }
+
+ /**
+ * Magic Method for calling the methods on the default cache driver.
+ *
+ *
+ * // Call the "get" method on the default cache driver
+ * $name = Cache::get('name');
+ *
+ * // Call the "put" method on the default cache driver
+ * Cache::put('name', 'Taylor', 15);
+ *
+ */
+ public static function __callStatic($method, $parameters)
+ {
+ return call_user_func_array(array(static::driver(), $method), $parameters);
+ }
+
+}
diff --git a/laravel/cache/drivers/apc.php b/laravel/cache/drivers/apc.php
new file mode 100644
index 0000000..2fade42
--- /dev/null
+++ b/laravel/cache/drivers/apc.php
@@ -0,0 +1,89 @@
+key = $key;
+ }
+
+ /**
+ * Determine if an item exists in the cache.
+ *
+ * @param string $key
+ * @return bool
+ */
+ public function has($key)
+ {
+ return ( ! is_null($this->get($key)));
+ }
+
+ /**
+ * Retrieve an item from the cache driver.
+ *
+ * @param string $key
+ * @return mixed
+ */
+ protected function retrieve($key)
+ {
+ if (($cache = apc_fetch($this->key.$key)) !== false)
+ {
+ return $cache;
+ }
+ }
+
+ /**
+ * Write an item to the cache for a given number of minutes.
+ *
+ *
+ * // Put an item in the cache for 15 minutes
+ * Cache::put('name', 'Taylor', 15);
+ *
+ *
+ * @param string $key
+ * @param mixed $value
+ * @param int $minutes
+ * @return void
+ */
+ public function put($key, $value, $minutes)
+ {
+ apc_store($this->key.$key, $value, $minutes * 60);
+ }
+
+ /**
+ * Write an item to the cache that lasts forever.
+ *
+ * @param string $key
+ * @param mixed $value
+ * @return void
+ */
+ public function forever($key, $value)
+ {
+ return $this->put($key, $value, 0);
+ }
+
+ /**
+ * Delete an item from the cache.
+ *
+ * @param string $key
+ * @return void
+ */
+ public function forget($key)
+ {
+ apc_delete($this->key.$key);
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/cache/drivers/database.php b/laravel/cache/drivers/database.php
new file mode 100644
index 0000000..44bf478
--- /dev/null
+++ b/laravel/cache/drivers/database.php
@@ -0,0 +1,125 @@
+key = $key;
+ }
+
+ /**
+ * Determine if an item exists in the cache.
+ *
+ * @param string $key
+ * @return bool
+ */
+ public function has($key)
+ {
+ return ( ! is_null($this->get($key)));
+ }
+
+ /**
+ * Retrieve an item from the cache driver.
+ *
+ * @param string $key
+ * @return mixed
+ */
+ protected function retrieve($key)
+ {
+ $cache = $this->table()->where('key', '=', $this->key.$key)->first();
+
+ if ( ! is_null($cache))
+ {
+ if (time() >= $cache->expiration) return $this->forget($key);
+
+ return unserialize($cache->value);
+ }
+ }
+
+ /**
+ * Write an item to the cache for a given number of minutes.
+ *
+ *
+ * // Put an item in the cache for 15 minutes
+ * Cache::put('name', 'Taylor', 15);
+ *
+ *
+ * @param string $key
+ * @param mixed $value
+ * @param int $minutes
+ * @return void
+ */
+ public function put($key, $value, $minutes)
+ {
+ $key = $this->key.$key;
+
+ $value = serialize($value);
+
+ $expiration = $this->expiration($minutes);
+
+ // To update the value, we'll first attempt an insert against the
+ // database and if we catch an exception we'll assume that the
+ // primary key already exists in the table and update.
+ try
+ {
+ $this->table()->insert(compact('key', 'value', 'expiration'));
+ }
+ catch (\Exception $e)
+ {
+ $this->table()->where('key', '=', $key)->update(compact('value', 'expiration'));
+ }
+ }
+
+ /**
+ * Write an item to the cache for five years.
+ *
+ * @param string $key
+ * @param mixed $value
+ * @return void
+ */
+ public function forever($key, $value)
+ {
+ return $this->put($key, $value, 2628000);
+ }
+
+ /**
+ * Delete an item from the cache.
+ *
+ * @param string $key
+ * @return void
+ */
+ public function forget($key)
+ {
+ $this->table()->where('key', '=', $this->key.$key)->delete();
+ }
+
+ /**
+ * Get a query builder for the database table.
+ *
+ * @return Laravel\Database\Query
+ */
+ protected function table()
+ {
+ $connection = DB::connection(Config::get('cache.database.connection'));
+
+ return $connection->table(Config::get('cache.database.table'));
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/cache/drivers/driver.php b/laravel/cache/drivers/driver.php
new file mode 100644
index 0000000..2ee13a9
--- /dev/null
+++ b/laravel/cache/drivers/driver.php
@@ -0,0 +1,118 @@
+
+ * // Get an item from the cache driver
+ * $name = Cache::driver('name');
+ *
+ * // Return a default value if the requested item isn't cached
+ * $name = Cache::get('name', 'Taylor');
+ *
+ *
+ * @param string $key
+ * @param mixed $default
+ * @return mixed
+ */
+ public function get($key, $default = null)
+ {
+ return ( ! is_null($item = $this->retrieve($key))) ? $item : value($default);
+ }
+
+ /**
+ * Retrieve an item from the cache driver.
+ *
+ * @param string $key
+ * @return mixed
+ */
+ abstract protected function retrieve($key);
+
+ /**
+ * Write an item to the cache for a given number of minutes.
+ *
+ *
+ * // Put an item in the cache for 15 minutes
+ * Cache::put('name', 'Taylor', 15);
+ *
+ *
+ * @param string $key
+ * @param mixed $value
+ * @param int $minutes
+ * @return void
+ */
+ abstract public function put($key, $value, $minutes);
+
+ /**
+ * Get an item from the cache, or cache and return the default value.
+ *
+ *
+ * // Get an item from the cache, or cache a value for 15 minutes
+ * $name = Cache::remember('name', 'Taylor', 15);
+ *
+ * // Use a closure for deferred execution
+ * $count = Cache::remember('count', function() { return User::count(); }, 15);
+ *
+ *
+ * @param string $key
+ * @param mixed $default
+ * @param int $minutes
+ * @return mixed
+ */
+ public function remember($key, $default, $minutes, $function = 'put')
+ {
+ if ( ! is_null($item = $this->get($key, null))){
+ Log::info('Cache hit for ' . $key);
+ return $item;
+ }
+
+ $this->$function($key, $default = value($default), $minutes);
+
+ Log::info('Cache miss for ' . $key);
+ return $default;
+ }
+
+ /**
+ * Get an item from the cache, or cache the default value forever.
+ *
+ * @param string $key
+ * @param mixed $default
+ * @return mixed
+ */
+ public function sear($key, $default)
+ {
+ return $this->remember($key, $default, null, 'forever');
+ }
+
+ /**
+ * Delete an item from the cache.
+ *
+ * @param string $key
+ * @return void
+ */
+ abstract public function forget($key);
+
+ /**
+ * Get the expiration time as a UNIX timestamp.
+ *
+ * @param int $minutes
+ * @return int
+ */
+ protected function expiration($minutes)
+ {
+ return time() + ($minutes * 60);
+ }
+
+}
diff --git a/laravel/cache/drivers/file.php b/laravel/cache/drivers/file.php
new file mode 100644
index 0000000..c37520e
--- /dev/null
+++ b/laravel/cache/drivers/file.php
@@ -0,0 +1,100 @@
+path = $path;
+ }
+
+ /**
+ * Determine if an item exists in the cache.
+ *
+ * @param string $key
+ * @return bool
+ */
+ public function has($key)
+ {
+ return ( ! is_null($this->get($key)));
+ }
+
+ /**
+ * Retrieve an item from the cache driver.
+ *
+ * @param string $key
+ * @return mixed
+ */
+ protected function retrieve($key)
+ {
+ if ( ! file_exists($this->path.$key)) return null;
+
+ // File based caches store have the expiration timestamp stored in
+ // UNIX format prepended to their contents. We'll compare the
+ // timestamp to the current time when we read the file.
+ if (time() >= substr($cache = file_get_contents($this->path.$key), 0, 10))
+ {
+ return $this->forget($key);
+ }
+
+ return unserialize(substr($cache, 10));
+ }
+
+ /**
+ * Write an item to the cache for a given number of minutes.
+ *
+ *
+ * // Put an item in the cache for 15 minutes
+ * Cache::put('name', 'Taylor', 15);
+ *
+ *
+ * @param string $key
+ * @param mixed $value
+ * @param int $minutes
+ * @return void
+ */
+ public function put($key, $value, $minutes)
+ {
+ if ($minutes <= 0) return;
+
+ $value = $this->expiration($minutes).serialize($value);
+
+ file_put_contents($this->path.$key, $value, LOCK_EX);
+ }
+
+ /**
+ * Write an item to the cache for five years.
+ *
+ * @param string $key
+ * @param mixed $value
+ * @return void
+ */
+ public function forever($key, $value)
+ {
+ return $this->put($key, $value, 2628000);
+ }
+
+ /**
+ * Delete an item from the cache.
+ *
+ * @param string $key
+ * @return void
+ */
+ public function forget($key)
+ {
+ if (file_exists($this->path.$key)) @unlink($this->path.$key);
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/cache/drivers/memcached.php b/laravel/cache/drivers/memcached.php
new file mode 100644
index 0000000..3e6a454
--- /dev/null
+++ b/laravel/cache/drivers/memcached.php
@@ -0,0 +1,185 @@
+key = $key;
+ $this->memcache = $memcache;
+ }
+
+ /**
+ * Determine if an item exists in the cache.
+ *
+ * @param string $key
+ * @return bool
+ */
+ public function has($key)
+ {
+ return ( ! is_null($this->get($key)));
+ }
+
+ /**
+ * Retrieve an item from the cache driver.
+ *
+ * @param string $key
+ * @return mixed
+ */
+ protected function retrieve($key)
+ {
+ if ($this->sectionable($key))
+ {
+ list($section, $key) = $this->parse($key);
+
+ return $this->get_from_section($section, $key);
+ }
+ elseif (($cache = $this->memcache->get($this->key.$key)) !== false)
+ {
+ return $cache;
+ }
+ }
+
+ /**
+ * Write an item to the cache for a given number of minutes.
+ *
+ *
+ * // Put an item in the cache for 15 minutes
+ * Cache::put('name', 'Taylor', 15);
+ *
+ *
+ * @param string $key
+ * @param mixed $value
+ * @param int $minutes
+ * @return void
+ */
+ public function put($key, $value, $minutes)
+ {
+ if ($this->sectionable($key))
+ {
+ list($section, $key) = $this->parse($key);
+
+ return $this->put_in_section($section, $key, $value, $minutes);
+ }
+ else
+ {
+ $this->memcache->set($this->key.$key, $value, $minutes * 60);
+ }
+ }
+
+ /**
+ * Write an item to the cache that lasts forever.
+ *
+ * @param string $key
+ * @param mixed $value
+ * @return void
+ */
+ public function forever($key, $value)
+ {
+ if ($this->sectionable($key))
+ {
+ list($section, $key) = $this->parse($key);
+
+ return $this->forever_in_section($section, $key, $value);
+ }
+ else
+ {
+ return $this->put($key, $value, 0);
+ }
+ }
+
+ /**
+ * Delete an item from the cache.
+ *
+ * @param string $key
+ * @return void
+ */
+ public function forget($key)
+ {
+ if ($this->sectionable($key))
+ {
+ list($section, $key) = $this->parse($key);
+
+ if ($key == '*')
+ {
+ $this->forget_section($section);
+ }
+ else
+ {
+ $this->forget_in_section($section, $key);
+ }
+ }
+ else
+ {
+ $this->memcache->delete($this->key.$key);
+ }
+ }
+
+ /**
+ * Delete an entire section from the cache.
+ *
+ * @param string $section
+ * @return int|bool
+ */
+ public function forget_section($section)
+ {
+ return $this->memcache->increment($this->key.$this->section_key($section));
+ }
+
+ /**
+ * Get the current section ID for a given section.
+ *
+ * @param string $section
+ * @return int
+ */
+ protected function section_id($section)
+ {
+ return $this->sear($this->section_key($section), function()
+ {
+ return rand(1, 10000);
+ });
+ }
+
+ /**
+ * Get a section key name for a given section.
+ *
+ * @param string $section
+ * @return string
+ */
+ protected function section_key($section)
+ {
+ return $section.'_section_key';
+ }
+
+ /**
+ * Get a section item key for a given section and key.
+ *
+ * @param string $section
+ * @param string $key
+ * @return string
+ */
+ protected function section_item_key($section, $key)
+ {
+ return $section.'#'.$this->section_id($section).'#'.$key;
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/cache/drivers/memory.php b/laravel/cache/drivers/memory.php
new file mode 100644
index 0000000..9f57592
--- /dev/null
+++ b/laravel/cache/drivers/memory.php
@@ -0,0 +1,151 @@
+get($key)));
+ }
+
+ /**
+ * Retrieve an item from the cache driver.
+ *
+ * @param string $key
+ * @return mixed
+ */
+ protected function retrieve($key)
+ {
+ if ($this->sectionable($key))
+ {
+ list($section, $key) = $this->parse($key);
+
+ return $this->get_from_section($section, $key);
+ }
+ else
+ {
+ return array_get($this->storage, $key);
+ }
+ }
+
+ /**
+ * Write an item to the cache for a given number of minutes.
+ *
+ *
+ * // Put an item in the cache for 15 minutes
+ * Cache::put('name', 'Taylor', 15);
+ *
+ *
+ * @param string $key
+ * @param mixed $value
+ * @param int $minutes
+ * @return void
+ */
+ public function put($key, $value, $minutes)
+ {
+ if ($this->sectionable($key))
+ {
+ list($section, $key) = $this->parse($key);
+
+ return $this->put_in_section($section, $key, $value, $minutes);
+ }
+ else
+ {
+ array_set($this->storage, $key, $value);
+ }
+ }
+
+ /**
+ * Write an item to the cache that lasts forever.
+ *
+ * @param string $key
+ * @param mixed $value
+ * @return void
+ */
+ public function forever($key, $value)
+ {
+ if ($this->sectionable($key))
+ {
+ list($section, $key) = $this->parse($key);
+
+ return $this->forever_in_section($section, $key, $value);
+ }
+ else
+ {
+ $this->put($key, $value, 0);
+ }
+ }
+
+ /**
+ * Delete an item from the cache.
+ *
+ * @param string $key
+ * @return void
+ */
+ public function forget($key)
+ {
+ if ($this->sectionable($key))
+ {
+ list($section, $key) = $this->parse($key);
+
+ if ($key == '*')
+ {
+ $this->forget_section($section);
+ }
+ else
+ {
+ $this->forget_in_section($section, $key);
+ }
+ }
+ else
+ {
+ array_forget($this->storage, $key);
+ }
+ }
+
+ /**
+ * Delete an entire section from the cache.
+ *
+ * @param string $section
+ * @return int|bool
+ */
+ public function forget_section($section)
+ {
+ array_forget($this->storage, 'section#'.$section);
+ }
+
+ /**
+ * Flush the entire cache.
+ *
+ * @return void
+ */
+ public function flush()
+ {
+ $this->storage = array();
+ }
+
+ /**
+ * Get a section item key for a given section and key.
+ *
+ * @param string $section
+ * @param string $key
+ * @return string
+ */
+ protected function section_item_key($section, $key)
+ {
+ return "section#{$section}.{$key}";
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/cache/drivers/redis.php b/laravel/cache/drivers/redis.php
new file mode 100644
index 0000000..3195566
--- /dev/null
+++ b/laravel/cache/drivers/redis.php
@@ -0,0 +1,91 @@
+redis = $redis;
+ }
+
+ /**
+ * Determine if an item exists in the cache.
+ *
+ * @param string $key
+ * @return bool
+ */
+ public function has($key)
+ {
+ return ( ! is_null($this->redis->get($key)));
+ }
+
+ /**
+ * Retrieve an item from the cache driver.
+ *
+ * @param string $key
+ * @return mixed
+ */
+ protected function retrieve($key)
+ {
+ if ( ! is_null($cache = $this->redis->get($key)))
+ {
+ return unserialize($cache);
+ }
+ }
+
+ /**
+ * Write an item to the cache for a given number of minutes.
+ *
+ *
+ * // Put an item in the cache for 15 minutes
+ * Cache::put('name', 'Taylor', 15);
+ *
+ *
+ * @param string $key
+ * @param mixed $value
+ * @param int $minutes
+ * @return void
+ */
+ public function put($key, $value, $minutes)
+ {
+ $this->forever($key, $value);
+
+ $this->redis->expire($key, $minutes * 60);
+ }
+
+ /**
+ * Write an item to the cache that lasts forever.
+ *
+ * @param string $key
+ * @param mixed $value
+ * @return void
+ */
+ public function forever($key, $value)
+ {
+ $this->redis->set($key, serialize($value));
+ }
+
+ /**
+ * Delete an item from the cache.
+ *
+ * @param string $key
+ * @return void
+ */
+ public function forget($key)
+ {
+ $this->redis->del($key);
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/cache/drivers/sectionable.php b/laravel/cache/drivers/sectionable.php
new file mode 100644
index 0000000..4ec7824
--- /dev/null
+++ b/laravel/cache/drivers/sectionable.php
@@ -0,0 +1,141 @@
+get($this->section_item_key($section, $key), $default);
+ }
+
+ /**
+ * Write a sectioned item to the cache.
+ *
+ * @param string $section
+ * @param string $key
+ * @param mixed $value
+ * @param int $minutes
+ * @return void
+ */
+ public function put_in_section($section, $key, $value, $minutes)
+ {
+ $this->put($this->section_item_key($section, $key), $value, $minutes);
+ }
+
+ /**
+ * Write a sectioned item to the cache that lasts forever.
+ *
+ * @param string $section
+ * @param string $key
+ * @param mixed $value
+ * @return void
+ */
+ public function forever_in_section($section, $key, $value)
+ {
+ return $this->forever($this->section_item_key($section, $key), $value);
+ }
+
+ /**
+ * Get a sectioned item from the cache, or cache and return the default value.
+ *
+ * @param string $section
+ * @param string $key
+ * @param mixed $default
+ * @param int $minutes
+ * @return mixed
+ */
+ public function remember_in_section($section, $key, $default, $minutes, $function = 'put')
+ {
+ $key = $this->section_item_key($section, $key);
+
+ return $this->remember($key, $default, $minutes, $function);
+ }
+
+ /**
+ * Get a sectioned item from the cache, or cache the default value forever.
+ *
+ * @param string $section
+ * @param string $key
+ * @param mixed $default
+ * @return mixed
+ */
+ public function sear_in_section($section, $key, $default)
+ {
+ return $this->sear($this->section_item_key($section, $key), $default);
+ }
+
+ /**
+ * Delete a sectioned item from the cache.
+ *
+ * @param string $section
+ * @param string $key
+ * @return void
+ */
+ public function forget_in_section($section, $key)
+ {
+ return $this->forget($this->section_item_key($section, $key));
+ }
+
+ /**
+ * Delete an entire section from the cache.
+ *
+ * @param string $section
+ * @return int|bool
+ */
+ abstract public function forget_section($section);
+
+ /**
+ * Indicates if a key is sectionable.
+ *
+ * @param string $key
+ * @return bool
+ */
+ protected function sectionable($key)
+ {
+ return $this->implicit and $this->sectioned($key);
+ }
+
+ /**
+ * Determine if a key is sectioned.
+ *
+ * @param string $key
+ * @return bool
+ */
+ protected function sectioned($key)
+ {
+ return str_contains($key, '::');
+ }
+
+ /**
+ * Get the section and key from a sectioned key.
+ *
+ * @param string $key
+ * @return array
+ */
+ protected function parse($key)
+ {
+ return explode('::', $key, 2);
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/cli/artisan.php b/laravel/cli/artisan.php
new file mode 100644
index 0000000..46886dc
--- /dev/null
+++ b/laravel/cli/artisan.php
@@ -0,0 +1,49 @@
+getMessage();
+}
+
+echo PHP_EOL;
\ No newline at end of file
diff --git a/laravel/cli/command.php b/laravel/cli/command.php
new file mode 100644
index 0000000..7b4ae3a
--- /dev/null
+++ b/laravel/cli/command.php
@@ -0,0 +1,198 @@
+
+ * // Call the migrate artisan task
+ * Command::run(array('migrate'));
+ *
+ * // Call the migrate task with some arguments
+ * Command::run(array('migrate:rollback', 'bundle-name'))
+ *
+ *
+ * @param array $arguments
+ * @return void
+ */
+ public static function run($arguments = array())
+ {
+ static::validate($arguments);
+
+ list($bundle, $task, $method) = static::parse($arguments[0]);
+
+ // If the task exists within a bundle, we will start the bundle so that any
+ // dependencies can be registered in the application IoC container. If the
+ // task is registered in the container, we'll resolve it.
+ if (Bundle::exists($bundle))
+ {
+ Bundle::start($bundle);
+ }
+
+ $task = static::resolve($bundle, $task);
+
+ // Once the bundle has been resolved, we'll make sure we could actually
+ // find that task, and then verify that the method exists on the task
+ // so we can successfully call it without a problem.
+ if (is_null($task))
+ {
+ throw new \Exception("Sorry, I can't find that task.");
+ }
+
+ if (is_callable(array($task, $method)))
+ {
+ $task->$method(array_slice($arguments, 1));
+ }
+ else
+ {
+ throw new \Exception("Sorry, I can't find that method!");
+ }
+ }
+
+ /**
+ * Determine if the given command arguments are valid.
+ *
+ * @param array $arguments
+ * @return void
+ */
+ protected static function validate($arguments)
+ {
+ if ( ! isset($arguments[0]))
+ {
+ throw new \Exception("You forgot to provide the task name.");
+ }
+ }
+
+ /**
+ * Parse the task name to extract the bundle, task, and method.
+ *
+ * @param string $task
+ * @return array
+ */
+ protected static function parse($task)
+ {
+ list($bundle, $task) = Bundle::parse($task);
+
+ // Extract the task method from the task string. Methods are called
+ // on tasks by separating the task and method with a single colon.
+ // If no task is specified, "run" is used as the default.
+ if (str_contains($task, ':'))
+ {
+ list($task, $method) = explode(':', $task);
+ }
+ else
+ {
+ $method = 'run';
+ }
+
+ return array($bundle, $task, $method);
+ }
+
+ /**
+ * Resolve an instance of the given task name.
+ *
+ *
+ * // Resolve an instance of a task
+ * $task = Command::resolve('application', 'migrate');
+ *
+ * // Resolve an instance of a task wtihin a bundle
+ * $task = Command::resolve('bundle', 'foo');
+ *
+ *
+ * @param string $bundle
+ * @param string $task
+ * @return object
+ */
+ public static function resolve($bundle, $task)
+ {
+ $identifier = Bundle::identifier($bundle, $task);
+
+ // First we'll check to see if the task has been registered in the
+ // application IoC container. This allows all dependencies to be
+ // injected into tasks for more flexible testability.
+ if (IoC::registered("task: {$identifier}"))
+ {
+ return IoC::resolve("task: {$identifier}");
+ }
+
+ // If the task file exists, we'll format the bundle and task name
+ // into a task class name and resolve an instance of the so that
+ // the requested method may be executed.
+ if (file_exists($path = Bundle::path($bundle).'tasks/'.$task.EXT))
+ {
+ require $path;
+
+ $task = static::format($bundle, $task);
+
+ return new $task;
+ }
+ }
+
+ /**
+ * Parse the command line arguments and return the results.
+ *
+ * @param array $argv
+ * @return array
+ */
+ public static function options($argv)
+ {
+ $options = array();
+
+ $arguments = array();
+
+ for ($i = 0, $count = count($argv); $i < $count; $i++)
+ {
+ $argument = $argv[$i];
+
+ // If the CLI argument starts with a double hyphen, it is an option,
+ // so we will extract the value and add it to the array of options
+ // to be returned by the method.
+ if (starts_with($argument, '--'))
+ {
+ // By default, we will assume the value of the options is true,
+ // but if the option contains an equals sign, we will take the
+ // value to the right of the equals sign as the value and
+ // remove the value from the option key.
+ list($key, $value) = array(substr($argument, 2), true);
+
+ if (($equals = strpos($argument, '=')) !== false)
+ {
+ $key = substr($argument, 2, $equals - 2);
+
+ $value = substr($argument, $equals + 1);
+ }
+
+ $options[$key] = $value;
+ }
+ // If the CLI argument does not start with a double hyphen it's
+ // simply an argument to be passed to the console task so we'll
+ // add it to the array of "regular" arguments.
+ else
+ {
+ $arguments[] = $argument;
+ }
+ }
+
+ return array($arguments, $options);
+ }
+
+ /**
+ * Format a bundle and task into a task class name.
+ *
+ * @param string $bundle
+ * @param string $task
+ * @return string
+ */
+ protected static function format($bundle, $task)
+ {
+ $prefix = Bundle::class_prefix($bundle);
+
+ return '\\'.$prefix.Str::classify($task).'_Task';
+ }
+
+}
diff --git a/laravel/cli/dependencies.php b/laravel/cli/dependencies.php
new file mode 100644
index 0000000..f0c59e8
--- /dev/null
+++ b/laravel/cli/dependencies.php
@@ -0,0 +1,128 @@
+repository = $repository;
+ }
+
+ /**
+ * Install the given bundles into the application.
+ *
+ * @param array $bundles
+ * @return void
+ */
+ public function install($bundles)
+ {
+ foreach ($this->get($bundles) as $bundle)
+ {
+ if (Bundle::exists($bundle['name']))
+ {
+ echo "Bundle {$bundle['name']} is already installed.";
+
+ continue;
+ }
+
+ // Once we have the bundle information, we can resolve an instance
+ // of a provider and install the bundle into the application and
+ // all of its registered dependencies as well.
+ //
+ // Each bundle provider implements the Provider interface and
+ // is repsonsible for retrieving the bundle source from its
+ // hosting party and installing it into the application.
+ $path = path('bundle').$this->path($bundle);
+
+ echo "Fetching [{$bundle['name']}]...";
+
+ $this->download($bundle, $path);
+
+ echo "done! Bundle installed.".PHP_EOL;
+ }
+ }
+
+ /**
+ * Upgrade the given bundles for the application.
+ *
+ * @param array $bundles
+ * @return void
+ */
+ public function upgrade($bundles)
+ {
+ if (count($bundles) == 0) $bundles = Bundle::names();
+
+ foreach ($bundles as $name)
+ {
+ if ( ! Bundle::exists($name))
+ {
+ echo "Bundle [{$name}] is not installed!";
+
+ continue;
+ }
+
+ // First we want to retrieve the information for the bundle, such as
+ // where it is currently installed. This will allow us to upgrade
+ // the bundle into it's current installation path.
+ $location = Bundle::path($name);
+
+ // If the bundle exists, we will grab the data about the bundle from
+ // the API so we can make the right bundle provider for the bundle,
+ // since we don't know the provider used to install.
+ $response = $this->retrieve($name);
+
+ if ($response['status'] == 'not-found')
+ {
+ continue;
+ }
+
+ // Once we have the bundle information from the API, we'll simply
+ // recursively delete the bundle and then re-download it using
+ // the correct provider assigned to the bundle.
+ File::rmdir($location);
+
+ $this->download($response['bundle'], $location);
+
+ echo "Bundle [{$name}] has been upgraded!".PHP_EOL;
+ }
+ }
+
+ /**
+ * Gather all of the bundles from the bundle repository.
+ *
+ * @param array $bundles
+ * @return array
+ */
+ protected function get($bundles)
+ {
+ $responses = array();
+
+ foreach ($bundles as $bundle)
+ {
+ // First we'll call the bundle repository to gather the bundle data
+ // array, which contains all of the information needed to install
+ // the bundle into the Laravel application.
+ $response = $this->retrieve($bundle);
+
+ if ($response['status'] == 'not-found')
+ {
+ throw new \Exception("There is no bundle named [$bundle].");
+ }
+
+ // If the bundle was retrieved successfully, we will add it to
+ // our array of bundles, as well as merge all of the bundle's
+ // dependencies into the array of responses.
+ $bundle = $response['bundle'];
+
+ $responses[] = $bundle;
+
+ // We'll also get the bundle's declared dependenceis so they
+ // can be installed along with the bundle, making it easy
+ // to install a group of bundles.
+ $dependencies = $this->get($bundle['dependencies']);
+
+ $responses = array_merge($responses, $dependencies);
+ }
+
+ return $responses;
+ }
+
+ /**
+ * Publish bundle assets to the public directory.
+ *
+ * @param array $bundles
+ * @return void
+ */
+ public function publish($bundles)
+ {
+ if (count($bundles) == 0) $bundles = Bundle::names();
+
+ array_walk($bundles, array(IoC::resolve('bundle.publisher'), 'publish'));
+ }
+
+ /**
+ * Install a bundle using a provider.
+ *
+ * @param string $bundle
+ * @param string $path
+ * @return void
+ */
+ protected function download($bundle, $path)
+ {
+ $provider = "bundle.provider: {$bundle['provider']}";
+
+ IoC::resolve($provider)->install($bundle, $path);
+ }
+
+ /**
+ * Retrieve a bundle from the repository.
+ *
+ * @param string $bundle
+ * @return array
+ */
+ protected function retrieve($bundle)
+ {
+ $response = $this->repository->get($bundle);
+
+ if ( ! $response)
+ {
+ throw new \Exception("The bundle API is not responding.");
+ }
+
+ return $response;
+ }
+
+ /**
+ * Return the path for a given bundle.
+ *
+ * @param array $bundle
+ * @return string
+ */
+ protected function path($bundle)
+ {
+ return array_get($bundle, 'path', $bundle['name']);
+ }
+
+}
diff --git a/laravel/cli/tasks/bundle/providers/github.php b/laravel/cli/tasks/bundle/providers/github.php
new file mode 100644
index 0000000..7aa3462
--- /dev/null
+++ b/laravel/cli/tasks/bundle/providers/github.php
@@ -0,0 +1,19 @@
+download($url));
+
+ $zip = new \ZipArchive;
+
+ $zip->open($target);
+
+ // Once we have the Zip archive, we can open it and extract it
+ // into the working directory. By convention, we expect the
+ // archive to contain one root directory with the bundle.
+ mkdir($work.'zip');
+
+ $zip->extractTo($work.'zip');
+
+ $latest = File::latest($work.'zip')->getRealPath();
+
+ @chmod($latest, 0777);
+
+ // Once we have the latest modified directory, we should be
+ // able to move its contents over into the bundles folder
+ // so the bundle will be usable by the develoepr.
+ File::mvdir($latest, $path);
+
+ File::rmdir($work.'zip');
+
+ $zip->close();
+ @unlink($target);
+ }
+
+ /**
+ * Download a remote zip archive from a URL.
+ *
+ * @param string $url
+ * @return string
+ */
+ protected function download($url)
+ {
+ $remote = file_get_contents($url);
+
+ // If we were unable to download the zip archive correctly
+ // we'll bomb out since we don't want to extract the last
+ // zip that was put in the storage directory.
+ if ($remote === false)
+ {
+ throw new \Exception("Error downloading bundle [{$bundle}].");
+ }
+
+ return $remote;
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/cli/tasks/bundle/publisher.php b/laravel/cli/tasks/bundle/publisher.php
new file mode 100644
index 0000000..12527b0
--- /dev/null
+++ b/laravel/cli/tasks/bundle/publisher.php
@@ -0,0 +1,65 @@
+move($path.'public', path('public').'bundles'.DS.$bundle);
+
+ echo "Assets published for bundle [$bundle].".PHP_EOL;
+ }
+
+ /**
+ * Copy the contents of a bundle's assets to the public folder.
+ *
+ * @param string $source
+ * @param string $destination
+ * @return void
+ */
+ protected function move($source, $destination)
+ {
+ File::cpdir($source, $destination);
+ }
+
+ /**
+ * Get the "to" location of the bundle's assets.
+ *
+ * @param string $bundle
+ * @return string
+ */
+ protected function to($bundle)
+ {
+ return path('public').'bundles'.DS.$bundle.DS;
+ }
+
+ /**
+ * Get the "from" location of the bundle's assets.
+ *
+ * @param string $bundle
+ * @return string
+ */
+ protected function from($bundle)
+ {
+ return Bundle::path($bundle).'public';
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/cli/tasks/bundle/repository.php b/laravel/cli/tasks/bundle/repository.php
new file mode 100644
index 0000000..2ee43d9
--- /dev/null
+++ b/laravel/cli/tasks/bundle/repository.php
@@ -0,0 +1,29 @@
+api.$bundle);
+
+ return json_decode($bundle, true);
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/cli/tasks/key.php b/laravel/cli/tasks/key.php
new file mode 100644
index 0000000..0c08a84
--- /dev/null
+++ b/laravel/cli/tasks/key.php
@@ -0,0 +1,57 @@
+path = path('app').'config/application'.EXT;
+ }
+
+ /**
+ * Generate a random key for the application.
+ *
+ * @param array $arguments
+ * @return void
+ */
+ public function generate($arguments = array())
+ {
+ // By default the Crypter class uses AES-256 encryption which uses
+ // a 32 byte input vector, so that is the length of string we will
+ // generate for the application token unless another length is
+ // specified through the CLI.
+ $key = Str::random(array_get($arguments, 0, 32));
+
+ $config = File::get($this->path);
+
+ $config = str_replace("'key' => '',", "'key' => '{$key}',", $config, $count);
+
+ File::put($this->path, $config);
+
+ if ($count > 0)
+ {
+ echo "Configuration updated with secure key!";
+ }
+ else
+ {
+ echo "An application key already exists!";
+ }
+
+ echo PHP_EOL;
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/cli/tasks/migrate/database.php b/laravel/cli/tasks/migrate/database.php
new file mode 100644
index 0000000..a6aae9d
--- /dev/null
+++ b/laravel/cli/tasks/migrate/database.php
@@ -0,0 +1,84 @@
+table()->insert(compact('bundle', 'name', 'batch'));
+ }
+
+ /**
+ * Delete a row from the migration table.
+ *
+ * @param string $bundle
+ * @param string $name
+ * @return void
+ */
+ public function delete($bundle, $name)
+ {
+ $this->table()->where_bundle_and_name($bundle, $name)->delete();
+ }
+
+ /**
+ * Return an array of the last batch of migrations.
+ *
+ * @return array
+ */
+ public function last()
+ {
+ $table = $this->table();
+
+ // First we need to grab the last batch ID from the migration table,
+ // as this will allow us to grab the lastest batch of migrations
+ // that need to be run for a rollback command.
+ $id = $this->batch();
+
+ // Once we have the batch ID, we will pull all of the rows for that
+ // batch. Then we can feed the results into the resolve method to
+ // get the migration instances for the command.
+ return $table->where_batch($id)->order_by('name', 'desc')->get();
+ }
+
+ /**
+ * Get all of the migrations that have run for a bundle.
+ *
+ * @param string $bundle
+ * @return array
+ */
+ public function ran($bundle)
+ {
+ return $this->table()->where_bundle($bundle)->lists('name');
+ }
+
+ /**
+ * Get the maximum batch ID from the migration table.
+ *
+ * @return int
+ */
+ public function batch()
+ {
+ return $this->table()->max('batch');
+ }
+
+ /**
+ * Get a database query instance for the migration table.
+ *
+ * @return Laravel\Database\Query
+ */
+ protected function table()
+ {
+ return DB::connection(Request::server('cli.db'))->table('laravel_migrations');
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/cli/tasks/migrate/migrator.php b/laravel/cli/tasks/migrate/migrator.php
new file mode 100644
index 0000000..5bf7617
--- /dev/null
+++ b/laravel/cli/tasks/migrate/migrator.php
@@ -0,0 +1,245 @@
+resolver = $resolver;
+ $this->database = $database;
+ }
+
+ /**
+ * Run a database migration command.
+ *
+ * @param array $arguments
+ * @return void
+ */
+ public function run($arguments = array())
+ {
+ // If no arguments were passed to the task, we will just migrate
+ // to the latest version across all bundles. Otherwise, we will
+ // parse the arguments to determine the bundle for which the
+ // database migrations should be run.
+ if (count($arguments) == 0)
+ {
+ $this->migrate();
+ }
+ else
+ {
+ $this->migrate(array_get($arguments, 0));
+ }
+ }
+
+ /**
+ * Run the outstanding migrations for a given bundle.
+ *
+ * @param string $bundle
+ * @param int $version
+ * @return void
+ */
+ public function migrate($bundle = null, $version = null)
+ {
+ $migrations = $this->resolver->outstanding($bundle);
+
+ if (count($migrations) == 0)
+ {
+ echo "No outstanding migrations.";
+
+ return;
+ }
+
+ // We need to grab the latest batch ID and increment it by one.
+ // This allows us to group the migrations so we can easily
+ // determine which migrations need to roll back.
+ $batch = $this->database->batch() + 1;
+
+ foreach ($migrations as $migration)
+ {
+ $migration['migration']->up();
+
+ echo 'Migrated: '.$this->display($migration).PHP_EOL;
+
+ // After running a migration, we log its execution in the migration
+ // table so that we can easily determine which migrations we'll
+ // reverse in the event of a migration rollback.
+ $this->database->log($migration['bundle'], $migration['name'], $batch);
+ }
+ }
+
+ /**
+ * Rollback the latest migration command.
+ *
+ * @param array $arguments
+ * @return bool
+ */
+ public function rollback($arguments = array())
+ {
+ $migrations = $this->resolver->last();
+
+ if (count($migrations) == 0)
+ {
+ echo "Nothing to rollback.";
+
+ return false;
+ }
+
+ // The "last" method on the resolver returns an array of migrations,
+ // along with their bundles and names. We will iterate through each
+ // migration and run the "down" method.
+ foreach (array_reverse($migrations) as $migration)
+ {
+ $migration['migration']->down();
+
+ echo 'Rolled back: '.$this->display($migration).PHP_EOL;
+
+ // By only removing the migration after it has successfully rolled back,
+ // we can re-run the rollback command in the event of any errors with
+ // the migration and pick up where we left off.
+ $this->database->delete($migration['bundle'], $migration['name']);
+ }
+
+ return true;
+ }
+
+ /**
+ * Rollback all of the executed migrations.
+ *
+ * @param array $arguments
+ * @return void
+ */
+ public function reset($arguments = array())
+ {
+ while ($this->rollback()) {};
+ }
+
+ /**
+ * Install the database tables used by the migration system.
+ *
+ * @return void
+ */
+ public function install()
+ {
+ Schema::table('laravel_migrations', function($table)
+ {
+ $table->create();
+
+ // Migrations can be run for a specific bundle, so we'll use
+ // the bundle name and string migration name as an unique ID
+ // for the migrations, allowing us to easily identify which
+ // migrations have been run for each bundle.
+ $table->string('bundle', 50);
+
+ $table->string('name', 200);
+
+ // When running a migration command, we will store a batch
+ // ID with each of the rows on the table. This will allow
+ // us to grab all of the migrations that were run for the
+ // last command when performing rollbacks.
+ $table->integer('batch');
+
+ $table->primary(array('bundle', 'name'));
+ });
+
+ echo "Migration table created successfully.";
+ }
+
+ /**
+ * Generate a new migration file.
+ *
+ * @param array $arguments
+ * @return string
+ */
+ public function make($arguments = array())
+ {
+ if (count($arguments) == 0)
+ {
+ throw new \Exception("I need to know what to name the migration.");
+ }
+
+ list($bundle, $migration) = Bundle::parse($arguments[0]);
+
+ // The migration path is prefixed with the date timestamp, which
+ // is a better way of ordering migrations than a simple integer
+ // incrementation, since developers may start working on the
+ // next migration at the same time unknowingly.
+ $prefix = date('Y_m_d_His');
+
+ $path = Bundle::path($bundle).'migrations'.DS;
+
+ // If the migration directory does not exist for the bundle,
+ // we will create the directory so there aren't errors when
+ // when we try to write the migration file.
+ if ( ! is_dir($path)) mkdir($path);
+
+ $file = $path.$prefix.'_'.$migration.EXT;
+
+ File::put($file, $this->stub($bundle, $migration));
+
+ echo "Great! New migration created!";
+
+ // Once the migration has been created, we'll return the
+ // migration file name so it can be used by the task
+ // consumer if necessary for futher work.
+ return $file;
+ }
+
+ /**
+ * Get the stub migration with the proper class name.
+ *
+ * @param string $bundle
+ * @param string $migration
+ * @return string
+ */
+ protected function stub($bundle, $migration)
+ {
+ $stub = File::get(path('sys').'cli/tasks/migrate/stub'.EXT);
+
+ $prefix = Bundle::class_prefix($bundle);
+
+ // The class name is formatted simialrly to tasks and controllers,
+ // where the bundle name is prefixed to the class if it is not in
+ // the default "application" bundle.
+ $class = $prefix.Str::classify($migration);
+
+ return str_replace('{{class}}', $class, $stub);
+ }
+
+ /**
+ * Get the migration bundle and name for display.
+ *
+ * @param array $migration
+ * @return string
+ */
+ protected function display($migration)
+ {
+ return $migration['bundle'].'/'.$migration['name'];
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/cli/tasks/migrate/resolver.php b/laravel/cli/tasks/migrate/resolver.php
new file mode 100644
index 0000000..0e144b4
--- /dev/null
+++ b/laravel/cli/tasks/migrate/resolver.php
@@ -0,0 +1,175 @@
+database = $database;
+ }
+
+ /**
+ * Resolve all of the outstanding migrations for a bundle.
+ *
+ * @param string $bundle
+ * @return array
+ */
+ public function outstanding($bundle = null)
+ {
+ $migrations = array();
+
+ // If no bundle was given to the command, we'll grab every bundle for
+ // the application, including the "application" bundle, which is not
+ // returned by "all" method on the Bundle class.
+ if (is_null($bundle))
+ {
+ $bundles = array_merge(Bundle::names(), array('application'));
+ }
+ else
+ {
+ $bundles = array($bundle);
+ }
+
+ foreach ($bundles as $bundle)
+ {
+ // First we need to grab all of the migrations that have already
+ // run for this bundle, as well as all of the migration files
+ // for the bundle. Once we have these, we can determine which
+ // migrations are still outstanding.
+ $ran = $this->database->ran($bundle);
+
+ $files = $this->migrations($bundle);
+
+ // To find outstanding migrations, we will simply iterate over
+ // the migration files and add the files that do not exist in
+ // the array of ran migrations to the outstanding array.
+ foreach ($files as $key => $name)
+ {
+ if ( ! in_array($name, $ran))
+ {
+ $migrations[] = compact('bundle', 'name');
+ }
+ }
+ }
+
+ return $this->resolve($migrations);
+ }
+
+ /**
+ * Resolve an array of the last batch of migrations.
+ *
+ * @return array
+ */
+ public function last()
+ {
+ return $this->resolve($this->database->last());
+ }
+
+ /**
+ * Resolve an array of migration instances.
+ *
+ * @param array $migrations
+ * @return array
+ */
+ protected function resolve($migrations)
+ {
+ $instances = array();
+
+ foreach ($migrations as $migration)
+ {
+ $migration = (array) $migration;
+
+ // The migration array contains the bundle name, so we will get the
+ // path to the bundle's migrations and resolve an instance of the
+ // migration using the name.
+ $bundle = $migration['bundle'];
+
+ $path = Bundle::path($bundle).'migrations/';
+
+ // Migrations are not resolved through the auto-loader, so we will
+ // manually instantiate the migration class instances for each of
+ // the migration names we're given.
+ $name = $migration['name'];
+
+ require_once $path.$name.EXT;
+
+ // Since the migration name will begin with the numeric ID, we'll
+ // slice off the ID so we are left with the migration class name.
+ // The IDs are for sorting when resolving outstanding migrations.
+ //
+ // Migrations that exist within bundles other than the default
+ // will be prefixed with the bundle name to avoid any possible
+ // naming collisions with other bundle's migrations.
+ $prefix = Bundle::class_prefix($bundle);
+
+ $class = $prefix.\Laravel\Str::classify(substr($name, 18));
+
+ $migration = new $class;
+
+ // When adding to the array of instances, we will actually
+ // add the migration instance, the bundle, and the name.
+ // This allows the migrator to log the bundle and name
+ // when the migration is executed.
+ $instances[] = compact('bundle', 'name', 'migration');
+ }
+
+ // At this point the migrations are only sorted within their
+ // bundles so we need to resort them by name to ensure they
+ // are in a consistent order.
+ usort($instances, function($a, $b)
+ {
+ return strcmp($a['name'], $b['name']);
+ });
+
+ return $instances;
+ }
+
+ /**
+ * Grab all of the migration filenames for a bundle.
+ *
+ * @param string $bundle
+ * @return array
+ */
+ protected function migrations($bundle)
+ {
+ $files = glob(Bundle::path($bundle).'migrations/*_*'.EXT);
+
+ // When open_basedir is enabled, glob will return false on an
+ // empty directory, so we will return an empty array in this
+ // case so the application doesn't bomb out.
+ if ($files === false)
+ {
+ return array();
+ }
+
+ // Once we have the array of files in the migration directory,
+ // we'll take the basename of the file and remove the PHP file
+ // extension, which isn't needed.
+ foreach ($files as &$file)
+ {
+ $file = str_replace(EXT, '', basename($file));
+ }
+
+ // We'll also sort the files so that the earlier migrations
+ // will be at the front of the array and will be resolved
+ // first by this class' resolve method.
+ sort($files);
+
+ return $files;
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/cli/tasks/migrate/stub.php b/laravel/cli/tasks/migrate/stub.php
new file mode 100644
index 0000000..6ce685f
--- /dev/null
+++ b/laravel/cli/tasks/migrate/stub.php
@@ -0,0 +1,25 @@
+route();
+
+ echo PHP_EOL;
+ }
+
+ /**
+ * Dump the results of the currently established route.
+ *
+ * @return void
+ */
+ protected function route()
+ {
+ // We'll call the router using the method and URI specified by
+ // the developer on the CLI. If a route is found, we will not
+ // run the filters, but simply dump the result.
+ $route = Router::route(Request::method(), URI::current());
+
+ if ( ! is_null($route))
+ {
+ var_dump($route->response());
+ }
+ else
+ {
+ echo '404: Not Found';
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/cli/tasks/session/manager.php b/laravel/cli/tasks/session/manager.php
new file mode 100644
index 0000000..ebf30a0
--- /dev/null
+++ b/laravel/cli/tasks/session/manager.php
@@ -0,0 +1,93 @@
+generate();
+
+ // To create the session table, we will actually create a database
+ // migration and then run it. This allows the application to stay
+ // portable through the framework's migrations system.
+ $migration = $migrator->make(array('create_session_table'));
+
+ $stub = path('sys').'cli/tasks/session/migration'.EXT;
+
+ File::put($migration, File::get($stub));
+
+ // By default no session driver is set within the configuration.
+ // Since the developer is requesting that the session table be
+ // created on the database, we'll set it.
+ $this->driver('database');
+
+ echo PHP_EOL;
+
+ $migrator->run();
+ }
+
+ /**
+ * Sweep the expired sessions from storage.
+ *
+ * @param array $arguments
+ * @return void
+ */
+ public function sweep($arguments = array())
+ {
+ $driver = Session::factory(Config::get('session.driver'));
+
+ // If the driver implements the "Sweeper" interface, we know that it
+ // can sweep expired sessions from storage. Not all drivers need be
+ // sweepers since they do their own.
+ if ($driver instanceof Sweeper)
+ {
+ $lifetime = Config::get('session.lifetime');
+
+ $driver->sweep(time() - ($lifetime * 60));
+ }
+
+ echo "The session table has been swept!";
+ }
+
+ /**
+ * Set the session driver to a given value.
+ *
+ * @param string $driver
+ * @return void
+ */
+ protected function driver($driver)
+ {
+ // By default no session driver is set within the configuration.
+ // This method will replace the empty driver option with the
+ // driver specified in the arguments.
+ $config = File::get(path('app').'config/session'.EXT);
+
+ $config = str_replace(
+ "'driver' => '',",
+ "'driver' => 'database',",
+ $config
+ );
+
+ File::put(path('app').'config/session'.EXT, $config);
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/cli/tasks/session/migration.php b/laravel/cli/tasks/session/migration.php
new file mode 100644
index 0000000..8ef8632
--- /dev/null
+++ b/laravel/cli/tasks/session/migration.php
@@ -0,0 +1,40 @@
+create();
+
+ // The session table consists simply of an ID, a UNIX timestamp to
+ // indicate the expiration time, and a blob field which will hold
+ // the serialized form of the session payload.
+ $table->string('id')->length(40)->primary('session_primary');
+
+ $table->integer('last_activity');
+
+ $table->text('data');
+ });
+ }
+
+ /**
+ * Revert the changes to the database.
+ *
+ * @return void
+ */
+ public function down()
+ {
+ Schema::table(Config::get('session.table'), function($table)
+ {
+ $table->drop();
+ });
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/cli/tasks/task.php b/laravel/cli/tasks/task.php
new file mode 100644
index 0000000..0ed4e2c
--- /dev/null
+++ b/laravel/cli/tasks/task.php
@@ -0,0 +1,3 @@
+
+ * @link http://laravel.com
+ */
+
+// --------------------------------------------------------------
+// Define the directory separator for the environment.
+// --------------------------------------------------------------
+define('DS', DIRECTORY_SEPARATOR);
+
+// --------------------------------------------------------------
+// Set the core Laravel path constants.
+// --------------------------------------------------------------
+require 'paths.php';
+
+// --------------------------------------------------------------
+// Override the application paths when testing the core.
+// --------------------------------------------------------------
+$config = file_get_contents('phpunit.xml');
+
+if (strpos($config, 'laravel-tests') !== false)
+{
+ $path = path('bundle').'laravel-tests'.DS;
+
+ set_path('app', $path.'application'.DS);
+
+ set_path('bundle', $path.'bundles'.DS);
+
+ set_path('storage', $path.'storage'.DS);
+}
+
+// --------------------------------------------------------------
+// Bootstrap the Laravel core.
+// --------------------------------------------------------------
+require path('sys').'core.php';
+
+// --------------------------------------------------------------
+// Start the default bundle.
+// --------------------------------------------------------------
+Laravel\Bundle::start(DEFAULT_BUNDLE);
\ No newline at end of file
diff --git a/laravel/cli/tasks/test/runner.php b/laravel/cli/tasks/test/runner.php
new file mode 100644
index 0000000..8578789
--- /dev/null
+++ b/laravel/cli/tasks/test/runner.php
@@ -0,0 +1,138 @@
+bundle($bundles);
+ }
+
+ /**
+ * Run the tests for the Laravel framework.
+ *
+ * @return void
+ */
+ public function core()
+ {
+ if ( ! is_dir(path('bundle').'laravel-tests'))
+ {
+ throw new \Exception("The bundle [laravel-tests] has not been installed!");
+ }
+
+ // When testing the Laravel core, we will just stub the path directly
+ // so the test bundle is not required to be registered in the bundle
+ // configuration, as it is kind of a unique bundle.
+ $this->stub(path('bundle').'laravel-tests/cases');
+
+ $path = path('bundle').'laravel-tests/';
+
+ $this->test();
+ }
+
+ /**
+ * Run the tests for a given bundle.
+ *
+ * @param array $bundles
+ * @return void
+ */
+ public function bundle($bundles = array())
+ {
+ if (count($bundles) == 0)
+ {
+ $bundles = Bundle::names();
+ }
+
+ foreach ($bundles as $bundle)
+ {
+ // To run PHPUnit for the application, bundles, and the framework
+ // from one task, we'll dynamically stub PHPUnit.xml files via
+ // the task and point the test suite to the correct directory
+ // based on what was requested.
+ if (is_dir($path = Bundle::path($bundle).'tests'))
+ {
+ $this->stub($path);
+
+ $this->test();
+ }
+ }
+ }
+
+ /**
+ * Run PHPUnit with the temporary XML configuration.
+ *
+ * @return void
+ */
+ protected function test()
+ {
+ // We'll simply fire off PHPUnit with the configuration switch
+ // pointing to our temporary configuration file. This allows
+ // us to flexibly run tests for any setup.
+ $path = path('base').'phpunit.xml';
+
+ passthru('phpunit --configuration '.$path);
+
+ @unlink($path);
+ }
+
+ /**
+ * Write a stub phpunit.xml file to the base directory.
+ *
+ * @param string $directory
+ * @return void
+ */
+ protected function stub($directory)
+ {
+ $path = path('sys').'cli/tasks/test/';
+
+ $stub = File::get($path.'stub.xml');
+
+ // The PHPUnit bootstrap file contains several items that are swapped
+ // at test time. This allows us to point PHPUnit at a few different
+ // locations depending on what the developer wants to test.
+ foreach (array('bootstrap', 'directory') as $item)
+ {
+ $stub = $this->{"swap_{$item}"}($stub, $path, $directory);
+ }
+
+ File::put(path('base').'phpunit.xml', $stub);
+ }
+
+ /**
+ * Swap the bootstrap file in the stub.
+ *
+ * @param string $stub
+ * @param string $path
+ * @param string $directory
+ * @return string
+ */
+ protected function swap_bootstrap($stub, $path, $directory)
+ {
+ return str_replace('{{bootstrap}}', $path.'phpunit.php', $stub);
+ }
+
+ /**
+ * Swap the directory in the stub.
+ *
+ * @param string $stub
+ * @param string $path
+ * @param string $directory
+ * @return string
+ */
+ protected function swap_directory($stub, $path, $directory)
+ {
+ return str_replace('{{directory}}', $directory, $stub);
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/cli/tasks/test/stub.xml b/laravel/cli/tasks/test/stub.xml
new file mode 100644
index 0000000..d8f569f
--- /dev/null
+++ b/laravel/cli/tasks/test/stub.xml
@@ -0,0 +1,9 @@
+
+
+
+ {{directory}}
+
+
+
\ No newline at end of file
diff --git a/laravel/config.php b/laravel/config.php
new file mode 100644
index 0000000..50bd7dc
--- /dev/null
+++ b/laravel/config.php
@@ -0,0 +1,235 @@
+
+ * // Determine if the "session" configuration file exists
+ * $exists = Config::has('session');
+ *
+ * // Determine if the "timezone" option exists in the configuration
+ * $exists = Config::has('application.timezone');
+ *
+ *
+ * @param string $key
+ * @return bool
+ */
+ public static function has($key)
+ {
+ return ! is_null(static::get($key));
+ }
+
+ /**
+ * Get a configuration item.
+ *
+ * If no item is requested, the entire configuration array will be returned.
+ *
+ *
+ * // Get the "session" configuration array
+ * $session = Config::get('session');
+ *
+ * // Get a configuration item from a bundle's configuration file
+ * $name = Config::get('admin::names.first');
+ *
+ * // Get the "timezone" option from the "application" configuration file
+ * $timezone = Config::get('application.timezone');
+ *
+ *
+ * @param string $key
+ * @param mixed $default
+ * @return array
+ */
+ public static function get($key, $default = null)
+ {
+ list($bundle, $file, $item) = static::parse($key);
+
+ if ( ! static::load($bundle, $file)) return value($default);
+
+ $items = static::$items[$bundle][$file];
+
+ // If a specific configuration item was not requested, the key will be null,
+ // meaning we'll to return the entire array of configuration item from the
+ // requested configuration file. Otherwise we can return the item.
+ if (is_null($item))
+ {
+ return $items;
+ }
+ else
+ {
+ return array_get($items, $item, $default);
+ }
+ }
+
+ /**
+ * Set a configuration item's value.
+ *
+ *
+ * // Set the "session" configuration array
+ * Config::set('session', $array);
+ *
+ * // Set a configuration option that belongs by a bundle
+ * Config::set('admin::names.first', 'Taylor');
+ *
+ * // Set the "timezone" option in the "application" configuration file
+ * Config::set('application.timezone', 'UTC');
+ *
+ *
+ * @param string $key
+ * @param mixed $value
+ * @return void
+ */
+ public static function set($key, $value)
+ {
+ list($bundle, $file, $item) = static::parse($key);
+
+ static::load($bundle, $file);
+
+ // If the item is null, it means the developer wishes to set the entire
+ // configuration array to a given value, so we will pass the entire
+ // array for the bundle into the array_set method.
+ if (is_null($item))
+ {
+ array_set(static::$items[$bundle], $file, $value);
+ }
+ else
+ {
+ array_set(static::$items[$bundle][$file], $item, $value);
+ }
+ }
+
+ /**
+ * Parse a key and return its bundle, file, and key segments.
+ *
+ * Configuration items are named using the {bundle}::{file}.{item} convention.
+ *
+ * @param string $key
+ * @return array
+ */
+ protected static function parse($key)
+ {
+ // First, we'll check the keyed cache of configuration items, as this will
+ // be the fastest method of retrieving the configuration option. After an
+ // item is parsed, it is always stored in the cache by its key.
+ if (array_key_exists($key, static::$cache))
+ {
+ return static::$cache[$key];
+ }
+
+ $bundle = Bundle::name($key);
+
+ $segments = explode('.', Bundle::element($key));
+
+ // If there are not at least two segments in the array, it means that the
+ // developer is requesting the entire configuration array to be returned.
+ // If that is the case, we'll make the item field "null".
+ if (count($segments) >= 2)
+ {
+ $parsed = array($bundle, $segments[0], implode('.', array_slice($segments, 1)));
+ }
+ else
+ {
+ $parsed = array($bundle, $segments[0], null);
+ }
+
+ return static::$cache[$key] = $parsed;
+ }
+
+ /**
+ * Load all of the configuration items from a configuration file.
+ *
+ * @param string $bundle
+ * @param string $file
+ * @return bool
+ */
+ public static function load($bundle, $file)
+ {
+ if (isset(static::$items[$bundle][$file])) return true;
+
+ // We allow a "config.loader" event to be registered which is responsible for
+ // returning an array representing the configuration for the bundle and file
+ // requested. This allows many types of config "drivers".
+ $config = Event::first(static::loader, func_get_args());
+
+ // If configuration items were actually found for the bundle and file we
+ // will add them to the configuration array and return true, otherwise
+ // we will return false indicating the file was not found.
+ if (count($config) > 0)
+ {
+ static::$items[$bundle][$file] = $config;
+ }
+
+ return isset(static::$items[$bundle][$file]);
+ }
+
+ /**
+ * Load the configuration items from a configuration file.
+ *
+ * @param string $bundle
+ * @param string $file
+ * @return array
+ */
+ public static function file($bundle, $file)
+ {
+ $config = array();
+
+ // Configuration files cascade. Typically, the bundle configuration array is
+ // loaded first, followed by the environment array, providing the convenient
+ // cascading of configuration options across environments.
+ foreach (static::paths($bundle) as $directory)
+ {
+ if ($directory !== '' and file_exists($path = $directory.$file.EXT))
+ {
+ $config = array_merge($config, require $path);
+ }
+ }
+
+ return $config;
+ }
+
+ /**
+ * Get the array of configuration paths that should be searched for a bundle.
+ *
+ * @param string $bundle
+ * @return array
+ */
+ protected static function paths($bundle)
+ {
+ $paths[] = Bundle::path($bundle).'config/';
+
+ // Configuration files can be made specific for a given environment. If an
+ // environment has been set, we will merge the environment configuration
+ // in last, so that it overrides all other options.
+ if ( ! is_null(Request::env()))
+ {
+ $paths[] = $paths[count($paths) - 1].Request::env().'/';
+ }
+
+ return $paths;
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/cookie.php b/laravel/cookie.php
new file mode 100644
index 0000000..1f79a69
--- /dev/null
+++ b/laravel/cookie.php
@@ -0,0 +1,123 @@
+
+ * // Get the value of the "favorite" cookie
+ * $favorite = Cookie::get('favorite');
+ *
+ * // Get the value of a cookie or return a default value
+ * $favorite = Cookie::get('framework', 'Laravel');
+ *
+ *
+ * @param string $name
+ * @param mixed $default
+ * @return string
+ */
+ public static function get($name, $default = null)
+ {
+ if (isset(static::$jar[$name])) return static::$jar[$name]['value'];
+
+ return array_get(Request::foundation()->cookies->all(), $name, $default);
+ }
+
+ /**
+ * Set the value of a cookie.
+ *
+ *
+ * // Set the value of the "favorite" cookie
+ * Cookie::put('favorite', 'Laravel');
+ *
+ * // Set the value of the "favorite" cookie for twenty minutes
+ * Cookie::put('favorite', 'Laravel', 20);
+ *
+ *
+ * @param string $name
+ * @param string $value
+ * @param int $expiration
+ * @param string $path
+ * @param string $domain
+ * @param bool $secure
+ * @return void
+ */
+ public static function put($name, $value, $expiration = 0, $path = '/', $domain = null, $secure = false)
+ {
+ if ($expiration !== 0)
+ {
+ $expiration = time() + ($expiration * 60);
+ }
+
+ // If the secure option is set to true, yet the request is not over HTTPS
+ // we'll throw an exception to let the developer know that they are
+ // attempting to send a secure cookie over the unsecure HTTP.
+ if ($secure and ! Request::secure())
+ {
+ throw new \Exception("Attempting to set secure cookie over HTTP.");
+ }
+
+ static::$jar[$name] = compact('name', 'value', 'expiration', 'path', 'domain', 'secure');
+ }
+
+ /**
+ * Set a "permanent" cookie. The cookie will last for one year.
+ *
+ *
+ * // Set a cookie that should last one year
+ * Cookie::forever('favorite', 'Blue');
+ *
+ *
+ * @param string $name
+ * @param string $value
+ * @param string $path
+ * @param string $domain
+ * @param bool $secure
+ * @return bool
+ */
+ public static function forever($name, $value, $path = '/', $domain = null, $secure = false)
+ {
+ return static::put($name, $value, static::forever, $path, $domain, $secure);
+ }
+
+ /**
+ * Delete a cookie.
+ *
+ * @param string $name
+ * @param string $path
+ * @param string $domain
+ * @param bool $secure
+ * @return bool
+ */
+ public static function forget($name, $path = '/', $domain = null, $secure = false)
+ {
+ return static::put($name, null, -2000, $path, $domain, $secure);
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/core.php b/laravel/core.php
new file mode 100644
index 0000000..a38bf9d
--- /dev/null
+++ b/laravel/core.php
@@ -0,0 +1,229 @@
+ path('sys')));
+
+/*
+|--------------------------------------------------------------------------
+| Register Eloquent Mappings
+|--------------------------------------------------------------------------
+|
+| A few of the Eloquent ORM classes use a non PSR-0 naming standard so
+| we will just map them with hard-coded paths here since PSR-0 uses
+| underscores as directory hierarchy indicators.
+|
+*/
+
+Autoloader::map(array(
+ 'Laravel\\Database\\Eloquent\\Relationships\\Belongs_To'
+ => path('sys').'database/eloquent/relationships/belongs_to'.EXT,
+ 'Laravel\\Database\\Eloquent\\Relationships\\Has_Many'
+ => path('sys').'database/eloquent/relationships/has_many'.EXT,
+ 'Laravel\\Database\\Eloquent\\Relationships\\Has_Many_And_Belongs_To'
+ => path('sys').'database/eloquent/relationships/has_many_and_belongs_to'.EXT,
+ 'Laravel\\Database\\Eloquent\\Relationships\\Has_One'
+ => path('sys').'database/eloquent/relationships/has_one'.EXT,
+ 'Laravel\\Database\\Eloquent\\Relationships\\Has_One_Or_Many'
+ => path('sys').'database/eloquent/relationships/has_one_or_many'.EXT,
+));
+
+/*
+|--------------------------------------------------------------------------
+| Register The Symfony Components
+|--------------------------------------------------------------------------
+|
+| Laravel makes use of the Symfony components where the situation is
+| applicable and it is possible to do so. This allows us to focus
+| on the parts of the framework that are unique and not re-do
+| plumbing code that others have written.
+|
+*/
+
+Autoloader::namespaces(array(
+ 'Symfony\Component\Console'
+ => path('sys').'vendor/Symfony/Component/Console',
+ 'Symfony\Component\HttpFoundation'
+ => path('sys').'vendor/Symfony/Component/HttpFoundation',
+));
+
+/*
+|--------------------------------------------------------------------------
+| Magic Quotes Strip Slashes
+|--------------------------------------------------------------------------
+|
+| Even though "Magic Quotes" are deprecated in PHP 5.3.x, they may still
+| be enabled on the server. To account for this, we will strip slashes
+| on all input arrays if magic quotes are enabled for the server.
+|
+*/
+
+if (magic_quotes())
+{
+ $magics = array(&$_GET, &$_POST, &$_COOKIE, &$_REQUEST);
+
+ foreach ($magics as &$magic)
+ {
+ $magic = array_strip_slashes($magic);
+ }
+}
+
+/*
+|--------------------------------------------------------------------------
+| Create The HttpFoundation Request
+|--------------------------------------------------------------------------
+|
+| Laravel uses the HttpFoundation Symfony component to handle the request
+| and response functionality for the framework. This allows us to not
+| worry about that boilerplate code and focus on what matters.
+|
+*/
+
+use Symfony\Component\HttpFoundation\LaravelRequest as RequestFoundation;
+
+Request::$foundation = RequestFoundation::createFromGlobals();
+
+/*
+|--------------------------------------------------------------------------
+| Determine The Application Environment
+|--------------------------------------------------------------------------
+|
+| Next we're ready to determine the application environment. This may be
+| set either via the command line options or via the mapping of URIs to
+| environments that lives in the "paths.php" file for the application
+| and is parsed. When determining the CLI environment, the "--env"
+| CLI option overrides the mapping in "paths.php".
+|
+*/
+
+if (Request::cli())
+{
+ $environment = get_cli_option('env');
+
+ if ( ! isset($environment))
+ {
+ $environment = Request::detect_env($environments, gethostname());
+ }
+}
+else
+{
+ $root = Request::foundation()->getRootUrl();
+
+ $environment = Request::detect_env($environments, $root);
+}
+
+/*
+|--------------------------------------------------------------------------
+| Set The Application Environment
+|--------------------------------------------------------------------------
+|
+| Once we have determined the application environment, we will set it on
+| the global server array of the HttpFoundation request. This makes it
+| available throughout the application, thought it is mainly only
+| used to determine which configuration files to merge in.
+|
+*/
+
+if (isset($environment))
+{
+ Request::set_env($environment);
+}
+
+/*
+|--------------------------------------------------------------------------
+| Set The CLI Options Array
+|--------------------------------------------------------------------------
+|
+| If the current request is from the Artisan command-line interface, we
+| will parse the command line arguments and options and set them the
+| array of options in the $_SERVER global array for convenience.
+|
+*/
+
+if (defined('STDIN'))
+{
+ $console = CLI\Command::options($_SERVER['argv']);
+
+ list($arguments, $options) = $console;
+
+ $options = array_change_key_case($options, CASE_UPPER);
+
+ $_SERVER['CLI'] = $options;
+}
+
+/*
+|--------------------------------------------------------------------------
+| Register The Laravel Bundles
+|--------------------------------------------------------------------------
+|
+| Finally we will register all of the bundles that have been defined for
+| the application. None of them will be started yet, but will be setup
+| so that they may be started by the developer at any time.
+|
+*/
+
+$bundles = require path('app').'bundles'.EXT;
+
+foreach ($bundles as $bundle => $config)
+{
+ Bundle::register($bundle, $config);
+}
\ No newline at end of file
diff --git a/laravel/crypter.php b/laravel/crypter.php
new file mode 100644
index 0000000..18bac81
--- /dev/null
+++ b/laravel/crypter.php
@@ -0,0 +1,166 @@
+
+ * // Get the default database connection for the application
+ * $connection = DB::connection();
+ *
+ * // Get a specific connection by passing the connection name
+ * $connection = DB::connection('mysql');
+ *
+ *
+ * @param string $connection
+ * @return Database\Connection
+ */
+ public static function connection($connection = null)
+ {
+ if (is_null($connection)) $connection = Config::get('database.default');
+
+ if ( ! isset(static::$connections[$connection]))
+ {
+ $config = Config::get("database.connections.{$connection}");
+
+ if (is_null($config))
+ {
+ throw new \Exception("Database connection is not defined for [$connection].");
+ }
+
+ static::$connections[$connection] = new Connection(static::connect($config), $config);
+ }
+
+ return static::$connections[$connection];
+ }
+
+ /**
+ * Get a PDO database connection for a given database configuration.
+ *
+ * @param array $config
+ * @return PDO
+ */
+ protected static function connect($config)
+ {
+ return static::connector($config['driver'])->connect($config);
+ }
+
+ /**
+ * Create a new database connector instance.
+ *
+ * @param string $driver
+ * @return Database\Connectors\Connector
+ */
+ protected static function connector($driver)
+ {
+ if (isset(static::$registrar[$driver]))
+ {
+ $resolver = static::$registrar[$driver]['connector'];
+
+ return $resolver();
+ }
+
+ switch ($driver)
+ {
+ case 'sqlite':
+ return new Database\Connectors\SQLite;
+
+ case 'mysql':
+ return new Database\Connectors\MySQL;
+
+ case 'pgsql':
+ return new Database\Connectors\Postgres;
+
+ case 'sqlsrv':
+ return new Database\Connectors\SQLServer;
+
+ default:
+ throw new \Exception("Database driver [$driver] is not supported.");
+ }
+ }
+
+ /**
+ * Begin a fluent query against a table.
+ *
+ * @param string $table
+ * @param string $connection
+ * @return Database\Query
+ */
+ public static function table($table, $connection = null)
+ {
+ return static::connection($connection)->table($table);
+ }
+
+ /**
+ * Create a new database expression instance.
+ *
+ * Database expressions are used to inject raw SQL into a fluent query.
+ *
+ * @param string $value
+ * @return Expression
+ */
+ public static function raw($value)
+ {
+ return new Expression($value);
+ }
+
+ /**
+ * Get the profiling data for all queries.
+ *
+ * @return array
+ */
+ public static function profile()
+ {
+ return Database\Connection::$queries;
+ }
+
+ /**
+ * Get the last query that was executed.
+ *
+ * Returns false if no queries have been executed yet.
+ *
+ * @return string
+ */
+ public static function last_query()
+ {
+ return end(Database\Connection::$queries);
+ }
+
+ /**
+ * Register a database connector and grammars.
+ *
+ * @param string $name
+ * @param Closure $connector
+ * @param Closure $query
+ * @param Closure $schema
+ * @return void
+ */
+ public static function extend($name, Closure $connector, $query = null, $schema = null)
+ {
+ if (is_null($query)) $query = '\Laravel\Database\Query\Grammars\Grammar';
+
+ static::$registrar[$name] = compact('connector', 'query', 'schema');
+ }
+
+ /**
+ * Magic Method for calling methods on the default database connection.
+ *
+ *
+ * // Get the driver name for the default database connection
+ * $driver = DB::driver();
+ *
+ * // Execute a fluent query on the default database connection
+ * $users = DB::table('users')->get();
+ *
+ */
+ public static function __callStatic($method, $parameters)
+ {
+ return call_user_func_array(array(static::connection(), $method), $parameters);
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/connection.php b/laravel/database/connection.php
new file mode 100644
index 0000000..2619773
--- /dev/null
+++ b/laravel/database/connection.php
@@ -0,0 +1,336 @@
+pdo = $pdo;
+ $this->config = $config;
+ }
+
+ /**
+ * Begin a fluent query against a table.
+ *
+ *
+ * // Start a fluent query against the "users" table
+ * $query = DB::connection()->table('users');
+ *
+ * // Start a fluent query against the "users" table and get all the users
+ * $users = DB::connection()->table('users')->get();
+ *
+ *
+ * @param string $table
+ * @return Query
+ */
+ public function table($table)
+ {
+ return new Query($this, $this->grammar(), $table);
+ }
+
+ /**
+ * Create a new query grammar for the connection.
+ *
+ * @return Query\Grammars\Grammar
+ */
+ protected function grammar()
+ {
+ if (isset($this->grammar)) return $this->grammar;
+
+ if (isset(\Laravel\Database::$registrar[$this->driver()]))
+ {
+ \Laravel\Database::$registrar[$this->driver()]['query']();
+ }
+
+ switch ($this->driver())
+ {
+ case 'mysql':
+ return $this->grammar = new Query\Grammars\MySQL($this);
+
+ case 'sqlite':
+ return $this->grammar = new Query\Grammars\SQLite($this);
+
+ case 'sqlsrv':
+ return $this->grammar = new Query\Grammars\SQLServer($this);
+
+ case 'pgsql':
+ return $this->grammar = new Query\Grammars\Postgres($this);
+
+ default:
+ return $this->grammar = new Query\Grammars\Grammar($this);
+ }
+ }
+
+ /**
+ * Execute a callback wrapped in a database transaction.
+ *
+ * @param callback $callback
+ * @return void
+ */
+ public function transaction($callback)
+ {
+ $this->pdo->beginTransaction();
+
+ // After beginning the database transaction, we will call the callback
+ // so that it can do its database work. If an exception occurs we'll
+ // rollback the transaction and re-throw back to the developer.
+ try
+ {
+ call_user_func($callback);
+ }
+ catch (\Exception $e)
+ {
+ $this->pdo->rollBack();
+
+ throw $e;
+ }
+
+ $this->pdo->commit();
+ }
+
+ /**
+ * Execute a SQL query against the connection and return a single column result.
+ *
+ *
+ * // Get the total number of rows on a table
+ * $count = DB::connection()->only('select count(*) from users');
+ *
+ * // Get the sum of payment amounts from a table
+ * $sum = DB::connection()->only('select sum(amount) from payments')
+ *
+ *
+ * @param string $sql
+ * @param array $bindings
+ * @return mixed
+ */
+ public function only($sql, $bindings = array())
+ {
+ $results = (array) $this->first($sql, $bindings);
+
+ return reset($results);
+ }
+
+ /**
+ * Execute a SQL query against the connection and return the first result.
+ *
+ *
+ * // Execute a query against the database connection
+ * $user = DB::connection()->first('select * from users');
+ *
+ * // Execute a query with bound parameters
+ * $user = DB::connection()->first('select * from users where id = ?', array($id));
+ *
+ *
+ * @param string $sql
+ * @param array $bindings
+ * @return object
+ */
+ public function first($sql, $bindings = array())
+ {
+ if (count($results = $this->query($sql, $bindings)) > 0)
+ {
+ return $results[0];
+ }
+ }
+
+ /**
+ * Execute a SQL query and return an array of StdClass objects.
+ *
+ * @param string $sql
+ * @param array $bindings
+ * @return array
+ */
+ public function query($sql, $bindings = array())
+ {
+ $sql = trim($sql);
+
+ list($statement, $result) = $this->execute($sql, $bindings);
+
+ // The result we return depends on the type of query executed against the
+ // database. On SELECT clauses, we will return the result set, for update
+ // and deletes we will return the affected row count.
+ if (stripos($sql, 'select') === 0)
+ {
+ return $this->fetch($statement, Config::get('database.fetch'));
+ }
+ elseif (stripos($sql, 'update') === 0 or stripos($sql, 'delete') === 0)
+ {
+ return $statement->rowCount();
+ }
+ // For insert statements that use the "returning" clause, which is allowed
+ // by database systems such as Postgres, we need to actually return the
+ // real query result so the consumer can get the ID.
+ elseif (stripos($sql, 'insert') === 0 and stripos($sql, 'returning') !== false)
+ {
+ return $this->fetch($statement, Config::get('database.fetch'));
+ }
+ else
+ {
+ return $result;
+ }
+ }
+
+ /**
+ * Execute a SQL query against the connection.
+ *
+ * The PDO statement and boolean result will be return in an array.
+ *
+ * @param string $sql
+ * @param array $bindings
+ * @return array
+ */
+ protected function execute($sql, $bindings = array())
+ {
+ $bindings = (array) $bindings;
+
+ // Since expressions are injected into the query as strings, we need to
+ // remove them from the array of bindings. After we have removed them,
+ // we'll reset the array so there are not gaps within the keys.
+ $bindings = array_filter($bindings, function($binding)
+ {
+ return ! $binding instanceof Expression;
+ });
+
+ $bindings = array_values($bindings);
+
+ $sql = $this->grammar()->shortcut($sql, $bindings);
+
+ // Next we need to translate all DateTime bindings to their date-time
+ // strings that are compatible with the database. Each grammar may
+ // define it's own date-time format according to its needs.
+ $datetime = $this->grammar()->datetime;
+
+ for ($i = 0; $i < count($bindings); $i++)
+ {
+ if ($bindings[$i] instanceof \DateTime)
+ {
+ $bindings[$i] = $bindings[$i]->format($datetime);
+ }
+ }
+
+ // Each database operation is wrapped in a try / catch so we can wrap
+ // any database exceptions in our custom exception class, which will
+ // set the message to include the SQL and query bindings.
+ try
+ {
+ $statement = $this->pdo->prepare($sql);
+
+ $start = microtime(true);
+
+ $result = $statement->execute($bindings);
+ }
+ // If an exception occurs, we'll pass it into our custom exception
+ // and set the message to include the SQL and query bindings so
+ // debugging is much easier on the developer.
+ catch (\Exception $exception)
+ {
+ $exception = new Exception($sql, $bindings, $exception);
+
+ throw $exception;
+ }
+
+ // Once we have execute the query, we log the SQL, bindings, and
+ // execution time in a static array that is accessed by all of
+ // the connections actively being used by the application.
+ if (Config::get('database.profile'))
+ {
+ $this->log($sql, $bindings, $start);
+ }
+
+ return array($statement, $result);
+ }
+
+ /**
+ * Fetch all of the rows for a given statement.
+ *
+ * @param PDOStatement $statement
+ * @param int $style
+ * @return array
+ */
+ protected function fetch($statement, $style)
+ {
+ // If the fetch style is "class", we'll hydrate an array of PHP
+ // stdClass objects as generic containers for the query rows,
+ // otherwise we'll just use the fetch styel value.
+ if ($style === PDO::FETCH_CLASS)
+ {
+ return $statement->fetchAll(PDO::FETCH_CLASS, 'stdClass');
+ }
+ else
+ {
+ return $statement->fetchAll($style);
+ }
+ }
+
+ /**
+ * Log the query and fire the core query event.
+ *
+ * @param string $sql
+ * @param array $bindings
+ * @param int $start
+ * @return void
+ */
+ protected function log($sql, $bindings, $start)
+ {
+ $time = number_format((microtime(true) - $start) * 1000, 2);
+
+ Event::fire('laravel.query', array($sql, $bindings, $time));
+
+ static::$queries[] = compact('sql', 'bindings', 'time');
+ }
+
+ /**
+ * Get the driver name for the database connection.
+ *
+ * @return string
+ */
+ public function driver()
+ {
+ return $this->config['driver'];
+ }
+
+ /**
+ * Magic Method for dynamically beginning queries on database tables.
+ */
+ public function __call($method, $parameters)
+ {
+ return $this->table($method);
+ }
+
+}
diff --git a/laravel/database/connectors/connector.php b/laravel/database/connectors/connector.php
new file mode 100644
index 0000000..0106558
--- /dev/null
+++ b/laravel/database/connectors/connector.php
@@ -0,0 +1,41 @@
+ PDO::CASE_LOWER,
+ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
+ PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
+ PDO::ATTR_STRINGIFY_FETCHES => false,
+ PDO::ATTR_EMULATE_PREPARES => false,
+ );
+
+ /**
+ * Establish a PDO database connection.
+ *
+ * @param array $config
+ * @return PDO
+ */
+ abstract public function connect($config);
+
+ /**
+ * Get the PDO connection options for the configuration.
+ *
+ * Developer specified options will override the default connection options.
+ *
+ * @param array $config
+ * @return array
+ */
+ protected function options($config)
+ {
+ $options = (isset($config['options'])) ? $config['options'] : array();
+
+ return $this->options + $options;
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/connectors/mysql.php b/laravel/database/connectors/mysql.php
new file mode 100644
index 0000000..0ea5eba
--- /dev/null
+++ b/laravel/database/connectors/mysql.php
@@ -0,0 +1,46 @@
+options($config));
+
+ // If a character set has been specified, we'll execute a query against
+ // the database to set the correct character set. By default, this is
+ // set to UTF-8 which should be fine for most scenarios.
+ if (isset($config['charset']))
+ {
+ $connection->prepare("SET NAMES '{$config['charset']}'")->execute();
+ }
+
+ return $connection;
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/connectors/postgres.php b/laravel/database/connectors/postgres.php
new file mode 100644
index 0000000..3721f36
--- /dev/null
+++ b/laravel/database/connectors/postgres.php
@@ -0,0 +1,50 @@
+ PDO::CASE_LOWER,
+ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
+ PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
+ PDO::ATTR_STRINGIFY_FETCHES => false,
+ );
+
+ /**
+ * Establish a PDO database connection.
+ *
+ * @param array $config
+ * @return PDO
+ */
+ public function connect($config)
+ {
+ extract($config);
+
+ $dsn = "pgsql:host={$host};dbname={$database}";
+
+ // The developer has the freedom of specifying a port for the PostgresSQL
+ // database or the default port (5432) will be used by PDO to create the
+ // connection to the database for the developer.
+ if (isset($config['port']))
+ {
+ $dsn .= ";port={$config['port']}";
+ }
+
+ $connection = new PDO($dsn, $username, $password, $this->options($config));
+
+ // If a character set has been specified, we'll execute a query against
+ // the database to set the correct character set. By default, this is
+ // set to UTF-8 which should be fine for most scenarios.
+ if (isset($config['charset']))
+ {
+ $connection->prepare("SET NAMES '{$config['charset']}'")->execute();
+ }
+
+ return $connection;
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/connectors/sqlite.php b/laravel/database/connectors/sqlite.php
new file mode 100644
index 0000000..1e2fc7e
--- /dev/null
+++ b/laravel/database/connectors/sqlite.php
@@ -0,0 +1,28 @@
+options($config);
+
+ // SQLite provides supported for "in-memory" databases, which exist only for
+ // lifetime of the request. Any given in-memory database may only have one
+ // PDO connection open to it at a time. These are mainly for tests.
+ if ($config['database'] == ':memory:')
+ {
+ return new PDO('sqlite::memory:', null, null, $options);
+ }
+
+ $path = path('storage').'database'.DS.$config['database'].'.sqlite';
+
+ return new PDO('sqlite:'.$path, null, null, $options);
+ }
+
+}
diff --git a/laravel/database/connectors/sqlserver.php b/laravel/database/connectors/sqlserver.php
new file mode 100644
index 0000000..29c6929
--- /dev/null
+++ b/laravel/database/connectors/sqlserver.php
@@ -0,0 +1,37 @@
+ PDO::CASE_LOWER,
+ PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION,
+ PDO::ATTR_ORACLE_NULLS => PDO::NULL_NATURAL,
+ PDO::ATTR_STRINGIFY_FETCHES => false,
+ );
+
+ /**
+ * Establish a PDO database connection.
+ *
+ * @param array $config
+ * @return PDO
+ */
+ public function connect($config)
+ {
+ extract($config);
+
+ // Format the SQL Server connection string. This connection string format can
+ // also be used to connect to Azure SQL Server databases. The port is defined
+ // directly after the server name, so we'll create that first.
+ $port = (isset($port)) ? ','.$port : '';
+
+ $dsn = "sqlsrv:Server={$host}{$port};Database={$database}";
+
+ return new PDO($dsn, $username, $password, $this->options($config));
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/eloquent/model.php b/laravel/database/eloquent/model.php
new file mode 100644
index 0000000..7e94686
--- /dev/null
+++ b/laravel/database/eloquent/model.php
@@ -0,0 +1,804 @@
+exists = $exists;
+
+ $this->fill($attributes);
+ }
+
+ /**
+ * Hydrate the model with an array of attributes.
+ *
+ * @param array $attributes
+ * @param bool $raw
+ * @return Model
+ */
+ public function fill(array $attributes, $raw = false)
+ {
+ foreach ($attributes as $key => $value)
+ {
+ // If the "raw" flag is set, it means that we'll just load every value from
+ // the array directly into the attributes, without any accessibility or
+ // mutators being accounted for. What you pass in is what you get.
+ if ($raw)
+ {
+ $this->set_attribute($key, $value);
+
+ continue;
+ }
+
+ // If the "accessible" property is an array, the developer is limiting the
+ // attributes that may be mass assigned, and we need to verify that the
+ // current attribute is included in that list of allowed attributes.
+ if (is_array(static::$accessible))
+ {
+ if (in_array($key, static::$accessible))
+ {
+ $this->$key = $value;
+ }
+ }
+
+ // If the "accessible" property is not an array, no attributes have been
+ // white-listed and we are free to set the value of the attribute to
+ // the value that has been passed into the method without a check.
+ else
+ {
+ $this->$key = $value;
+ }
+ }
+
+ // If the original attribute values have not been set, we will set
+ // them to the values passed to this method allowing us to easily
+ // check if the model has changed since hydration.
+ if (count($this->original) === 0)
+ {
+ $this->original = $this->attributes;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Fill the model with the contents of the array.
+ *
+ * No mutators or accessibility checks will be accounted for.
+ *
+ * @param array $attributes
+ * @return Model
+ */
+ public function fill_raw(array $attributes)
+ {
+ return $this->fill($attributes, true);
+ }
+
+ /**
+ * Set the accessible attributes for the given model.
+ *
+ * @param array $attributes
+ * @return void
+ */
+ public static function accessible($attributes = null)
+ {
+ if (is_null($attributes)) return static::$accessible;
+
+ static::$accessible = $attributes;
+ }
+
+ /**
+ * Create a new model and store it in the database.
+ *
+ * If save is successful, the model will be returned, otherwise false.
+ *
+ * @param array $attributes
+ * @return Model|false
+ */
+ public static function create($attributes)
+ {
+ $model = new static($attributes);
+
+ $success = $model->save();
+
+ return ($success) ? $model : false;
+ }
+
+ /**
+ * Update a model instance in the database.
+ *
+ * @param mixed $id
+ * @param array $attributes
+ * @return int
+ */
+ public static function update($id, $attributes)
+ {
+ $model = new static(array(), true);
+
+ if (static::$timestamps) $attributes['updated_at'] = new \DateTime;
+
+ return $model->query()->where($model->key(), '=', $id)->update($attributes);
+ }
+
+ /**
+ * Find a model by its primary key.
+ *
+ * @param string $id
+ * @param array $columns
+ * @return Model
+ */
+ public function _find($id, $columns = array('*'))
+ {
+ return $this->query()->where(static::$key, '=', $id)->first($columns);
+ }
+
+ /**
+ * Get all of the models in the database.
+ *
+ * @return array
+ */
+ public static function all()
+ {
+ return with(new static)->query()->get();
+ }
+
+ /**
+ * The relationships that should be eagerly loaded by the query.
+ *
+ * @param array $includes
+ * @return Model
+ */
+ public function _with($includes)
+ {
+ $this->includes = (array) $includes;
+
+ return $this;
+ }
+
+ /**
+ * Get the query for a one-to-one association.
+ *
+ * @param string $model
+ * @param string $foreign
+ * @return Relationship
+ */
+ public function has_one($model, $foreign = null)
+ {
+ return $this->has_one_or_many(__FUNCTION__, $model, $foreign);
+ }
+
+ /**
+ * Get the query for a one-to-many association.
+ *
+ * @param string $model
+ * @param string $foreign
+ * @return Relationship
+ */
+ public function has_many($model, $foreign = null)
+ {
+ return $this->has_one_or_many(__FUNCTION__, $model, $foreign);
+ }
+
+ /**
+ * Get the query for a one-to-one / many association.
+ *
+ * @param string $type
+ * @param string $model
+ * @param string $foreign
+ * @return Relationship
+ */
+ protected function has_one_or_many($type, $model, $foreign)
+ {
+ if ($type == 'has_one')
+ {
+ return new Relationships\Has_One($this, $model, $foreign);
+ }
+ else
+ {
+ return new Relationships\Has_Many($this, $model, $foreign);
+ }
+ }
+
+ /**
+ * Get the query for a one-to-one (inverse) relationship.
+ *
+ * @param string $model
+ * @param string $foreign
+ * @return Relationship
+ */
+ public function belongs_to($model, $foreign = null)
+ {
+ // If no foreign key is specified for the relationship, we will assume that the
+ // name of the calling function matches the foreign key. For example, if the
+ // calling function is "manager", we'll assume the key is "manager_id".
+ if (is_null($foreign))
+ {
+ list(, $caller) = debug_backtrace(false);
+
+ $foreign = "{$caller['function']}_id";
+ }
+
+ return new Relationships\Belongs_To($this, $model, $foreign);
+ }
+
+ /**
+ * Get the query for a many-to-many relationship.
+ *
+ * @param string $model
+ * @param string $table
+ * @param string $foreign
+ * @param string $other
+ * @return Relationship
+ */
+ public function has_many_and_belongs_to($model, $table = null, $foreign = null, $other = null)
+ {
+ return new Has_Many_And_Belongs_To($this, $model, $table, $foreign, $other);
+ }
+
+
+ /**
+ * Updates the created_at timestamp to current time.
+ *
+ * @return bool
+ */
+ public function touch()
+ {
+ $this->timestamp();
+ return $this->save();
+ }
+
+ /**
+ * Save the model and all of its relations to the database.
+ *
+ * @return bool
+ */
+ public function push()
+ {
+ $this->save();
+
+ // To sync all of the relationships to the database, we will simply spin through
+ // the relationships, calling the "push" method on each of the models in that
+ // given relationship, this should ensure that each model is saved.
+ foreach ($this->relationships as $name => $models)
+ {
+ if ( ! is_array($models))
+ {
+ $models = array($models);
+ }
+
+ foreach ($models as $model)
+ {
+ $model->push();
+ }
+ }
+ }
+
+ /**
+ * Save the model instance to the database.
+ *
+ * @return bool
+ */
+ public function save()
+ {
+ if ( ! $this->dirty()) return true;
+
+ if (static::$timestamps)
+ {
+ $this->timestamp();
+ }
+
+ $this->fire_event('saving');
+
+ // If the model exists, we only need to update it in the database, and the update
+ // will be considered successful if there is one affected row returned from the
+ // fluent query instance. We'll set the where condition automatically.
+ if ($this->exists)
+ {
+ $query = $this->query()->where(static::$key, '=', $this->get_key());
+
+ $result = $query->update($this->get_dirty()) === 1;
+
+ if ($result) $this->fire_event('updated');
+ }
+
+ // If the model does not exist, we will insert the record and retrieve the last
+ // insert ID that is associated with the model. If the ID returned is numeric
+ // then we can consider the insert successful.
+ else
+ {
+ $id = $this->query()->insert_get_id($this->attributes, $this->key());
+
+ $this->set_key($id);
+
+ $this->exists = $result = is_numeric($this->get_key());
+
+ if ($result) $this->fire_event('created');
+ }
+
+ // After the model has been "saved", we will set the original attributes to
+ // match the current attributes so the model will not be viewed as being
+ // dirty and subsequent calls won't hit the database.
+ $this->original = $this->attributes;
+
+ if ($result)
+ {
+ $this->fire_event('saved');
+ }
+
+ return $result;
+ }
+
+ /**
+ * Delete the model from the database.
+ *
+ * @return int
+ */
+ public function delete()
+ {
+ if ($this->exists)
+ {
+ $this->fire_event('deleting');
+
+ $result = $this->query()->where(static::$key, '=', $this->get_key())->delete();
+
+ $this->fire_event('deleted');
+
+ return $result;
+ }
+ }
+
+ /**
+ * Set the update and creation timestamps on the model.
+ *
+ * @return void
+ */
+ protected function timestamp()
+ {
+ $this->updated_at = new \DateTime;
+
+ if ( ! $this->exists) $this->created_at = $this->updated_at;
+ }
+
+ /**
+ * Get a new fluent query builder instance for the model.
+ *
+ * @return Query
+ */
+ protected function query()
+ {
+ return new Query($this);
+ }
+
+ /**
+ * Sync the original attributes with the current attributes.
+ *
+ * @return bool
+ */
+ final public function sync()
+ {
+ $this->original = $this->attributes;
+
+ return true;
+ }
+
+ /**
+ * Determine if a given attribute has changed from its original state.
+ *
+ * @param string $attribute
+ * @return bool
+ */
+ public function changed($attribute)
+ {
+ return array_get($this->attributes, $attribute) !== array_get($this->original, $attribute);
+ }
+
+ /**
+ * Determine if the model has been changed from its original state.
+ *
+ * Models that haven't been persisted to storage are always considered dirty.
+ *
+ * @return bool
+ */
+ public function dirty()
+ {
+ return ! $this->exists or count($this->get_dirty()) > 0;
+ }
+
+ /**
+ * Get the name of the table associated with the model.
+ *
+ * @return string
+ */
+ public function table()
+ {
+ return static::$table ?: strtolower(Str::plural(class_basename($this)));
+ }
+
+ /**
+ * Get the dirty attributes for the model.
+ *
+ * @return array
+ */
+ public function get_dirty()
+ {
+ $dirty = array();
+
+ foreach ($this->attributes as $key => $value)
+ {
+ if ( ! isset($this->original[$key]) or $value !== $this->original[$key])
+ {
+ $dirty[$key] = $value;
+ }
+ }
+
+ return $dirty;
+ }
+
+ /**
+ * Get the value of the primary key for the model.
+ *
+ * @return int
+ */
+ public function get_key()
+ {
+ return $this->get_attribute(static::$key);
+ }
+
+ /**
+ * Set the value of the primary key for the model.
+ *
+ * @param int $value
+ * @return void
+ */
+ public function set_key($value)
+ {
+ return $this->set_attribute(static::$key, $value);
+ }
+
+ /**
+ * Get a given attribute from the model.
+ *
+ * @param string $key
+ */
+ public function get_attribute($key)
+ {
+ return array_get($this->attributes, $key);
+ }
+
+ /**
+ * Set an attribute's value on the model.
+ *
+ * @param string $key
+ * @param mixed $value
+ * @return void
+ */
+ public function set_attribute($key, $value)
+ {
+ $this->attributes[$key] = $value;
+ }
+
+ /**
+ * Remove an attribute from the model.
+ *
+ * @param string $key
+ */
+ final public function purge($key)
+ {
+ unset($this->original[$key]);
+
+ unset($this->attributes[$key]);
+ }
+
+ /**
+ * Get the model attributes and relationships in array form.
+ *
+ * @return array
+ */
+ public function to_array()
+ {
+ $attributes = array();
+
+ // First we need to gather all of the regular attributes. If the attribute
+ // exists in the array of "hidden" attributes, it will not be added to
+ // the array so we can easily exclude things like passwords, etc.
+ foreach (array_keys($this->attributes) as $attribute)
+ {
+ if ( ! in_array($attribute, static::$hidden))
+ {
+ $attributes[$attribute] = $this->$attribute;
+ }
+ }
+
+ foreach ($this->relationships as $name => $models)
+ {
+ // If the relationship is not a "to-many" relationship, we can just
+ // to_array the related model and add it as an attribute to the
+ // array of existing regular attributes we gathered.
+ if ($models instanceof Model)
+ {
+ $attributes[$name] = $models->to_array();
+ }
+
+ // If the relationship is a "to-many" relationship we need to spin
+ // through each of the related models and add each one with the
+ // to_array method, keying them both by name and ID.
+ elseif (is_array($models))
+ {
+ foreach ($models as $id => $model)
+ {
+ $attributes[$name][$id] = $model->to_array();
+ }
+ }
+ elseif (is_null($models))
+ {
+ $attributes[$name] = $models;
+ }
+ }
+
+ return $attributes;
+ }
+
+ /**
+ * Fire a given event for the model.
+ *
+ * @param string $event
+ * @return array
+ */
+ protected function fire_event($event)
+ {
+ $events = array("eloquent.{$event}", "eloquent.{$event}: ".get_class($this));
+
+ Event::fire($events, array($this));
+ }
+
+ /**
+ * Handle the dynamic retrieval of attributes and associations.
+ *
+ * @param string $key
+ * @return mixed
+ */
+ public function __get($key)
+ {
+ // First we will check to see if the requested key is an already loaded
+ // relationship and return it if it is. All relationships are stored
+ // in the special relationships array so they are not persisted.
+ if (array_key_exists($key, $this->relationships))
+ {
+ return $this->relationships[$key];
+ }
+
+ // Next we'll check if the requested key is in the array of attributes
+ // for the model. These are simply regular properties that typically
+ // correspond to a single column on the database for the model.
+ elseif (array_key_exists($key, $this->attributes))
+ {
+ return $this->{"get_{$key}"}();
+ }
+
+ // If the item is not a loaded relationship, it may be a relationship
+ // that hasn't been loaded yet. If it is, we will lazy load it and
+ // set the value of the relationship in the relationship array.
+ elseif (method_exists($this, $key))
+ {
+ return $this->relationships[$key] = $this->$key()->results();
+ }
+
+ // Finally we will just assume the requested key is just a regular
+ // attribute and attempt to call the getter method for it, which
+ // will fall into the __call method if one doesn't exist.
+ else
+ {
+ return $this->{"get_{$key}"}();
+ }
+ }
+
+ /**
+ * Handle the dynamic setting of attributes.
+ *
+ * @param string $key
+ * @param mixed $value
+ * @return void
+ */
+ public function __set($key, $value)
+ {
+ $this->{"set_{$key}"}($value);
+ }
+
+ /**
+ * Determine if an attribute exists on the model.
+ *
+ * @param string $key
+ * @return bool
+ */
+ public function __isset($key)
+ {
+ foreach (array('attributes', 'relationships') as $source)
+ {
+ if (array_key_exists($key, $this->$source)) return true;
+ }
+
+ if (method_exists($this, $key)) return true;
+ }
+
+ /**
+ * Remove an attribute from the model.
+ *
+ * @param string $key
+ * @return void
+ */
+ public function __unset($key)
+ {
+ foreach (array('attributes', 'relationships') as $source)
+ {
+ unset($this->$source[$key]);
+ }
+ }
+
+ /**
+ * Handle dynamic method calls on the model.
+ *
+ * @param string $method
+ * @param array $parameters
+ * @return mixed
+ */
+ public function __call($method, $parameters)
+ {
+ $meta = array('key', 'table', 'connection', 'sequence', 'per_page', 'timestamps');
+
+ // If the method is actually the name of a static property on the model we'll
+ // return the value of the static property. This makes it convenient for
+ // relationships to access these values off of the instances.
+ if (in_array($method, $meta))
+ {
+ return static::$$method;
+ }
+
+ $underscored = array('with', 'find');
+
+ // Some methods need to be accessed both staticly and non-staticly so we'll
+ // keep underscored methods of those methods and intercept calls to them
+ // here so they can be called either way on the model instance.
+ if (in_array($method, $underscored))
+ {
+ return call_user_func_array(array($this, '_'.$method), $parameters);
+ }
+
+ // First we want to see if the method is a getter / setter for an attribute.
+ // If it is, we'll call the basic getter and setter method for the model
+ // to perform the appropriate action based on the method.
+ if (starts_with($method, 'get_'))
+ {
+ return $this->get_attribute(substr($method, 4));
+ }
+ elseif (starts_with($method, 'set_'))
+ {
+ $this->set_attribute(substr($method, 4), $parameters[0]);
+ }
+
+ // Finally we will assume that the method is actually the beginning of a
+ // query, such as "where", and will create a new query instance and
+ // call the method on the query instance, returning it after.
+ else
+ {
+ return call_user_func_array(array($this->query(), $method), $parameters);
+ }
+ }
+
+ /**
+ * Dynamically handle static method calls on the model.
+ *
+ * @param string $method
+ * @param array $parameters
+ * @return mixed
+ */
+ public static function __callStatic($method, $parameters)
+ {
+ $model = get_called_class();
+
+ return call_user_func_array(array(new $model, $method), $parameters);
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/eloquent/pivot.php b/laravel/database/eloquent/pivot.php
new file mode 100644
index 0000000..d2878bb
--- /dev/null
+++ b/laravel/database/eloquent/pivot.php
@@ -0,0 +1,54 @@
+pivot_table = $table;
+ $this->connection = $connection;
+
+ parent::__construct(array(), true);
+ }
+
+ /**
+ * Get the name of the pivot table.
+ *
+ * @return string
+ */
+ public function table()
+ {
+ return $this->pivot_table;
+ }
+
+ /**
+ * Get the connection used by the pivot table.
+ *
+ * @return string
+ */
+ public function connection()
+ {
+ return $this->connection;
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/eloquent/query.php b/laravel/database/eloquent/query.php
new file mode 100644
index 0000000..3aee79c
--- /dev/null
+++ b/laravel/database/eloquent/query.php
@@ -0,0 +1,280 @@
+model = ($model instanceof Model) ? $model : new $model;
+
+ $this->table = $this->table();
+ }
+
+ /**
+ * Get the first model result for the query.
+ *
+ * @param array $columns
+ * @return mixed
+ */
+ public function first($columns = array('*'))
+ {
+ $results = $this->hydrate($this->model, $this->table->take(1)->get($columns));
+
+ return (count($results) > 0) ? head($results) : null;
+ }
+
+ /**
+ * Get all of the model results for the query.
+ *
+ * @param array $columns
+ * @return array
+ */
+ public function get($columns = array('*'))
+ {
+ return $this->hydrate($this->model, $this->table->get($columns));
+ }
+
+ /**
+ * Get an array of paginated model results.
+ *
+ * @param int $per_page
+ * @param array $columns
+ * @return Paginator
+ */
+ public function paginate($per_page = null, $columns = array('*'))
+ {
+ $per_page = $per_page ?: $this->model->per_page();
+
+ // First we'll grab the Paginator instance and get the results. Then we can
+ // feed those raw database results into the hydrate method to get models
+ // for the results, which we'll set on the paginator and return it.
+ $paginator = $this->table->paginate($per_page, $columns);
+
+ $paginator->results = $this->hydrate($this->model, $paginator->results);
+
+ return $paginator;
+ }
+
+ /**
+ * Hydrate an array of models from the given results.
+ *
+ * @param Model $model
+ * @param array $results
+ * @return array
+ */
+ public function hydrate($model, $results)
+ {
+ $class = get_class($model);
+
+ $models = array();
+
+ // We'll spin through the array of database results and hydrate a model
+ // for each one of the records. We will also set the "exists" flag to
+ // "true" so that the model will be updated when it is saved.
+ foreach ((array) $results as $result)
+ {
+ $result = (array) $result;
+
+ $new = new $class(array(), true);
+
+ // We need to set the attributes manually in case the accessible property is
+ // set on the array which will prevent the mass assignemnt of attributes if
+ // we were to pass them in using the constructor or fill methods.
+ $new->fill_raw($result);
+
+ $models[] = $new;
+ }
+
+ if (count($results) > 0)
+ {
+ foreach ($this->model_includes() as $relationship => $constraints)
+ {
+ // If the relationship is nested, we will skip loading it here and let
+ // the load method parse and set the nested eager loads on the right
+ // relationship when it is getting ready to eager load.
+ if (str_contains($relationship, '.'))
+ {
+ continue;
+ }
+
+ $this->load($models, $relationship, $constraints);
+ }
+ }
+
+ // The many to many relationships may have pivot table column on them
+ // so we will call the "clean" method on the relationship to remove
+ // any pivot columns that are on the model.
+ if ($this instanceof Relationships\Has_Many_And_Belongs_To)
+ {
+ $this->hydrate_pivot($models);
+ }
+
+ return $models;
+ }
+
+ /**
+ * Hydrate an eagerly loaded relationship on the model results.
+ *
+ * @param array $results
+ * @param string $relationship
+ * @param array|null $constraints
+ * @return void
+ */
+ protected function load(&$results, $relationship, $constraints)
+ {
+ $query = $this->model->$relationship();
+
+ $query->model->includes = $this->nested_includes($relationship);
+
+ // We'll remove any of the where clauses from the relationship to give
+ // the relationship the opportunity to set the constraints for an
+ // eager relationship using a separate, specific method.
+ $query->table->reset_where();
+
+ $query->eagerly_constrain($results);
+
+ // Constraints may be specified in-line for the eager load by passing
+ // a Closure as the value portion of the eager load. We can use the
+ // query builder's nested query support to add the constraints.
+ if ( ! is_null($constraints))
+ {
+ $query->table->where_nested($constraints);
+ }
+
+ $query->initialize($results, $relationship);
+
+ $query->match($relationship, $results, $query->get());
+ }
+
+ /**
+ * Gather the nested includes for a given relationship.
+ *
+ * @param string $relationship
+ * @return array
+ */
+ protected function nested_includes($relationship)
+ {
+ $nested = array();
+
+ foreach ($this->model_includes() as $include => $constraints)
+ {
+ // To get the nested includes, we want to find any includes that begin
+ // the relationship and a dot, then we will strip off the leading
+ // nesting indicator and set the include in the array.
+ if (starts_with($include, $relationship.'.'))
+ {
+ $nested[substr($include, strlen($relationship.'.'))] = $constraints;
+ }
+ }
+
+ return $nested;
+ }
+
+ /**
+ * Get the eagerly loaded relationships for the model.
+ *
+ * @return array
+ */
+ protected function model_includes()
+ {
+ $includes = array();
+
+ foreach ($this->model->includes as $relationship => $constraints)
+ {
+ // When eager loading relationships, constraints may be set on the eager
+ // load definition; however, is none are set, we need to swap the key
+ // and the value of the array since there are no constraints.
+ if (is_numeric($relationship))
+ {
+ list($relationship, $constraints) = array($constraints, null);
+ }
+
+ $includes[$relationship] = $constraints;
+ }
+
+ return $includes;
+ }
+
+ /**
+ * Get a fluent query builder for the model.
+ *
+ * @return Query
+ */
+ protected function table()
+ {
+ return $this->connection()->table($this->model->table());
+ }
+
+ /**
+ * Get the database connection for the model.
+ *
+ * @return Connection
+ */
+ public function connection()
+ {
+ return Database::connection($this->model->connection());
+ }
+
+ /**
+ * Handle dynamic method calls to the query.
+ *
+ * @param string $method
+ * @param array $parameters
+ * @return mixed
+ */
+ public function __call($method, $parameters)
+ {
+ $result = call_user_func_array(array($this->table, $method), $parameters);
+
+ // Some methods may get their results straight from the fluent query
+ // builder such as the aggregate methods. If the called method is
+ // one of these, we will just return the result straight away.
+ if (in_array($method, $this->passthru))
+ {
+ return $result;
+ }
+
+ return $this;
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/eloquent/relationships/belongs_to.php b/laravel/database/eloquent/relationships/belongs_to.php
new file mode 100644
index 0000000..ef25783
--- /dev/null
+++ b/laravel/database/eloquent/relationships/belongs_to.php
@@ -0,0 +1,114 @@
+get_dirty() : $attributes;
+
+ return $this->model->update($this->foreign_value(), $attributes);
+ }
+
+ /**
+ * Set the proper constraints on the relationship table.
+ *
+ * @return void
+ */
+ protected function constrain()
+ {
+ $this->table->where($this->model->key(), '=', $this->foreign_value());
+ }
+
+ /**
+ * Initialize a relationship on an array of parent models.
+ *
+ * @param array $parents
+ * @param string $relationship
+ * @return void
+ */
+ public function initialize(&$parents, $relationship)
+ {
+ foreach ($parents as &$parent)
+ {
+ $parent->relationships[$relationship] = null;
+ }
+ }
+
+ /**
+ * Set the proper constraints on the relationship table for an eager load.
+ *
+ * @param array $results
+ * @return void
+ */
+ public function eagerly_constrain($results)
+ {
+ $keys = array();
+
+ // Inverse one-to-many relationships require us to gather the keys from the
+ // parent models and use those keys when setting the constraint since we
+ // are looking for the parent of a child model in this relationship.
+ foreach ($results as $result)
+ {
+ if ( ! is_null($key = $result->{$this->foreign_key()}))
+ {
+ $keys[] = $key;
+ }
+ }
+
+ if (count($keys) == 0) $keys = array(0);
+
+ $this->table->where_in($this->model->key(), array_unique($keys));
+ }
+
+ /**
+ * Match eagerly loaded child models to their parent models.
+ *
+ * @param array $children
+ * @param array $parents
+ * @return void
+ */
+ public function match($relationship, &$children, $parents)
+ {
+ $foreign = $this->foreign_key();
+
+ foreach ($children as &$child)
+ {
+ $parent = array_first($parents, function($k, $v) use (&$child, $foreign)
+ {
+ return $v->get_key() == $child->$foreign;
+ });
+
+ if ( ! is_null($parent))
+ {
+ $child->relationships[$relationship] = $parent;
+ }
+ }
+ }
+
+ /**
+ * Get the value of the foreign key from the base model.
+ *
+ * @return mixed
+ */
+ public function foreign_value()
+ {
+ return $this->base->get_attribute($this->foreign);
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/eloquent/relationships/has_many.php b/laravel/database/eloquent/relationships/has_many.php
new file mode 100644
index 0000000..726bef2
--- /dev/null
+++ b/laravel/database/eloquent/relationships/has_many.php
@@ -0,0 +1,105 @@
+table->lists($this->model->key());
+
+ foreach ($models as $attributes)
+ {
+ $class = get_class($this->model);
+
+ // If the "attributes" are actually an array of the related model we'll
+ // just use the existing instance instead of creating a fresh model
+ // instance for the attributes. This allows for validation.
+ if ($attributes instanceof $class)
+ {
+ $model = $attributes;
+ }
+ else
+ {
+ $model = $this->fresh_model($attributes);
+ }
+
+ // We'll need to associate the model with its parent, so we'll set the
+ // foreign key on the model to the key of the parent model, making
+ // sure that the two models are associated in the database.
+ $foreign = $this->foreign_key();
+
+ $model->$foreign = $this->base->get_key();
+
+ $id = $model->get_key();
+
+ $model->exists = ( ! is_null($id) and in_array($id, $current));
+
+ // Before saving we'll force the entire model to be "dirty" so all of
+ // the attributes are saved. It shouldn't affect the updates as
+ // saving all the attributes shouldn't hurt anything.
+ $model->original = array();
+
+ $model->save();
+ }
+
+ return true;
+ }
+
+ /**
+ * Initialize a relationship on an array of parent models.
+ *
+ * @param array $parents
+ * @param string $relationship
+ * @return void
+ */
+ public function initialize(&$parents, $relationship)
+ {
+ foreach ($parents as &$parent)
+ {
+ $parent->relationships[$relationship] = array();
+ }
+ }
+
+ /**
+ * Match eagerly loaded child models to their parent models.
+ *
+ * @param array $parents
+ * @param array $children
+ * @return void
+ */
+ public function match($relationship, &$parents, $children)
+ {
+ $foreign = $this->foreign_key();
+
+ foreach ($parents as &$parent)
+ {
+ $matching = array_filter($children, function($v) use (&$parent, $foreign)
+ {
+ return $v->$foreign == $parent->get_key();
+ });
+
+ $parent->relationships[$relationship] = array_values($matching);
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/eloquent/relationships/has_many_and_belongs_to.php b/laravel/database/eloquent/relationships/has_many_and_belongs_to.php
new file mode 100644
index 0000000..52276a5
--- /dev/null
+++ b/laravel/database/eloquent/relationships/has_many_and_belongs_to.php
@@ -0,0 +1,428 @@
+other = $other;
+
+ $this->joining = $table ?: $this->joining($model, $associated);
+
+ // If the Pivot table is timestamped, we'll set the timestamp columns to be
+ // fetched when the pivot table models are fetched by the developer else
+ // the ID will be the only "extra" column fetched in by default.
+ if (Pivot::$timestamps)
+ {
+ $this->with[] = 'created_at';
+
+ $this->with[] = 'updated_at';
+ }
+
+ parent::__construct($model, $associated, $foreign);
+ }
+
+ /**
+ * Determine the joining table name for the relationship.
+ *
+ * By default, the name is the models sorted and joined with underscores.
+ *
+ * @return string
+ */
+ protected function joining($model, $associated)
+ {
+ $models = array(class_basename($model), class_basename($associated));
+
+ sort($models);
+
+ return strtolower($models[0].'_'.$models[1]);
+ }
+
+ /**
+ * Get the properly hydrated results for the relationship.
+ *
+ * @return array
+ */
+ public function results()
+ {
+ return parent::get();
+ }
+
+ /**
+ * Insert a new record into the joining table of the association.
+ *
+ * @param int $id
+ * @param array $joining
+ * @return bool
+ */
+ public function attach($id, $attributes = array())
+ {
+ $joining = array_merge($this->join_record($id), $attributes);
+
+ return $this->insert_joining($joining);
+ }
+
+ /**
+ * Detach a record from the joining table of the association.
+ *
+ * @param int $ids
+ * @return bool
+ */
+ public function detach($ids)
+ {
+ if ( ! is_array($ids)) $ids = array($ids);
+
+ return $this->pivot()->where_in($this->other_key(), $ids)->delete();
+ }
+
+ /**
+ * Sync the joining table with the array of given IDs.
+ *
+ * @param array $ids
+ * @return bool
+ */
+ public function sync($ids)
+ {
+ $current = $this->pivot()->lists($this->other_key());
+
+ // First we need to attach any of the associated models that are not currently
+ // in the joining table. We'll spin through the given IDs, checking to see
+ // if they exist in the array of current ones, and if not we insert.
+ foreach ($ids as $id)
+ {
+ if ( ! in_array($id, $current))
+ {
+ $this->attach($id);
+ }
+ }
+
+ // Next we will take the difference of the current and given IDs and detach
+ // all of the entities that exists in the current array but are not in
+ // the array of IDs given to the method, finishing the sync.
+ $detach = array_diff($current, $ids);
+
+ if (count($detach) > 0)
+ {
+ $this->detach(array_diff($current, $ids));
+ }
+ }
+
+ /**
+ * Insert a new record for the association.
+ *
+ * @param Model|array $attributes
+ * @param array $joining
+ * @return bool
+ */
+ public function insert($attributes, $joining = array())
+ {
+ // If the attributes are actually an instance of a model, we'll just grab the
+ // array of attributes off of the model for saving, allowing the developer
+ // to easily validate the joining models before inserting them.
+ if ($attributes instanceof Model)
+ {
+ $attributes = $attributes->attributes;
+ }
+
+ $model = $this->model->create($attributes);
+
+ // If the insert was successful, we'll insert a record into the joining table
+ // using the new ID that was just inserted into the related table, allowing
+ // the developer to not worry about maintaining the join table.
+ if ($model instanceof Model)
+ {
+ $joining = array_merge($this->join_record($model->get_key()), $joining);
+
+ $result = $this->insert_joining($joining);
+ }
+
+ return $model instanceof Model and $result;
+ }
+
+ /**
+ * Delete all of the records from the joining table for the model.
+ *
+ * @return int
+ */
+ public function delete()
+ {
+ return $this->pivot()->delete();
+ }
+
+ /**
+ * Create an array representing a new joining record for the association.
+ *
+ * @param int $id
+ * @return array
+ */
+ protected function join_record($id)
+ {
+ return array($this->foreign_key() => $this->base->get_key(), $this->other_key() => $id);
+ }
+
+ /**
+ * Insert a new record into the joining table of the association.
+ *
+ * @param array $attributes
+ * @return void
+ */
+ protected function insert_joining($attributes)
+ {
+ if (Pivot::$timestamps)
+ {
+ $attributes['created_at'] = new \DateTime;
+
+ $attributes['updated_at'] = $attributes['created_at'];
+ }
+
+ return $this->joining_table()->insert($attributes);
+ }
+
+ /**
+ * Get a fluent query for the joining table of the relationship.
+ *
+ * @return Query
+ */
+ protected function joining_table()
+ {
+ return $this->connection()->table($this->joining);
+ }
+
+ /**
+ * Set the proper constraints on the relationship table.
+ *
+ * @return void
+ */
+ protected function constrain()
+ {
+ $other = $this->other_key();
+
+ $foreign = $this->foreign_key();
+
+ $this->set_select($foreign, $other)->set_join($other)->set_where($foreign);
+ }
+
+ /**
+ * Set the SELECT clause on the query builder for the relationship.
+ *
+ * @param string $foreign
+ * @param string $other
+ * @return void
+ */
+ protected function set_select($foreign, $other)
+ {
+ $columns = array($this->model->table().'.*');
+
+ $this->with = array_merge($this->with, array($foreign, $other));
+
+ // Since pivot tables may have extra information on them that the developer
+ // needs we allow an extra array of columns to be specified that will be
+ // fetched from the pivot table and hydrate into the pivot model.
+ foreach ($this->with as $column)
+ {
+ $columns[] = $this->joining.'.'.$column.' as pivot_'.$column;
+ }
+
+ $this->table->select($columns);
+
+ return $this;
+ }
+
+ /**
+ * Set the JOIN clause on the query builder for the relationship.
+ *
+ * @param string $other
+ * @return void
+ */
+ protected function set_join($other)
+ {
+ $this->table->join($this->joining, $this->associated_key(), '=', $this->joining.'.'.$other);
+
+ return $this;
+ }
+
+ /**
+ * Set the WHERE clause on the query builder for the relationship.
+ *
+ * @param string $foreign
+ * @return void
+ */
+ protected function set_where($foreign)
+ {
+ $this->table->where($this->joining.'.'.$foreign, '=', $this->base->get_key());
+
+ return $this;
+ }
+
+ /**
+ * Initialize a relationship on an array of parent models.
+ *
+ * @param array $parents
+ * @param string $relationship
+ * @return void
+ */
+ public function initialize(&$parents, $relationship)
+ {
+ foreach ($parents as &$parent)
+ {
+ $parent->relationships[$relationship] = array();
+ }
+ }
+
+ /**
+ * Set the proper constraints on the relationship table for an eager load.
+ *
+ * @param array $results
+ * @return void
+ */
+ public function eagerly_constrain($results)
+ {
+ $this->table->where_in($this->joining.'.'.$this->foreign_key(), $this->keys($results));
+ }
+
+ /**
+ * Match eagerly loaded child models to their parent models.
+ *
+ * @param array $parents
+ * @param array $children
+ * @return void
+ */
+ public function match($relationship, &$parents, $children)
+ {
+ $foreign = $this->foreign_key();
+
+ foreach ($parents as &$parent)
+ {
+ $matching = array_filter($children, function($v) use (&$parent, $foreign)
+ {
+ return $v->pivot->$foreign == $parent->get_key();
+ });
+
+ $parent->relationships[$relationship] = array_values($matching);
+ }
+ }
+
+ /**
+ * Hydrate the Pivot model on an array of results.
+ *
+ * @param array $results
+ * @return void
+ */
+ protected function hydrate_pivot(&$results)
+ {
+ foreach ($results as &$result)
+ {
+ // Every model result for a many-to-many relationship needs a Pivot instance
+ // to represent the pivot table's columns. Sometimes extra columns are on
+ // the pivot table that may need to be accessed by the developer.
+ $pivot = new Pivot($this->joining, $this->model->connection());
+
+ // If the attribute key starts with "pivot_", we know this is a column on
+ // the pivot table, so we will move it to the Pivot model and purge it
+ // from the model since it actually belongs to the pivot model.
+ foreach ($result->attributes as $key => $value)
+ {
+ if (starts_with($key, 'pivot_'))
+ {
+ $pivot->{substr($key, 6)} = $value;
+
+ $result->purge($key);
+ }
+ }
+
+ // Once we have completed hydrating the pivot model instance, we'll set
+ // it on the result model's relationships array so the developer can
+ // quickly and easily access any pivot table information.
+ $result->relationships['pivot'] = $pivot;
+
+ $pivot->sync() and $result->sync();
+ }
+ }
+
+ /**
+ * Set the columns on the joining table that should be fetched.
+ *
+ * @param array $column
+ * @return Relationship
+ */
+ public function with($columns)
+ {
+ $columns = (is_array($columns)) ? $columns : func_get_args();
+
+ // The "with" array contains a couple of columns by default, so we will just
+ // merge in the developer specified columns here, and we will make sure
+ // the values of the array are unique to avoid duplicates.
+ $this->with = array_unique(array_merge($this->with, $columns));
+
+ $this->set_select($this->foreign_key(), $this->other_key());
+
+ return $this;
+ }
+
+ /**
+ * Get a relationship instance of the pivot table.
+ *
+ * @return Has_Many
+ */
+ public function pivot()
+ {
+ $pivot = new Pivot($this->joining, $this->model->connection());
+
+ return new Has_Many($this->base, $pivot, $this->foreign_key());
+ }
+
+ /**
+ * Get the other or associated key for the relationship.
+ *
+ * @return string
+ */
+ protected function other_key()
+ {
+ return Relationship::foreign($this->model, $this->other);
+ }
+
+ /**
+ * Get the fully qualified associated table's primary key.
+ *
+ * @return string
+ */
+ protected function associated_key()
+ {
+ return $this->model->table().'.'.$this->model->key();
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/eloquent/relationships/has_one.php b/laravel/database/eloquent/relationships/has_one.php
new file mode 100644
index 0000000..8d1e4ff
--- /dev/null
+++ b/laravel/database/eloquent/relationships/has_one.php
@@ -0,0 +1,52 @@
+relationships[$relationship] = null;
+ }
+ }
+
+ /**
+ * Match eagerly loaded child models to their parent models.
+ *
+ * @param array $parents
+ * @param array $children
+ * @return void
+ */
+ public function match($relationship, &$parents, $children)
+ {
+ $foreign = $this->foreign_key();
+
+ foreach ($parents as &$parent)
+ {
+ $matching = array_first($children, function($k, $v) use (&$parent, $foreign)
+ {
+ return $v->$foreign == $parent->get_key();
+ });
+
+ $parent->relationships[$relationship] = $matching;
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/eloquent/relationships/has_one_or_many.php b/laravel/database/eloquent/relationships/has_one_or_many.php
new file mode 100644
index 0000000..a8268de
--- /dev/null
+++ b/laravel/database/eloquent/relationships/has_one_or_many.php
@@ -0,0 +1,59 @@
+attributes : $attributes;
+
+ $attributes[$this->foreign_key()] = $this->base->get_key();
+
+ return $this->model->create($attributes);
+ }
+
+ /**
+ * Update a record for the association.
+ *
+ * @param array $attributes
+ * @return bool
+ */
+ public function update(array $attributes)
+ {
+ if ($this->model->timestamps())
+ {
+ $attributes['updated_at'] = new \DateTime;
+ }
+
+ return $this->table->update($attributes);
+ }
+
+ /**
+ * Set the proper constraints on the relationship table.
+ *
+ * @return void
+ */
+ protected function constrain()
+ {
+ $this->table->where($this->foreign_key(), '=', $this->base->get_key());
+ }
+
+ /**
+ * Set the proper constraints on the relationship table for an eager load.
+ *
+ * @param array $results
+ * @return void
+ */
+ public function eagerly_constrain($results)
+ {
+ $this->table->where_in($this->foreign_key(), $this->keys($results));
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/eloquent/relationships/relationship.php b/laravel/database/eloquent/relationships/relationship.php
new file mode 100644
index 0000000..34c03f6
--- /dev/null
+++ b/laravel/database/eloquent/relationships/relationship.php
@@ -0,0 +1,122 @@
+foreign = $foreign;
+
+ // We will go ahead and set the model and associated instances on the
+ // relationship to match the relationship targets passed in from the
+ // model. These will allow us to gather the relationship info.
+ if ($associated instanceof Model)
+ {
+ $this->model = $associated;
+ }
+ else
+ {
+ $this->model = new $associated;
+ }
+
+ // For relationships, we'll set the base model to be the model being
+ // associated from. This model contains the value of the foreign
+ // key needed to connect to the associated model.
+ if ($model instanceof Model)
+ {
+ $this->base = $model;
+ }
+ else
+ {
+ $this->base = new $model;
+ }
+
+ // Next we'll set the fluent query builder for the relationship and
+ // constrain the query such that it only returns the models that
+ // are appropriate for the relationship.
+ $this->table = $this->table();
+
+ $this->constrain();
+ }
+
+ /**
+ * Get the foreign key name for the given model.
+ *
+ * @param string $model
+ * @param string $foreign
+ * @return string
+ */
+ public static function foreign($model, $foreign = null)
+ {
+ if ( ! is_null($foreign)) return $foreign;
+
+ // If the model is an object we'll simply get the class of the object and
+ // then take the basename, which is simply the object name minus the
+ // namespace, and we'll append "_id" to the name.
+ if (is_object($model))
+ {
+ $model = class_basename($model);
+ }
+
+ return strtolower(basename($model).'_id');
+ }
+
+ /**
+ * Get a freshly instantiated instance of the related model class.
+ *
+ * @param array $attributes
+ * @return Model
+ */
+ protected function fresh_model($attributes = array())
+ {
+ $class = get_class($this->model);
+
+ return new $class($attributes);
+ }
+
+ /**
+ * Get the foreign key for the relationship.
+ *
+ * @return string
+ */
+ public function foreign_key()
+ {
+ return static::foreign($this->base, $this->foreign);
+ }
+
+ /**
+ * Gather all the primary keys from a result set.
+ *
+ * @param array $results
+ * @return array
+ */
+ public function keys($results)
+ {
+ $keys = array();
+
+ foreach ($results as $result)
+ {
+ $keys[] = $result->get_key();
+ }
+
+ return array_unique($keys);
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/exception.php b/laravel/database/exception.php
new file mode 100644
index 0000000..a116ad7
--- /dev/null
+++ b/laravel/database/exception.php
@@ -0,0 +1,41 @@
+inner = $inner;
+
+ $this->setMessage($sql, $bindings);
+ }
+
+ /**
+ * Set the exception message to include the SQL and bindings.
+ *
+ * @param string $sql
+ * @param array $bindings
+ * @return void
+ */
+ protected function setMessage($sql, $bindings)
+ {
+ $this->message = $this->inner->getMessage();
+
+ $this->message .= "\n\nSQL: ".$sql."\n\nBindings: ".var_export($bindings, true);
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/expression.php b/laravel/database/expression.php
new file mode 100644
index 0000000..f92eed6
--- /dev/null
+++ b/laravel/database/expression.php
@@ -0,0 +1,43 @@
+value = $value;
+ }
+
+ /**
+ * Get the string value of the database expression.
+ *
+ * @return string
+ */
+ public function get()
+ {
+ return $this->value;
+ }
+
+ /**
+ * Get the string value of the database expression.
+ *
+ * @return string
+ */
+ public function __toString()
+ {
+ return $this->get();
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/grammar.php b/laravel/database/grammar.php
new file mode 100644
index 0000000..13d92d8
--- /dev/null
+++ b/laravel/database/grammar.php
@@ -0,0 +1,174 @@
+connection = $connection;
+ }
+
+ /**
+ * Wrap a table in keyword identifiers.
+ *
+ * @param string $table
+ * @return string
+ */
+ public function wrap_table($table)
+ {
+ // Expressions should be injected into the query as raw strings so
+ // so we do not want to wrap them in any way. We will just return
+ // the string value from the expression to be included.
+ if ($table instanceof Expression)
+ {
+ return $this->wrap($table);
+ }
+
+ $prefix = '';
+
+ // Tables may be prefixed with a string. This allows developers to
+ // prefix tables by application on the same database which may be
+ // required in some brown-field situations.
+ if (isset($this->connection->config['prefix']))
+ {
+ $prefix = $this->connection->config['prefix'];
+ }
+
+ return $this->wrap($prefix.$table);
+ }
+
+ /**
+ * Wrap a value in keyword identifiers.
+ *
+ * @param string $value
+ * @return string
+ */
+ public function wrap($value)
+ {
+ // Expressions should be injected into the query as raw strings so
+ // so we do not want to wrap them in any way. We will just return
+ // the string value from the expression to be included.
+ if ($value instanceof Expression)
+ {
+ return $value->get();
+ }
+
+ // If the value being wrapped contains a column alias, we need to
+ // wrap it a little differently as each segment must be wrapped
+ // and not the entire string.
+ if (strpos(strtolower($value), ' as ') !== false)
+ {
+ $segments = explode(' ', $value);
+
+ return sprintf(
+ '%s AS %s',
+ $this->wrap($segments[0]),
+ $this->wrap($segments[2])
+ );
+ }
+
+ // Since columns may be prefixed with their corresponding table
+ // name so as to not make them ambiguous, we will need to wrap
+ // the table and the column in keyword identifiers.
+ $segments = explode('.', $value);
+
+ foreach ($segments as $key => $value)
+ {
+ if ($key == 0 and count($segments) > 1)
+ {
+ $wrapped[] = $this->wrap_table($value);
+ }
+ else
+ {
+ $wrapped[] = $this->wrap_value($value);
+ }
+ }
+
+ return implode('.', $wrapped);
+ }
+
+ /**
+ * Wrap a single string value in keyword identifiers.
+ *
+ * @param string $value
+ * @return string
+ */
+ protected function wrap_value($value)
+ {
+ return ($value !== '*') ? sprintf($this->wrapper, $value) : $value;
+ }
+
+ /**
+ * Create query parameters from an array of values.
+ *
+ *
+ * Returns "?, ?, ?", which may be used as PDO place-holders
+ * $parameters = $grammar->parameterize(array(1, 2, 3));
+ *
+ * // Returns "?, "Taylor"" since an expression is used
+ * $parameters = $grammar->parameterize(array(1, DB::raw('Taylor')));
+ *
+ *
+ * @param array $values
+ * @return string
+ */
+ final public function parameterize($values)
+ {
+ return implode(', ', array_map(array($this, 'parameter'), $values));
+ }
+
+ /**
+ * Get the appropriate query parameter string for a value.
+ *
+ *
+ * // Returns a "?" PDO place-holder
+ * $value = $grammar->parameter('Taylor Otwell');
+ *
+ * // Returns "Taylor Otwell" as the raw value of the expression
+ * $value = $grammar->parameter(DB::raw('Taylor Otwell'));
+ *
+ *
+ * @param mixed $value
+ * @return string
+ */
+ final public function parameter($value)
+ {
+ return ($value instanceof Expression) ? $value->get() : '?';
+ }
+
+ /**
+ * Create a comma-delimited list of wrapped column names.
+ *
+ *
+ * // Returns ""Taylor", "Otwell"" when the identifier is quotes
+ * $columns = $grammar->columnize(array('Taylor', 'Otwell'));
+ *
+ *
+ * @param array $columns
+ * @return string
+ */
+ final public function columnize($columns)
+ {
+ return implode(', ', array_map(array($this, 'wrap'), $columns));
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/query.php b/laravel/database/query.php
new file mode 100644
index 0000000..83c92b8
--- /dev/null
+++ b/laravel/database/query.php
@@ -0,0 +1,884 @@
+from = $table;
+ $this->grammar = $grammar;
+ $this->connection = $connection;
+ }
+
+ /**
+ * Force the query to return distinct results.
+ *
+ * @return Query
+ */
+ public function distinct()
+ {
+ $this->distinct = true;
+ return $this;
+ }
+
+ /**
+ * Add an array of columns to the SELECT clause.
+ *
+ * @param array $columns
+ * @return Query
+ */
+ public function select($columns = array('*'))
+ {
+ $this->selects = (array) $columns;
+ return $this;
+ }
+
+ /**
+ * Add a join clause to the query.
+ *
+ * @param string $table
+ * @param string $column1
+ * @param string $operator
+ * @param string $column2
+ * @param string $type
+ * @return Query
+ */
+ public function join($table, $column1, $operator = null, $column2 = null, $type = 'INNER')
+ {
+ // If the "column" is really an instance of a Closure, the developer is
+ // trying to create a join with a complex "ON" clause. So, we will add
+ // the join, and then call the Closure with the join/
+ if ($column1 instanceof Closure)
+ {
+ $this->joins[] = new Query\Join($type, $table);
+
+ call_user_func($column1, end($this->joins));
+ }
+
+ // If the column is just a string, we can assume that the join just
+ // has a simple on clause, and we'll create the join instance and
+ // add the clause automatically for the develoepr.
+ else
+ {
+ $join = new Query\Join($type, $table);
+
+ $join->on($column1, $operator, $column2);
+
+ $this->joins[] = $join;
+ }
+
+ return $this;
+ }
+
+ /**
+ * Add a left join to the query.
+ *
+ * @param string $table
+ * @param string $column1
+ * @param string $operator
+ * @param string $column2
+ * @return Query
+ */
+ public function left_join($table, $column1, $operator = null, $column2 = null)
+ {
+ return $this->join($table, $column1, $operator, $column2, 'LEFT');
+ }
+
+ /**
+ * Reset the where clause to its initial state.
+ *
+ * @return void
+ */
+ public function reset_where()
+ {
+ list($this->wheres, $this->bindings) = array(array(), array());
+ }
+
+ /**
+ * Add a raw where condition to the query.
+ *
+ * @param string $where
+ * @param array $bindings
+ * @param string $connector
+ * @return Query
+ */
+ public function raw_where($where, $bindings = array(), $connector = 'AND')
+ {
+ $this->wheres[] = array('type' => 'where_raw', 'connector' => $connector, 'sql' => $where);
+
+ $this->bindings = array_merge($this->bindings, $bindings);
+
+ return $this;
+ }
+
+ /**
+ * Add a raw or where condition to the query.
+ *
+ * @param string $where
+ * @param array $bindings
+ * @return Query
+ */
+ public function raw_or_where($where, $bindings = array())
+ {
+ return $this->raw_where($where, $bindings, 'OR');
+ }
+
+ /**
+ * Add a where condition to the query.
+ *
+ * @param string $column
+ * @param string $operator
+ * @param mixed $value
+ * @param string $connector
+ * @return Query
+ */
+ public function where($column, $operator = null, $value = null, $connector = 'AND')
+ {
+ // If a Closure is passed into the method, it means a nested where
+ // clause is being initiated, so we will take a different course
+ // of action than when the statement is just a simple where.
+ if ($column instanceof Closure)
+ {
+ return $this->where_nested($column, $connector);
+ }
+
+ $type = 'where';
+
+ $this->wheres[] = compact('type', 'column', 'operator', 'value', 'connector');
+
+ $this->bindings[] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Add an or where condition to the query.
+ *
+ * @param string $column
+ * @param string $operator
+ * @param mixed $value
+ * @return Query
+ */
+ public function or_where($column, $operator = null, $value = null)
+ {
+ return $this->where($column, $operator, $value, 'OR');
+ }
+
+ /**
+ * Add an or where condition for the primary key to the query.
+ *
+ * @param mixed $value
+ * @return Query
+ */
+ public function or_where_id($value)
+ {
+ return $this->or_where('id', '=', $value);
+ }
+
+ /**
+ * Add a where in condition to the query.
+ *
+ * @param string $column
+ * @param array $values
+ * @param string $connector
+ * @param bool $not
+ * @return Query
+ */
+ public function where_in($column, $values, $connector = 'AND', $not = false)
+ {
+ $type = ($not) ? 'where_not_in' : 'where_in';
+
+ $this->wheres[] = compact('type', 'column', 'values', 'connector');
+
+ $this->bindings = array_merge($this->bindings, $values);
+
+ return $this;
+ }
+
+ /**
+ * Add an or where in condition to the query.
+ *
+ * @param string $column
+ * @param array $values
+ * @return Query
+ */
+ public function or_where_in($column, $values)
+ {
+ return $this->where_in($column, $values, 'OR');
+ }
+
+ /**
+ * Add a where not in condition to the query.
+ *
+ * @param string $column
+ * @param array $values
+ * @param string $connector
+ * @return Query
+ */
+ public function where_not_in($column, $values, $connector = 'AND')
+ {
+ return $this->where_in($column, $values, $connector, true);
+ }
+
+ /**
+ * Add an or where not in condition to the query.
+ *
+ * @param string $column
+ * @param array $values
+ * @return Query
+ */
+ public function or_where_not_in($column, $values)
+ {
+ return $this->where_not_in($column, $values, 'OR');
+ }
+
+ /**
+ * Add a where null condition to the query.
+ *
+ * @param string $column
+ * @param string $connector
+ * @param bool $not
+ * @return Query
+ */
+ public function where_null($column, $connector = 'AND', $not = false)
+ {
+ $type = ($not) ? 'where_not_null' : 'where_null';
+
+ $this->wheres[] = compact('type', 'column', 'connector');
+
+ return $this;
+ }
+
+ /**
+ * Add an or where null condition to the query.
+ *
+ * @param string $column
+ * @return Query
+ */
+ public function or_where_null($column)
+ {
+ return $this->where_null($column, 'OR');
+ }
+
+ /**
+ * Add a where not null condition to the query.
+ *
+ * @param string $column
+ * @param string $connector
+ * @return Query
+ */
+ public function where_not_null($column, $connector = 'AND')
+ {
+ return $this->where_null($column, $connector, true);
+ }
+
+ /**
+ * Add an or where not null condition to the query.
+ *
+ * @param string $column
+ * @return Query
+ */
+ public function or_where_not_null($column)
+ {
+ return $this->where_not_null($column, 'OR');
+ }
+
+ /**
+ * Add a nested where condition to the query.
+ *
+ * @param Closure $callback
+ * @param string $connector
+ * @return Query
+ */
+ public function where_nested($callback, $connector = 'AND')
+ {
+ $type = 'where_nested';
+
+ // To handle a nested where statement, we will actually instantiate a new
+ // Query instance and run the callback over that instance, which will
+ // allow the developer to have a fresh query instance
+ $query = new Query($this->connection, $this->grammar, $this->from);
+
+ call_user_func($callback, $query);
+
+ // Once the callback has been run on the query, we will store the nested
+ // query instance on the where clause array so that it's passed to the
+ // query's query grammar instance when building.
+ if ($query->wheres !== null)
+ {
+ $this->wheres[] = compact('type', 'query', 'connector');
+ }
+
+ $this->bindings = array_merge($this->bindings, $query->bindings);
+
+ return $this;
+ }
+
+ /**
+ * Add dynamic where conditions to the query.
+ *
+ * @param string $method
+ * @param array $parameters
+ * @return Query
+ */
+ private function dynamic_where($method, $parameters)
+ {
+ $finder = substr($method, 6);
+
+ $flags = PREG_SPLIT_DELIM_CAPTURE;
+
+ $segments = preg_split('/(_and_|_or_)/i', $finder, -1, $flags);
+
+ // The connector variable will determine which connector will be used
+ // for the condition. We'll change it as we come across new boolean
+ // connectors in the dynamic method string.
+ //
+ // The index variable helps us get the correct parameter value for
+ // the where condition. We increment it each time we add another
+ // condition to the query's where clause.
+ $connector = 'AND';
+
+ $index = 0;
+
+ foreach ($segments as $segment)
+ {
+ // If the segment is not a boolean connector, we can assume it it is
+ // a column name, and we'll add it to the query as a new constraint
+ // of the query's where clause and keep iterating the segments.
+ if ($segment != '_and_' and $segment != '_or_')
+ {
+ $this->where($segment, '=', $parameters[$index], $connector);
+
+ $index++;
+ }
+ // Otherwise, we will store the connector so we know how the next
+ // where clause we find in the query should be connected to the
+ // previous one and will add it when we find the next one.
+ else
+ {
+ $connector = trim(strtoupper($segment), '_');
+ }
+ }
+
+ return $this;
+ }
+
+ /**
+ * Add a grouping to the query.
+ *
+ * @param string $column
+ * @return Query
+ */
+ public function group_by($column)
+ {
+ $this->groupings[] = $column;
+ return $this;
+ }
+
+ /**
+ * Add a having to the query.
+ *
+ * @param string $column
+ * @param string $operator
+ * @param mixed $value
+ */
+ public function having($column, $operator, $value)
+ {
+ $this->havings[] = compact('column', 'operator', 'value');
+
+ $this->bindings[] = $value;
+
+ return $this;
+ }
+
+ /**
+ * Add an ordering to the query.
+ *
+ * @param string $column
+ * @param string $direction
+ * @return Query
+ */
+ public function order_by($column, $direction = 'asc')
+ {
+ $this->orderings[] = compact('column', 'direction');
+ return $this;
+ }
+
+ /**
+ * Set the query offset.
+ *
+ * @param int $value
+ * @return Query
+ */
+ public function skip($value)
+ {
+ $this->offset = $value;
+ return $this;
+ }
+
+ /**
+ * Set the query limit.
+ *
+ * @param int $value
+ * @return Query
+ */
+ public function take($value)
+ {
+ $this->limit = $value;
+ return $this;
+ }
+
+ /**
+ * Set the query limit and offset for a given page.
+ *
+ * @param int $page
+ * @param int $per_page
+ * @return Query
+ */
+ public function for_page($page, $per_page)
+ {
+ return $this->skip(($page - 1) * $per_page)->take($per_page);
+ }
+
+ /**
+ * Find a record by the primary key.
+ *
+ * @param int $id
+ * @param array $columns
+ * @return object
+ */
+ public function find($id, $columns = array('*'))
+ {
+ return $this->where('id', '=', $id)->first($columns);
+ }
+
+ /**
+ * Execute the query as a SELECT statement and return a single column.
+ *
+ * @param string $column
+ * @return mixed
+ */
+ public function only($column)
+ {
+ $sql = $this->grammar->select($this->select(array($column)));
+
+ return $this->connection->only($sql, $this->bindings);
+ }
+
+ /**
+ * Execute the query as a SELECT statement and return the first result.
+ *
+ * @param array $columns
+ * @return mixed
+ */
+ public function first($columns = array('*'))
+ {
+ $columns = (array) $columns;
+
+ // Since we only need the first result, we'll go ahead and set the
+ // limit clause to 1, since this will be much faster than getting
+ // all of the rows and then only returning the first.
+ $results = $this->take(1)->get($columns);
+
+ return (count($results) > 0) ? $results[0] : null;
+ }
+
+ /**
+ * Get an array with the values of a given column.
+ *
+ * @param string $column
+ * @param string $key
+ * @return array
+ */
+ public function lists($column, $key = null)
+ {
+ $columns = (is_null($key)) ? array($column) : array($column, $key);
+
+ $results = $this->get($columns);
+
+ // First we will get the array of values for the requested column.
+ // Of course, this array will simply have numeric keys. After we
+ // have this array we will determine if we need to key the array
+ // by another column from the result set.
+ $values = array_map(function($row) use ($column)
+ {
+ return $row->$column;
+
+ }, $results);
+
+ // If a key was provided, we will extract an array of keys and
+ // set the keys on the array of values using the array_combine
+ // function provided by PHP, which should give us the proper
+ // array form to return from the method.
+ if ( ! is_null($key))
+ {
+ return array_combine(array_map(function($row) use ($key)
+ {
+ return $row->$key;
+
+ }, $results), $values);
+ }
+
+ return $values;
+ }
+
+ /**
+ * Execute the query as a SELECT statement.
+ *
+ * @param array $columns
+ * @return array
+ */
+ public function get($columns = array('*'))
+ {
+ if (is_null($this->selects)) $this->select($columns);
+
+ $sql = $this->grammar->select($this);
+
+ $results = $this->connection->query($sql, $this->bindings);
+
+ // If the query has an offset and we are using the SQL Server grammar,
+ // we need to spin through the results and remove the "rownum" from
+ // each of the objects since there is no "offset".
+ if ($this->offset > 0 and $this->grammar instanceof SQLServer)
+ {
+ array_walk($results, function($result)
+ {
+ unset($result->rownum);
+ });
+ }
+
+ // Reset the SELECT clause so more queries can be performed using
+ // the same instance. This is helpful for getting aggregates and
+ // then getting actual results from the query.
+ $this->selects = null;
+
+ return $results;
+ }
+
+ /**
+ * Get an aggregate value.
+ *
+ * @param string $aggregator
+ * @param array $columns
+ * @return mixed
+ */
+ public function aggregate($aggregator, $columns)
+ {
+ // We'll set the aggregate value so the grammar does not try to compile
+ // a SELECT clause on the query. If an aggregator is present, it's own
+ // grammar function will be used to build the SQL syntax.
+ $this->aggregate = compact('aggregator', 'columns');
+
+ $sql = $this->grammar->select($this);
+
+ $result = $this->connection->only($sql, $this->bindings);
+
+ // Reset the aggregate so more queries can be performed using the same
+ // instance. This is helpful for getting aggregates and then getting
+ // actual results from the query such as during paging.
+ $this->aggregate = null;
+
+ return $result;
+ }
+
+ /**
+ * Get the paginated query results as a Paginator instance.
+ *
+ * @param int $per_page
+ * @param array $columns
+ * @return Paginator
+ */
+ public function paginate($per_page = 20, $columns = array('*'))
+ {
+ // Because some database engines may throw errors if we leave orderings
+ // on the query when retrieving the total number of records, we'll drop
+ // all of the ordreings and put them back on the query.
+ list($orderings, $this->orderings) = array($this->orderings, null);
+
+ $total = $this->count(reset($columns));
+
+ $page = Paginator::page($total, $per_page);
+
+ $this->orderings = $orderings;
+
+ // Now we're ready to get the actual pagination results from the table
+ // using the for_page and get methods. The "for_page" method provides
+ // a convenient way to set the paging limit and offset.
+ $results = $this->for_page($page, $per_page)->get($columns);
+
+ return Paginator::make($results, $total, $per_page);
+ }
+
+ /**
+ * Insert an array of values into the database table.
+ *
+ * @param array $values
+ * @return bool
+ */
+ public function insert($values)
+ {
+ // Force every insert to be treated like a batch insert to make creating
+ // the binding array simpler since we can just spin through the inserted
+ // rows as if there/ was more than one every time.
+ if ( ! is_array(reset($values))) $values = array($values);
+
+ $bindings = array();
+
+ // We need to merge the the insert values into the array of the query
+ // bindings so that they will be bound to the PDO statement when it
+ // is executed by the database connection.
+ foreach ($values as $value)
+ {
+ $bindings = array_merge($bindings, array_values($value));
+ }
+
+ $sql = $this->grammar->insert($this, $values);
+
+ return $this->connection->query($sql, $bindings);
+ }
+
+ /**
+ * Insert an array of values into the database table and return the ID.
+ *
+ * @param array $values
+ * @param string $column
+ * @return int
+ */
+ public function insert_get_id($values, $column = 'id')
+ {
+ $sql = $this->grammar->insert_get_id($this, $values, $column);
+
+ $result = $this->connection->query($sql, array_values($values));
+
+ if ($this->grammar instanceof Postgres)
+ {
+ return (int) $result[0]->$column;
+ }
+ else
+ {
+ return (int) $this->connection->pdo->lastInsertId();
+ }
+ }
+
+ /**
+ * Increment the value of a column by a given amount.
+ *
+ * @param string $column
+ * @param int $amount
+ * @return int
+ */
+ public function increment($column, $amount = 1)
+ {
+ return $this->adjust($column, $amount, ' + ');
+ }
+
+ /**
+ * Decrement the value of a column by a given amount.
+ *
+ * @param string $column
+ * @param int $amount
+ * @return int
+ */
+ public function decrement($column, $amount = 1)
+ {
+ return $this->adjust($column, $amount, ' - ');
+ }
+
+ /**
+ * Adjust the value of a column up or down by a given amount.
+ *
+ * @param string $column
+ * @param int $amount
+ * @param string $operator
+ * @return int
+ */
+ protected function adjust($column, $amount, $operator)
+ {
+ $wrapped = $this->grammar->wrap($column);
+
+ // To make the adjustment to the column, we'll wrap the expression in an
+ // Expression instance, which forces the adjustment to be injected into
+ // the query as a string instead of bound.
+ $value = Database::raw($wrapped.$operator.$amount);
+
+ return $this->update(array($column => $value));
+ }
+
+ /**
+ * Update an array of values in the database table.
+ *
+ * @param array $values
+ * @return int
+ */
+ public function update($values)
+ {
+ // For update statements, we need to merge the bindings such that the update
+ // values occur before the where bindings in the array since the sets will
+ // precede any of the where clauses in the SQL syntax that is generated.
+ $bindings = array_merge(array_values($values), $this->bindings);
+
+ $sql = $this->grammar->update($this, $values);
+
+ return $this->connection->query($sql, $bindings);
+ }
+
+ /**
+ * Execute the query as a DELETE statement.
+ *
+ * Optionally, an ID may be passed to the method do delete a specific row.
+ *
+ * @param int $id
+ * @return int
+ */
+ public function delete($id = null)
+ {
+ // If an ID is given to the method, we'll set the where clause to
+ // match on the value of the ID. This allows the developer to
+ // quickly delete a row by its primary key value.
+ if ( ! is_null($id))
+ {
+ $this->where('id', '=', $id);
+ }
+
+ $sql = $this->grammar->delete($this);
+
+ return $this->connection->query($sql, $this->bindings);
+ }
+
+ /**
+ * Magic Method for handling dynamic functions.
+ *
+ * This method handles calls to aggregates as well as dynamic where clauses.
+ */
+ public function __call($method, $parameters)
+ {
+ if (strpos($method, 'where_') === 0)
+ {
+ return $this->dynamic_where($method, $parameters, $this);
+ }
+
+ // All of the aggregate methods are handled by a single method, so we'll
+ // catch them all here and then pass them off to the agregate method
+ // instead of creating methods for each one of them.
+ if (in_array($method, array('count', 'min', 'max', 'avg', 'sum')))
+ {
+ if (count($parameters) == 0) $parameters[0] = '*';
+
+ return $this->aggregate(strtoupper($method), (array) $parameters[0]);
+ }
+
+ throw new \Exception("Method [$method] is not defined on the Query class.");
+ }
+
+}
diff --git a/laravel/database/query/grammars/grammar.php b/laravel/database/query/grammars/grammar.php
new file mode 100644
index 0000000..65c62cf
--- /dev/null
+++ b/laravel/database/query/grammars/grammar.php
@@ -0,0 +1,464 @@
+concatenate($this->components($query));
+ }
+
+ /**
+ * Generate the SQL for every component of the query.
+ *
+ * @param Query $query
+ * @return array
+ */
+ final protected function components($query)
+ {
+ // Each portion of the statement is compiled by a function corresponding
+ // to an item in the components array. This lets us to keep the creation
+ // of the query very granular and very flexible.
+ foreach ($this->components as $component)
+ {
+ if ( ! is_null($query->$component))
+ {
+ $sql[$component] = call_user_func(array($this, $component), $query);
+ }
+ }
+
+ return (array) $sql;
+ }
+
+ /**
+ * Concatenate an array of SQL segments, removing those that are empty.
+ *
+ * @param array $components
+ * @return string
+ */
+ final protected function concatenate($components)
+ {
+ return implode(' ', array_filter($components, function($value)
+ {
+ return (string) $value !== '';
+ }));
+ }
+
+ /**
+ * Compile the SELECT clause for a query.
+ *
+ * @param Query $query
+ * @return string
+ */
+ protected function selects(Query $query)
+ {
+ if ( ! is_null($query->aggregate)) return;
+
+ $select = ($query->distinct) ? 'SELECT DISTINCT ' : 'SELECT ';
+
+ return $select.$this->columnize($query->selects);
+ }
+
+ /**
+ * Compile an aggregating SELECT clause for a query.
+ *
+ * @param Query $query
+ * @return string
+ */
+ protected function aggregate(Query $query)
+ {
+ $column = $this->columnize($query->aggregate['columns']);
+
+ // If the "distinct" flag is set and we're not aggregating everything
+ // we'll set the distinct clause on the query, since this is used
+ // to count all of the distinct values in a column, etc.
+ if ($query->distinct and $column !== '*')
+ {
+ $column = 'DISTINCT '.$column;
+ }
+
+ return 'SELECT '.$query->aggregate['aggregator'].'('.$column.') AS '.$this->wrap('aggregate');
+ }
+
+ /**
+ * Compile the FROM clause for a query.
+ *
+ * @param Query $query
+ * @return string
+ */
+ protected function from(Query $query)
+ {
+ return 'FROM '.$this->wrap_table($query->from);
+ }
+
+ /**
+ * Compile the JOIN clauses for a query.
+ *
+ * @param Query $query
+ * @return string
+ */
+ protected function joins(Query $query)
+ {
+ // We need to iterate through each JOIN clause that is attached to the
+ // query an translate it into SQL. The table and the columns will be
+ // wrapped in identifiers to avoid naming collisions.
+ foreach ($query->joins as $join)
+ {
+ $table = $this->wrap_table($join->table);
+
+ $clauses = array();
+
+ // Each JOIN statement may have multiple clauses, so we will iterate
+ // through each clause creating the conditions then we'll join all
+ // of the together at the end to build the clause.
+ foreach ($join->clauses as $clause)
+ {
+ extract($clause);
+
+ $column1 = $this->wrap($column1);
+
+ $column2 = $this->wrap($column2);
+
+ $clauses[] = "{$connector} {$column1} {$operator} {$column2}";
+ }
+
+ // The first clause will have a connector on the front, but it is
+ // not needed on the first condition, so we will strip it off of
+ // the condition before adding it to the arrya of joins.
+ $search = array('AND ', 'OR ');
+
+ $clauses[0] = str_replace($search, '', $clauses[0]);
+
+ $clauses = implode(' ', $clauses);
+
+ $sql[] = "{$join->type} JOIN {$table} ON {$clauses}";
+ }
+
+ // Finally, we should have an array of JOIN clauses that we can
+ // implode together and return as the complete SQL for the
+ // join clause of the query under construction.
+ return implode(' ', $sql);
+ }
+
+ /**
+ * Compile the WHERE clause for a query.
+ *
+ * @param Query $query
+ * @return string
+ */
+ final protected function wheres(Query $query)
+ {
+ if (is_null($query->wheres)) return '';
+
+ // Each WHERE clause array has a "type" that is assigned by the query
+ // builder, and each type has its own compiler function. We will call
+ // the appropriate compiler for each where clause.
+ foreach ($query->wheres as $where)
+ {
+ $sql[] = $where['connector'].' '.$this->{$where['type']}($where);
+ }
+
+ if (isset($sql))
+ {
+ // We attach the boolean connector to every where segment just
+ // for convenience. Once we have built the entire clause we'll
+ // remove the first instance of a connector.
+ return 'WHERE '.preg_replace('/AND |OR /', '', implode(' ', $sql), 1);
+ }
+ }
+
+ /**
+ * Compile a nested WHERE clause.
+ *
+ * @param array $where
+ * @return string
+ */
+ protected function where_nested($where)
+ {
+ return '('.substr($this->wheres($where['query']), 6).')';
+ }
+
+ /**
+ * Compile a simple WHERE clause.
+ *
+ * @param array $where
+ * @return string
+ */
+ protected function where($where)
+ {
+ $parameter = $this->parameter($where['value']);
+
+ return $this->wrap($where['column']).' '.$where['operator'].' '.$parameter;
+ }
+
+ /**
+ * Compile a WHERE IN clause.
+ *
+ * @param array $where
+ * @return string
+ */
+ protected function where_in($where)
+ {
+ $parameters = $this->parameterize($where['values']);
+
+ return $this->wrap($where['column']).' IN ('.$parameters.')';
+ }
+
+ /**
+ * Compile a WHERE NOT IN clause.
+ *
+ * @param array $where
+ * @return string
+ */
+ protected function where_not_in($where)
+ {
+ $parameters = $this->parameterize($where['values']);
+
+ return $this->wrap($where['column']).' NOT IN ('.$parameters.')';
+ }
+
+ /**
+ * Compile a WHERE NULL clause.
+ *
+ * @param array $where
+ * @return string
+ */
+ protected function where_null($where)
+ {
+ return $this->wrap($where['column']).' IS NULL';
+ }
+
+ /**
+ * Compile a WHERE NULL clause.
+ *
+ * @param array $where
+ * @return string
+ */
+ protected function where_not_null($where)
+ {
+ return $this->wrap($where['column']).' IS NOT NULL';
+ }
+
+ /**
+ * Compile a raw WHERE clause.
+ *
+ * @param array $where
+ * @return string
+ */
+ final protected function where_raw($where)
+ {
+ return $where['sql'];
+ }
+
+ /**
+ * Compile the GROUP BY clause for a query.
+ *
+ * @param Query $query
+ * @return string
+ */
+ protected function groupings(Query $query)
+ {
+ return 'GROUP BY '.$this->columnize($query->groupings);
+ }
+
+ /**
+ * Compile the HAVING clause for a query.
+ *
+ * @param Query $query
+ * @return string
+ */
+ protected function havings(Query $query)
+ {
+ if (is_null($query->havings)) return '';
+
+ foreach ($query->havings as $having)
+ {
+ $sql[] = 'AND '.$this->wrap($having['column']).' '.$having['operator'].' '.$this->parameter($having['value']);
+ }
+
+ return 'HAVING '.preg_replace('/AND /', '', implode(' ', $sql), 1);
+ }
+
+ /**
+ * Compile the ORDER BY clause for a query.
+ *
+ * @param Query $query
+ * @return string
+ */
+ protected function orderings(Query $query)
+ {
+ foreach ($query->orderings as $ordering)
+ {
+ $sql[] = $this->wrap($ordering['column']).' '.strtoupper($ordering['direction']);
+ }
+
+ return 'ORDER BY '.implode(', ', $sql);
+ }
+
+ /**
+ * Compile the LIMIT clause for a query.
+ *
+ * @param Query $query
+ * @return string
+ */
+ protected function limit(Query $query)
+ {
+ return 'LIMIT '.$query->limit;
+ }
+
+ /**
+ * Compile the OFFSET clause for a query.
+ *
+ * @param Query $query
+ * @return string
+ */
+ protected function offset(Query $query)
+ {
+ return 'OFFSET '.$query->offset;
+ }
+
+ /**
+ * Compile a SQL INSERT statment from a Query instance.
+ *
+ * This method handles the compilation of single row inserts and batch inserts.
+ *
+ * @param Query $query
+ * @param array $values
+ * @return string
+ */
+ public function insert(Query $query, $values)
+ {
+ $table = $this->wrap_table($query->from);
+
+ // Force every insert to be treated like a batch insert. This simply makes
+ // creating the SQL syntax a little easier on us since we can always treat
+ // the values as if it contains multiple inserts.
+ if ( ! is_array(reset($values))) $values = array($values);
+
+ // Since we only care about the column names, we can pass any of the insert
+ // arrays into the "columnize" method. The columns should be the same for
+ // every record inserted into the table.
+ $columns = $this->columnize(array_keys(reset($values)));
+
+ // Build the list of parameter place-holders of values bound to the query.
+ // Each insert should have the same number of bound paramters, so we can
+ // just use the first array of values.
+ $parameters = $this->parameterize(reset($values));
+
+ $parameters = implode(', ', array_fill(0, count($values), "($parameters)"));
+
+ return "INSERT INTO {$table} ({$columns}) VALUES {$parameters}";
+ }
+
+ /**
+ * Compile a SQL INSERT and get ID statment from a Query instance.
+ *
+ * @param Query $query
+ * @param array $values
+ * @param string $column
+ * @return string
+ */
+ public function insert_get_id(Query $query, $values, $column)
+ {
+ return $this->insert($query, $values);
+ }
+
+ /**
+ * Compile a SQL UPDATE statment from a Query instance.
+ *
+ * @param Query $query
+ * @param array $values
+ * @return string
+ */
+ public function update(Query $query, $values)
+ {
+ $table = $this->wrap_table($query->from);
+
+ // Each column in the UPDATE statement needs to be wrapped in the keyword
+ // identifiers, and a place-holder needs to be created for each value in
+ // the array of bindings, so we'll build the sets first.
+ foreach ($values as $column => $value)
+ {
+ $columns[] = $this->wrap($column).' = '.$this->parameter($value);
+ }
+
+ $columns = implode(', ', $columns);
+
+ // UPDATE statements may be constrained by a WHERE clause, so we'll run
+ // the entire where compilation process for those contraints. This is
+ // easily achieved by passing it to the "wheres" method.
+ return trim("UPDATE {$table} SET {$columns} ".$this->wheres($query));
+ }
+
+ /**
+ * Compile a SQL DELETE statment from a Query instance.
+ *
+ * @param Query $query
+ * @return string
+ */
+ public function delete(Query $query)
+ {
+ $table = $this->wrap_table($query->from);
+
+ return trim("DELETE FROM {$table} ".$this->wheres($query));
+ }
+
+ /**
+ * Transform an SQL short-cuts into real SQL for PDO.
+ *
+ * @param string $sql
+ * @param array $bindings
+ * @return string
+ */
+ public function shortcut($sql, &$bindings)
+ {
+ // Laravel provides an easy short-cut notation for writing raw WHERE IN
+ // statements. If (...) is in the query, it will be replaced with the
+ // correct number of parameters based on the query bindings.
+ if (strpos($sql, '(...)') !== false)
+ {
+ for ($i = 0; $i < count($bindings); $i++)
+ {
+ // If the binding is an array, we can just assume it's used to fill a
+ // where in condition, so we'll just replace the next place-holder
+ // in the query with the constraint and splice the bindings.
+ if (is_array($bindings[$i]))
+ {
+ $parameters = $this->parameterize($bindings[$i]);
+
+ array_splice($bindings, $i, 1, $bindings[$i]);
+
+ $sql = preg_replace('~\(\.\.\.\)~', "({$parameters})", $sql, 1);
+ }
+ }
+ }
+
+ return trim($sql);
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/query/grammars/mysql.php b/laravel/database/query/grammars/mysql.php
new file mode 100644
index 0000000..37692e0
--- /dev/null
+++ b/laravel/database/query/grammars/mysql.php
@@ -0,0 +1,12 @@
+insert($query, $values)." RETURNING $column";
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/query/grammars/sqlite.php b/laravel/database/query/grammars/sqlite.php
new file mode 100644
index 0000000..cacc936
--- /dev/null
+++ b/laravel/database/query/grammars/sqlite.php
@@ -0,0 +1,24 @@
+orderings as $ordering)
+ {
+ $sql[] = $this->wrap($ordering['column']).' COLLATE NOCASE '.strtoupper($ordering['direction']);
+ }
+
+ return 'ORDER BY '.implode(', ', $sql);
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/query/grammars/sqlserver.php b/laravel/database/query/grammars/sqlserver.php
new file mode 100644
index 0000000..def519a
--- /dev/null
+++ b/laravel/database/query/grammars/sqlserver.php
@@ -0,0 +1,140 @@
+offset > 0)
+ {
+ return $this->ansi_offset($query, $sql);
+ }
+
+ // Once all of the clauses have been compiled, we can join them all as
+ // one statement. Any segments that are null or an empty string will
+ // be removed from the array before imploding.
+ return $this->concatenate($sql);
+ }
+
+ /**
+ * Compile the SELECT clause for a query.
+ *
+ * @param Query $query
+ * @return string
+ */
+ protected function selects(Query $query)
+ {
+ if ( ! is_null($query->aggregate)) return;
+
+ $select = ($query->distinct) ? 'SELECT DISTINCT ' : 'SELECT ';
+
+ // Instead of using a "LIMIT" keyword, SQL Server uses the TOP keyword
+ // within the SELECT statement. So, if we have a limit, we will add
+ // it to the query here if there is not an OFFSET present.
+ if ($query->limit > 0 and $query->offset <= 0)
+ {
+ $select .= 'TOP '.$query->limit.' ';
+ }
+
+ return $select.$this->columnize($query->selects);
+ }
+
+ /**
+ * Generate the ANSI standard SQL for an offset clause.
+ *
+ * @param Query $query
+ * @param array $components
+ * @return array
+ */
+ protected function ansi_offset(Query $query, $components)
+ {
+ // An ORDER BY clause is required to make this offset query work, so if
+ // one doesn't exist, we'll just create a dummy clause to trick the
+ // database and pacify it so it doesn't complain about the query.
+ if ( ! isset($components['orderings']))
+ {
+ $components['orderings'] = 'ORDER BY (SELECT 0)';
+ }
+
+ // We need to add the row number to the query so we can compare it to
+ // the offset and limit values given for the statement. So we'll add
+ // an expression to the select for the row number.
+ $orderings = $components['orderings'];
+
+ $components['selects'] .= ", ROW_NUMBER() OVER ({$orderings}) AS RowNum";
+
+ unset($components['orderings']);
+
+ $start = $query->offset + 1;
+
+ // Next we need to calculate the constraint that should be placed on
+ // the row number to get the correct offset and limit on the query.
+ // If there is not limit, we'll just handle the offset.
+ if ($query->limit > 0)
+ {
+ $finish = $query->offset + $query->limit;
+
+ $constraint = "BETWEEN {$start} AND {$finish}";
+ }
+ else
+ {
+ $constraint = ">= {$start}";
+ }
+
+ // We're finally ready to build the final SQL query so we'll create
+ // a common table expression with the query and select all of the
+ // results with row numbers between the limit and offset.
+ $sql = $this->concatenate($components);
+
+ return "SELECT * FROM ($sql) AS TempTable WHERE RowNum {$constraint}";
+ }
+
+ /**
+ * Compile the LIMIT clause for a query.
+ *
+ * @param Query $query
+ * @return string
+ */
+ protected function limit(Query $query)
+ {
+ return '';
+ }
+
+ /**
+ * Compile the OFFSET clause for a query.
+ *
+ * @param Query $query
+ * @return string
+ */
+ protected function offset(Query $query)
+ {
+ return '';
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/query/join.php b/laravel/database/query/join.php
new file mode 100644
index 0000000..ff3c014
--- /dev/null
+++ b/laravel/database/query/join.php
@@ -0,0 +1,68 @@
+type = $type;
+ $this->table = $table;
+ }
+
+ /**
+ * Add an ON clause to the join.
+ *
+ * @param string $column1
+ * @param string $operator
+ * @param string $column2
+ * @param string $connector
+ * @return Join
+ */
+ public function on($column1, $operator, $column2, $connector = 'AND')
+ {
+ $this->clauses[] = compact('column1', 'operator', 'column2', 'connector');
+
+ return $this;
+ }
+
+ /**
+ * Add an OR ON clause to the join.
+ *
+ * @param string $column1
+ * @param string $operator
+ * @param string $column2
+ * @return Join
+ */
+ public function or_on($column1, $operator, $column2)
+ {
+ return $this->on($column1, $operator, $column2, 'OR');
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/schema.php b/laravel/database/schema.php
new file mode 100644
index 0000000..c7e5630
--- /dev/null
+++ b/laravel/database/schema.php
@@ -0,0 +1,174 @@
+create();
+
+ call_user_func($callback, $table);
+
+ return static::execute($table);
+ }
+
+ /**
+ * Drop a database table from the schema.
+ *
+ * @param string $table
+ * @param string $connection
+ * @return void
+ */
+ public static function drop($table, $connection = null)
+ {
+ $table = new Schema\Table($table);
+
+ $table->on($connection);
+
+ // To indicate that the table needs to be dropped, we will run the
+ // "drop" command on the table instance and pass the instance to
+ // the execute method as calling a Closure isn't needed.
+ $table->drop();
+
+ return static::execute($table);
+ }
+
+ /**
+ * Execute the given schema operation against the database.
+ *
+ * @param Schema\Table $table
+ * @return void
+ */
+ public static function execute($table)
+ {
+ // The implications method is responsible for finding any fluently
+ // defined indexes on the schema table and adding the explicit
+ // commands that are needed to tbe schema instance.
+ static::implications($table);
+
+ foreach ($table->commands as $command)
+ {
+ $connection = DB::connection($table->connection);
+
+ $grammar = static::grammar($connection);
+
+ // Each grammar has a function that corresponds to the command type and
+ // is for building that command's SQL. This lets the SQL syntax builds
+ // stay granular across various database systems.
+ if (method_exists($grammar, $method = $command->type))
+ {
+ $statements = $grammar->$method($table, $command);
+
+ // Once we have the statements, we will cast them to an array even
+ // though not all of the commands return an array just in case it
+ // needs multiple queries to complete.
+ foreach ((array) $statements as $statement)
+ {
+ $connection->query($statement);
+ }
+ }
+ }
+ }
+
+ /**
+ * Add any implicit commands to the schema table operation.
+ *
+ * @param Schema\Table $table
+ * @return void
+ */
+ protected static function implications($table)
+ {
+ // If the developer has specified columns for the table and the table is
+ // not being created, we'll assume they simply want to add the columns
+ // to the table and generate the add command.
+ if (count($table->columns) > 0 and ! $table->creating())
+ {
+ $command = new Fluent(array('type' => 'add'));
+
+ array_unshift($table->commands, $command);
+ }
+
+ // For some extra syntax sugar, we'll check for any implicit indexes
+ // on the table since the developer may specify the index type on
+ // the fluent column declaration for convenience.
+ foreach ($table->columns as $column)
+ {
+ foreach (array('primary', 'unique', 'fulltext', 'index') as $key)
+ {
+ if (isset($column->$key))
+ {
+ if ($column->$key === true)
+ {
+ $table->$key($column->name);
+ }
+ else
+ {
+ $table->$key($column->name, $column->$key);
+ }
+ }
+ }
+ }
+ }
+
+ /**
+ * Create the appropriate schema grammar for the driver.
+ *
+ * @param Connection $connection
+ * @return Grammar
+ */
+ public static function grammar(Connection $connection)
+ {
+ $driver = $connection->driver();
+
+ if (isset(\Laravel\Database::$registrar[$driver]))
+ {
+ return \Laravel\Database::$registrar[$driver]['schema']();
+ }
+
+ switch ($driver)
+ {
+ case 'mysql':
+ return new Schema\Grammars\MySQL($connection);
+
+ case 'pgsql':
+ return new Schema\Grammars\Postgres($connection);
+
+ case 'sqlsrv':
+ return new Schema\Grammars\SQLServer($connection);
+
+ case 'sqlite':
+ return new Schema\Grammars\SQLite($connection);
+ }
+
+ throw new \Exception("Schema operations not supported for [$driver].");
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/schema/grammars/grammar.php b/laravel/database/schema/grammars/grammar.php
new file mode 100644
index 0000000..1d3390a
--- /dev/null
+++ b/laravel/database/schema/grammars/grammar.php
@@ -0,0 +1,99 @@
+name;
+
+ // We need to wrap both of the table names in quoted identifiers to protect
+ // against any possible keyword collisions, both the table on which the
+ // command is being executed and the referenced table are wrapped.
+ $table = $this->wrap($table);
+
+ $on = $this->wrap($command->on);
+
+ // Next we need to columnize both the command table's columns as well as
+ // the columns referenced by the foreign key. We'll cast the referenced
+ // columns to an array since they aren't by the fluent command.
+ $foreign = $this->columnize($command->columns);
+
+ $referenced = $this->columnize((array) $command->references);
+
+ $sql = "ALTER TABLE $table ADD CONSTRAINT $name ";
+
+ $sql .= "FOREIGN KEY ($foreign) REFERENCES $on ($referenced)";
+
+ // Finally we will check for any "on delete" or "on update" options for
+ // the foreign key. These control the behavior of the constraint when
+ // an update or delete statement is run against the record.
+ if ( ! is_null($command->on_delete))
+ {
+ $sql .= " ON DELETE {$command->on_delete}";
+ }
+
+ if ( ! is_null($command->on_update))
+ {
+ $sql .= " ON UPDATE {$command->on_update}";
+ }
+
+ return $sql;
+ }
+
+ /**
+ * Drop a constraint from the table.
+ *
+ * @param Table $table
+ * @param Fluent $fluent
+ * @return string
+ */
+ protected function drop_constraint(Table $table, Fluent $command)
+ {
+ return "ALTER TABLE ".$this->wrap($table)." DROP CONSTRAINT ".$command->name;
+ }
+
+ /**
+ * Wrap a value in keyword identifiers.
+ *
+ * @param Table|string $value
+ * @return string
+ */
+ public function wrap($value)
+ {
+ // This method is primarily for convenience so we can just pass a
+ // column or table instance into the wrap method without sending
+ // in the name each time we need to wrap one of these objects.
+ if ($value instanceof Table)
+ {
+ return $this->wrap_table($value->name);
+ }
+ elseif ($value instanceof Fluent)
+ {
+ $value = $value->name;
+ }
+
+ return parent::wrap($value);
+ }
+
+ /**
+ * Get the appropriate data type definition for the column.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type(Fluent $column)
+ {
+ return $this->{'type_'.$column->type}($column);
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/schema/grammars/mysql.php b/laravel/database/schema/grammars/mysql.php
new file mode 100644
index 0000000..c2ae745
--- /dev/null
+++ b/laravel/database/schema/grammars/mysql.php
@@ -0,0 +1,421 @@
+columns($table));
+
+ // First we will generate the base table creation statement. Other than auto
+ // incrementing keys, no indexes will be created during the first creation
+ // of the table as they're added in separate commands.
+ $sql = 'CREATE TABLE '.$this->wrap($table).' ('.$columns.')';
+
+ if ( ! is_null($table->engine))
+ {
+ $sql .= ' ENGINE = '.$table->engine;
+ }
+
+ return $sql;
+ }
+
+ /**
+ * Geenrate the SQL statements for a table modification command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return array
+ */
+ public function add(Table $table, Fluent $command)
+ {
+ $columns = $this->columns($table);
+
+ // Once we the array of column definitions, we need to add "add" to the
+ // front of each definition, then we'll concatenate the definitions
+ // using commas like normal and generate the SQL.
+ $columns = implode(', ', array_map(function($column)
+ {
+ return 'ADD '.$column;
+
+ }, $columns));
+
+ return 'ALTER TABLE '.$this->wrap($table).' '.$columns;
+ }
+
+ /**
+ * Create the individual column definitions for the table.
+ *
+ * @param Table $table
+ * @return array
+ */
+ protected function columns(Table $table)
+ {
+ $columns = array();
+
+ foreach ($table->columns as $column)
+ {
+ // Each of the data type's have their own definition creation method,
+ // which is responsible for creating the SQL for the type. This lets
+ // us to keep the syntax easy and fluent, while translating the
+ // types to the correct types.
+ $sql = $this->wrap($column).' '.$this->type($column);
+
+ $elements = array('unsigned', 'nullable', 'defaults', 'incrementer');
+
+ foreach ($elements as $element)
+ {
+ $sql .= $this->$element($table, $column);
+ }
+
+ $columns[] = $sql;
+ }
+
+ return $columns;
+ }
+
+ /**
+ * Get the SQL syntax for indicating if a column is unsigned.
+ *
+ * @param Table $table
+ * @param Fluent $column
+ * @return string
+ */
+ protected function unsigned(Table $table, Fluent $column)
+ {
+ if ($column->type == 'integer' && $column->unsigned)
+ {
+ return ' UNSIGNED';
+ }
+ }
+
+ /**
+ * Get the SQL syntax for indicating if a column is nullable.
+ *
+ * @param Table $table
+ * @param Fluent $column
+ * @return string
+ */
+ protected function nullable(Table $table, Fluent $column)
+ {
+ return ($column->nullable) ? ' NULL' : ' NOT NULL';
+ }
+
+ /**
+ * Get the SQL syntax for specifying a default value on a column.
+ *
+ * @param Table $table
+ * @param Fluent $column
+ * @return string
+ */
+ protected function defaults(Table $table, Fluent $column)
+ {
+ if ( ! is_null($column->default))
+ {
+ return " DEFAULT '".$column->default."'";
+ }
+ }
+
+ /**
+ * Get the SQL syntax for defining an auto-incrementing column.
+ *
+ * @param Table $table
+ * @param Fluent $column
+ * @return string
+ */
+ protected function incrementer(Table $table, Fluent $column)
+ {
+ if ($column->type == 'integer' and $column->increment)
+ {
+ return ' AUTO_INCREMENT PRIMARY KEY';
+ }
+ }
+
+ /**
+ * Generate the SQL statement for creating a primary key.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function primary(Table $table, Fluent $command)
+ {
+ return $this->key($table, $command->name(null), 'PRIMARY KEY');
+ }
+
+ /**
+ * Generate the SQL statement for creating a unique index.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function unique(Table $table, Fluent $command)
+ {
+ return $this->key($table, $command, 'UNIQUE');
+ }
+
+ /**
+ * Generate the SQL statement for creating a full-text index.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function fulltext(Table $table, Fluent $command)
+ {
+ return $this->key($table, $command, 'FULLTEXT');
+ }
+
+ /**
+ * Generate the SQL statement for creating a regular index.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function index(Table $table, Fluent $command)
+ {
+ return $this->key($table, $command, 'INDEX');
+ }
+
+ /**
+ * Generate the SQL statement for creating a new index.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @param string $type
+ * @return string
+ */
+ protected function key(Table $table, Fluent $command, $type)
+ {
+ $keys = $this->columnize($command->columns);
+
+ $name = $command->name;
+
+ return 'ALTER TABLE '.$this->wrap($table)." ADD {$type} {$name}({$keys})";
+ }
+
+ /**
+ * Generate the SQL statement for a drop table command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function drop(Table $table, Fluent $command)
+ {
+ return 'DROP TABLE '.$this->wrap($table);
+ }
+
+ /**
+ * Generate the SQL statement for a drop column command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function drop_column(Table $table, Fluent $command)
+ {
+ $columns = array_map(array($this, 'wrap'), $command->columns);
+
+ // Once we the array of column names, we need to add "drop" to the front
+ // of each column, then we'll concatenate the columns using commas and
+ // generate the alter statement SQL.
+ $columns = implode(', ', array_map(function($column)
+ {
+ return 'DROP '.$column;
+
+ }, $columns));
+
+ return 'ALTER TABLE '.$this->wrap($table).' '.$columns;
+ }
+
+ /**
+ * Generate the SQL statement for a drop primary key command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function drop_primary(Table $table, Fluent $command)
+ {
+ return 'ALTER TABLE '.$this->wrap($table).' DROP PRIMARY KEY';
+ }
+
+ /**
+ * Generate the SQL statement for a drop unqique key command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function drop_unique(Table $table, Fluent $command)
+ {
+ return $this->drop_key($table, $command);
+ }
+
+ /**
+ * Generate the SQL statement for a drop full-text key command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function drop_fulltext(Table $table, Fluent $command)
+ {
+ return $this->drop_key($table, $command);
+ }
+
+ /**
+ * Generate the SQL statement for a drop unqique key command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function drop_index(Table $table, Fluent $command)
+ {
+ return $this->drop_key($table, $command);
+ }
+
+ /**
+ * Generate the SQL statement for a drop key command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ protected function drop_key(Table $table, Fluent $command)
+ {
+ return 'ALTER TABLE '.$this->wrap($table)." DROP INDEX {$command->name}";
+ }
+
+ /**
+ * Drop a foreign key constraint from the table.
+ *
+ * @param Table $table
+ * @param Fluent $fluent
+ * @return string
+ */
+ public function drop_foreign(Table $table, Fluent $command)
+ {
+ return "ALTER TABLE ".$this->wrap($table)." DROP FOREIGN KEY ".$command->name;
+ }
+
+ /**
+ * Generate the data-type definition for a string.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_string(Fluent $column)
+ {
+ return 'VARCHAR('.$column->length.')';
+ }
+
+ /**
+ * Generate the data-type definition for an integer.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_integer(Fluent $column)
+ {
+ return 'INT';
+ }
+
+ /**
+ * Generate the data-type definition for an integer.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_float(Fluent $column)
+ {
+ return 'FLOAT';
+ }
+
+ /**
+ * Generate the data-type definintion for a decimal.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_decimal(Fluent $column)
+ {
+ return "DECIMAL({$column->precision}, {$column->scale})";
+ }
+
+ /**
+ * Generate the data-type definition for a boolean.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_boolean(Fluent $column)
+ {
+ return 'TINYINT';
+ }
+
+ /**
+ * Generate the data-type definition for a date.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_date(Fluent $column)
+ {
+ return 'DATETIME';
+ }
+
+ /**
+ * Generate the data-type definition for a timestamp.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_timestamp(Fluent $column)
+ {
+ return 'TIMESTAMP';
+ }
+
+ /**
+ * Generate the data-type definition for a text column.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_text(Fluent $column)
+ {
+ return 'TEXT';
+ }
+
+ /**
+ * Generate the data-type definition for a blob.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_blob(Fluent $column)
+ {
+ return 'BLOB';
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/schema/grammars/postgres.php b/laravel/database/schema/grammars/postgres.php
new file mode 100644
index 0000000..930c516
--- /dev/null
+++ b/laravel/database/schema/grammars/postgres.php
@@ -0,0 +1,407 @@
+columns($table));
+
+ // First we will generate the base table creation statement. Other than auto
+ // incrementing keys, no indexes will be created during the first creation
+ // of the table as they're added in separate commands.
+ $sql = 'CREATE TABLE '.$this->wrap($table).' ('.$columns.')';
+
+ return $sql;
+ }
+
+ /**
+ * Geenrate the SQL statements for a table modification command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return array
+ */
+ public function add(Table $table, Fluent $command)
+ {
+ $columns = $this->columns($table);
+
+ // Once we the array of column definitions, we need to add "add" to the
+ // front of each definition, then we'll concatenate the definitions
+ // using commas like normal and generate the SQL.
+ $columns = implode(', ', array_map(function($column)
+ {
+ return 'ADD COLUMN '.$column;
+
+ }, $columns));
+
+ return 'ALTER TABLE '.$this->wrap($table).' '.$columns;
+ }
+
+ /**
+ * Create the individual column definitions for the table.
+ *
+ * @param Table $table
+ * @return array
+ */
+ protected function columns(Table $table)
+ {
+ $columns = array();
+
+ foreach ($table->columns as $column)
+ {
+ // Each of the data type's have their own definition creation method,
+ // which is responsible for creating the SQL for the type. This lets
+ // us to keep the syntax easy and fluent, while translating the
+ // types to the types used by the database.
+ $sql = $this->wrap($column).' '.$this->type($column);
+
+ $elements = array('incrementer', 'nullable', 'defaults');
+
+ foreach ($elements as $element)
+ {
+ $sql .= $this->$element($table, $column);
+ }
+
+ $columns[] = $sql;
+ }
+
+ return $columns;
+ }
+
+ /**
+ * Get the SQL syntax for indicating if a column is nullable.
+ *
+ * @param Table $table
+ * @param Fluent $column
+ * @return string
+ */
+ protected function nullable(Table $table, Fluent $column)
+ {
+ return ($column->nullable) ? ' NULL' : ' NOT NULL';
+ }
+
+ /**
+ * Get the SQL syntax for specifying a default value on a column.
+ *
+ * @param Table $table
+ * @param Fluent $column
+ * @return string
+ */
+ protected function defaults(Table $table, Fluent $column)
+ {
+ if ( ! is_null($column->default))
+ {
+ return " DEFAULT '".$column->default."'";
+ }
+ }
+
+ /**
+ * Get the SQL syntax for defining an auto-incrementing column.
+ *
+ * @param Table $table
+ * @param Fluent $column
+ * @return string
+ */
+ protected function incrementer(Table $table, Fluent $column)
+ {
+ // We don't actually need to specify an "auto_increment" keyword since we
+ // handle the auto-increment definition in the type definition for
+ // integers by changing the type to "serial".
+ if ($column->type == 'integer' and $column->increment)
+ {
+ return ' PRIMARY KEY';
+ }
+ }
+
+ /**
+ * Generate the SQL statement for creating a primary key.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function primary(Table $table, Fluent $command)
+ {
+ $columns = $this->columnize($command->columns);
+
+ return 'ALTER TABLE '.$this->wrap($table)." ADD PRIMARY KEY ({$columns})";
+ }
+
+ /**
+ * Generate the SQL statement for creating a unique index.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function unique(Table $table, Fluent $command)
+ {
+ $table = $this->wrap($table);
+
+ $columns = $this->columnize($command->columns);
+
+ return "ALTER TABLE $table ADD CONSTRAINT ".$command->name." UNIQUE ($columns)";
+ }
+
+ /**
+ * Generate the SQL statement for creating a full-text index.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function fulltext(Table $table, Fluent $command)
+ {
+ $name = $command->name;
+
+ $columns = $this->columnize($command->columns);
+
+ return "CREATE INDEX {$name} ON ".$this->wrap($table)." USING gin({$columns})";
+ }
+
+ /**
+ * Generate the SQL statement for creating a regular index.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function index(Table $table, Fluent $command)
+ {
+ return $this->key($table, $command);
+ }
+
+ /**
+ * Generate the SQL statement for creating a new index.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @param bool $unique
+ * @return string
+ */
+ protected function key(Table $table, Fluent $command, $unique = false)
+ {
+ $columns = $this->columnize($command->columns);
+
+ $create = ($unique) ? 'CREATE UNIQUE' : 'CREATE';
+
+ return $create." INDEX {$command->name} ON ".$this->wrap($table)." ({$columns})";
+ }
+
+ /**
+ * Generate the SQL statement for a drop table command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function drop(Table $table, Fluent $command)
+ {
+ return 'DROP TABLE '.$this->wrap($table);
+ }
+
+ /**
+ * Generate the SQL statement for a drop column command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function drop_column(Table $table, Fluent $command)
+ {
+ $columns = array_map(array($this, 'wrap'), $command->columns);
+
+ // Once we the array of column names, we need to add "drop" to the front
+ // of each column, then we'll concatenate the columns using commas and
+ // generate the alter statement SQL.
+ $columns = implode(', ', array_map(function($column)
+ {
+ return 'DROP COLUMN '.$column;
+
+ }, $columns));
+
+ return 'ALTER TABLE '.$this->wrap($table).' '.$columns;
+ }
+
+ /**
+ * Generate the SQL statement for a drop primary key command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function drop_primary(Table $table, Fluent $command)
+ {
+ return 'ALTER TABLE '.$this->wrap($table).' DROP CONSTRAINT '.$table->name.'_pkey';
+ }
+
+ /**
+ * Generate the SQL statement for a drop unqique key command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function drop_unique(Table $table, Fluent $command)
+ {
+ return $this->drop_constraint($table, $command);
+ }
+
+ /**
+ * Generate the SQL statement for a drop full-text key command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function drop_fulltext(Table $table, Fluent $command)
+ {
+ return $this->drop_key($table, $command);
+ }
+
+ /**
+ * Generate the SQL statement for a drop index command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function drop_index(Table $table, Fluent $command)
+ {
+ return $this->drop_key($table, $command);
+ }
+
+ /**
+ * Generate the SQL statement for a drop key command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ protected function drop_key(Table $table, Fluent $command)
+ {
+ return 'DROP INDEX '.$command->name;
+ }
+
+ /**
+ * Drop a foreign key constraint from the table.
+ *
+ * @param Table $table
+ * @param Fluent $fluent
+ * @return string
+ */
+ public function drop_foreign(Table $table, Fluent $command)
+ {
+ return $this->drop_constraint($table, $command);
+ }
+
+ /**
+ * Generate the data-type definition for a string.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_string(Fluent $column)
+ {
+ return 'VARCHAR('.$column->length.')';
+ }
+
+ /**
+ * Generate the data-type definition for an integer.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_integer(Fluent $column)
+ {
+ return ($column->increment) ? 'SERIAL' : 'BIGINT';
+ }
+
+ /**
+ * Generate the data-type definition for an integer.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_float(Fluent $column)
+ {
+ return 'REAL';
+ }
+
+ /**
+ * Generate the data-type definintion for a decimal.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_decimal(Fluent $column)
+ {
+ return "DECIMAL({$column->precision}, {$column->scale})";
+ }
+
+ /**
+ * Generate the data-type definition for a boolean.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_boolean(Fluent $column)
+ {
+ return 'SMALLINT';
+ }
+
+ /**
+ * Generate the data-type definition for a date.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_date(Fluent $column)
+ {
+ return 'TIMESTAMP(0) WITHOUT TIME ZONE';
+ }
+
+ /**
+ * Generate the data-type definition for a timestamp.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_timestamp(Fluent $column)
+ {
+ return 'TIMESTAMP';
+ }
+
+ /**
+ * Generate the data-type definition for a text column.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_text(Fluent $column)
+ {
+ return 'TEXT';
+ }
+
+ /**
+ * Generate the data-type definition for a blob.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_blob(Fluent $column)
+ {
+ return 'BYTEA';
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/schema/grammars/sqlite.php b/laravel/database/schema/grammars/sqlite.php
new file mode 100644
index 0000000..09102f5
--- /dev/null
+++ b/laravel/database/schema/grammars/sqlite.php
@@ -0,0 +1,351 @@
+columns($table));
+
+ // First we will generate the base table creation statement. Other than incrementing
+ // keys, no indexes will be created during the first creation of the table since
+ // they will be added in separate commands.
+ $sql = 'CREATE TABLE '.$this->wrap($table).' ('.$columns;
+
+ // SQLite does not allow adding a primary key as a command apart from the creation
+ // of the table, so we'll need to sniff out any primary keys here and add them to
+ // the table now during this command.
+ $primary = array_first($table->commands, function($key, $value)
+ {
+ return $value->type == 'primary';
+ });
+
+ // If we found primary key in the array of commands, we'll create the SQL for
+ // the key addition and append it to the SQL table creation statement for
+ // the schema table so the index is properly generated.
+ if ( ! is_null($primary))
+ {
+ $columns = $this->columnize($primary->columns);
+
+ $sql .= ", PRIMARY KEY ({$columns})";
+ }
+
+ return $sql .= ')';
+ }
+
+ /**
+ * Geenrate the SQL statements for a table modification command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return array
+ */
+ public function add(Table $table, Fluent $command)
+ {
+ $columns = $this->columns($table);
+
+ // Once we the array of column definitions, we need to add "add" to the
+ // front of each definition, then we'll concatenate the definitions
+ // using commas like normal and generate the SQL.
+ $columns = array_map(function($column)
+ {
+ return 'ADD COLUMN '.$column;
+
+ }, $columns);
+
+ // SQLite only allows one column to be added in an ALTER statement,
+ // so we will create an array of statements and return them all to
+ // the schema manager for separate execution.
+ foreach ($columns as $column)
+ {
+ $sql[] = 'ALTER TABLE '.$this->wrap($table).' '.$column;
+ }
+
+ return (array) $sql;
+ }
+
+ /**
+ * Create the individual column definitions for the table.
+ *
+ * @param Table $table
+ * @return array
+ */
+ protected function columns(Table $table)
+ {
+ $columns = array();
+
+ foreach ($table->columns as $column)
+ {
+ // Each of the data type's have their own definition creation method
+ // which is responsible for creating the SQL for the type. This lets
+ // us to keep the syntax easy and fluent, while translating the
+ // types to the types used by the database.
+ $sql = $this->wrap($column).' '.$this->type($column);
+
+ $elements = array('nullable', 'defaults', 'incrementer');
+
+ foreach ($elements as $element)
+ {
+ $sql .= $this->$element($table, $column);
+ }
+
+ $columns[] = $sql;
+ }
+
+ return $columns;
+ }
+
+ /**
+ * Get the SQL syntax for indicating if a column is nullable.
+ *
+ * @param Table $table
+ * @param Fluent $column
+ * @return string
+ */
+ protected function nullable(Table $table, Fluent $column)
+ {
+ return ' NULL';
+ }
+
+ /**
+ * Get the SQL syntax for specifying a default value on a column.
+ *
+ * @param Table $table
+ * @param Fluent $column
+ * @return string
+ */
+ protected function defaults(Table $table, Fluent $column)
+ {
+ if ( ! is_null($column->default))
+ {
+ return ' DEFAULT '.$this->wrap($column->default);
+ }
+ }
+
+ /**
+ * Get the SQL syntax for defining an auto-incrementing column.
+ *
+ * @param Table $table
+ * @param Fluent $column
+ * @return string
+ */
+ protected function incrementer(Table $table, Fluent $column)
+ {
+ if ($column->type == 'integer' and $column->increment)
+ {
+ return ' PRIMARY KEY AUTOINCREMENT';
+ }
+ }
+
+ /**
+ * Generate the SQL statement for creating a unique index.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function unique(Table $table, Fluent $command)
+ {
+ return $this->key($table, $command, true);
+ }
+
+ /**
+ * Generate the SQL statement for creating a full-text index.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function fulltext(Table $table, Fluent $command)
+ {
+ $columns = $this->columnize($command->columns);
+
+ return 'CREATE VIRTUAL TABLE '.$this->wrap($table)." USING fts4({$columns})";
+ }
+
+ /**
+ * Generate the SQL statement for creating a regular index.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function index(Table $table, Fluent $command)
+ {
+ return $this->key($table, $command);
+ }
+
+ /**
+ * Generate the SQL statement for creating a new index.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @param bool $unique
+ * @return string
+ */
+ protected function key(Table $table, Fluent $command, $unique = false)
+ {
+ $columns = $this->columnize($command->columns);
+
+ $create = ($unique) ? 'CREATE UNIQUE' : 'CREATE';
+
+ return $create." INDEX {$command->name} ON ".$this->wrap($table)." ({$columns})";
+ }
+
+ /**
+ * Generate the SQL statement for a drop table command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function drop(Table $table, Fluent $command)
+ {
+ return 'DROP TABLE '.$this->wrap($table);
+ }
+
+ /**
+ * Generate the SQL statement for a drop unqique key command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function drop_unique(Table $table, Fluent $command)
+ {
+ return $this->drop_key($table, $command);
+ }
+
+ /**
+ * Generate the SQL statement for a drop unqique key command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function drop_index(Table $table, Fluent $command)
+ {
+ return $this->drop_key($table, $command);
+ }
+
+ /**
+ * Generate the SQL statement for a drop key command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ protected function drop_key(Table $table, Fluent $command)
+ {
+ return 'DROP INDEX '.$this->wrap($command->name);
+ }
+
+ /**
+ * Generate the data-type definition for a string.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_string(Fluent $column)
+ {
+ return 'VARCHAR';
+ }
+
+ /**
+ * Generate the data-type definition for an integer.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_integer(Fluent $column)
+ {
+ return 'INTEGER';
+ }
+
+ /**
+ * Generate the data-type definition for an integer.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_float(Fluent $column)
+ {
+ return 'FLOAT';
+ }
+
+ /**
+ * Generate the data-type definintion for a decimal.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_decimal(Fluent $column)
+ {
+ return 'FLOAT';
+ }
+
+ /**
+ * Generate the data-type definition for a boolean.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_boolean(Fluent $column)
+ {
+ return 'INTEGER';
+ }
+
+ /**
+ * Generate the data-type definition for a date.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_date(Fluent $column)
+ {
+ return 'DATETIME';
+ }
+
+ /**
+ * Generate the data-type definition for a timestamp.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_timestamp(Fluent $column)
+ {
+ return 'DATETIME';
+ }
+
+ /**
+ * Generate the data-type definition for a text column.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_text(Fluent $column)
+ {
+ return 'TEXT';
+ }
+
+ /**
+ * Generate the data-type definition for a blob.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_blob(Fluent $column)
+ {
+ return 'BLOB';
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/schema/grammars/sqlserver.php b/laravel/database/schema/grammars/sqlserver.php
new file mode 100644
index 0000000..5f756c2
--- /dev/null
+++ b/laravel/database/schema/grammars/sqlserver.php
@@ -0,0 +1,425 @@
+columns($table));
+
+ // First we will generate the base table creation statement. Other than auto
+ // incrementing keys, no indexes will be created during the first creation
+ // of the table as they're added in separate commands.
+ $sql = 'CREATE TABLE '.$this->wrap($table).' ('.$columns.')';
+
+ return $sql;
+ }
+
+ /**
+ * Geenrate the SQL statements for a table modification command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return array
+ */
+ public function add(Table $table, Fluent $command)
+ {
+ $columns = $this->columns($table);
+
+ // Once we the array of column definitions, we need to add "add" to the
+ // front of each definition, then we'll concatenate the definitions
+ // using commas like normal and generate the SQL.
+ $columns = implode(', ', array_map(function($column)
+ {
+ return 'ADD '.$column;
+
+ }, $columns));
+
+ return 'ALTER TABLE '.$this->wrap($table).' '.$columns;
+ }
+
+ /**
+ * Create the individual column definitions for the table.
+ *
+ * @param Table $table
+ * @return array
+ */
+ protected function columns(Table $table)
+ {
+ $columns = array();
+
+ foreach ($table->columns as $column)
+ {
+ // Each of the data type's have their own definition creation method,
+ // which is responsible for creating the SQL for the type. This lets
+ // us to keep the syntax easy and fluent, while translating the
+ // types to the types used by the database.
+ $sql = $this->wrap($column).' '.$this->type($column);
+
+ $elements = array('incrementer', 'nullable', 'defaults');
+
+ foreach ($elements as $element)
+ {
+ $sql .= $this->$element($table, $column);
+ }
+
+ $columns[] = $sql;
+ }
+
+ return $columns;
+ }
+
+ /**
+ * Get the SQL syntax for indicating if a column is nullable.
+ *
+ * @param Table $table
+ * @param Fluent $column
+ * @return string
+ */
+ protected function nullable(Table $table, Fluent $column)
+ {
+ return ($column->nullable) ? ' NULL' : ' NOT NULL';
+ }
+
+ /**
+ * Get the SQL syntax for specifying a default value on a column.
+ *
+ * @param Table $table
+ * @param Fluent $column
+ * @return string
+ */
+ protected function defaults(Table $table, Fluent $column)
+ {
+ if ( ! is_null($column->default))
+ {
+ return " DEFAULT '".$column->default."'";
+ }
+ }
+
+ /**
+ * Get the SQL syntax for defining an auto-incrementing column.
+ *
+ * @param Table $table
+ * @param Fluent $column
+ * @return string
+ */
+ protected function incrementer(Table $table, Fluent $column)
+ {
+ if ($column->type == 'integer' and $column->increment)
+ {
+ return ' IDENTITY PRIMARY KEY';
+ }
+ }
+
+ /**
+ * Generate the SQL statement for creating a primary key.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function primary(Table $table, Fluent $command)
+ {
+ $name = $command->name;
+
+ $columns = $this->columnize($command->columns);
+
+ return 'ALTER TABLE '.$this->wrap($table)." ADD CONSTRAINT {$name} PRIMARY KEY ({$columns})";
+ }
+
+ /**
+ * Generate the SQL statement for creating a unique index.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function unique(Table $table, Fluent $command)
+ {
+ return $this->key($table, $command, true);
+ }
+
+ /**
+ * Generate the SQL statement for creating a full-text index.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function fulltext(Table $table, Fluent $command)
+ {
+ $columns = $this->columnize($command->columns);
+
+ $table = $this->wrap($table);
+
+ // SQL Server requires the creation of a full-text "catalog" before creating
+ // a full-text index, so we'll first create the catalog then add another
+ // separate statement for the index.
+ $sql[] = "CREATE FULLTEXT CATALOG {$command->catalog}";
+
+ $create = "CREATE FULLTEXT INDEX ON ".$table." ({$columns}) ";
+
+ // Full-text indexes must specify a unique, non-null column as the index
+ // "key" and this should have been created manually by the developer in
+ // a separate column addition command.
+ $sql[] = $create .= "KEY INDEX {$command->key} ON {$command->catalog}";
+
+ return $sql;
+ }
+
+ /**
+ * Generate the SQL statement for creating a regular index.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function index(Table $table, Fluent $command)
+ {
+ return $this->key($table, $command);
+ }
+
+ /**
+ * Generate the SQL statement for creating a new index.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @param bool $unique
+ * @return string
+ */
+ protected function key(Table $table, Fluent $command, $unique = false)
+ {
+ $columns = $this->columnize($command->columns);
+
+ $create = ($unique) ? 'CREATE UNIQUE' : 'CREATE';
+
+ return $create." INDEX {$command->name} ON ".$this->wrap($table)." ({$columns})";
+ }
+
+ /**
+ * Generate the SQL statement for a drop table command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function drop(Table $table, Fluent $command)
+ {
+ return 'DROP TABLE '.$this->wrap($table);
+ }
+
+ /**
+ * Generate the SQL statement for a drop column command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function drop_column(Table $table, Fluent $command)
+ {
+ $columns = array_map(array($this, 'wrap'), $command->columns);
+
+ // Once we the array of column names, we need to add "drop" to the front
+ // of each column, then we'll concatenate the columns using commas and
+ // generate the alter statement SQL.
+ $columns = implode(', ', array_map(function($column)
+ {
+ return 'DROP '.$column;
+
+ }, $columns));
+
+ return 'ALTER TABLE '.$this->wrap($table).' '.$columns;
+ }
+
+ /**
+ * Generate the SQL statement for a drop primary key command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function drop_primary(Table $table, Fluent $command)
+ {
+ return 'ALTER TABLE '.$this->wrap($table).' DROP CONSTRAINT '.$command->name;
+ }
+
+ /**
+ * Generate the SQL statement for a drop unqiue key command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function drop_unique(Table $table, Fluent $command)
+ {
+ return $this->drop_key($table, $command);
+ }
+
+ /**
+ * Generate the SQL statement for a drop full-text key command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function drop_fulltext(Table $table, Fluent $command)
+ {
+ $sql[] = "DROP FULLTEXT INDEX ".$command->name;
+
+ $sql[] = "DROP FULLTEXT CATALOG ".$command->catalog;
+
+ return $sql;
+ }
+
+ /**
+ * Generate the SQL statement for a drop index command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ public function drop_index(Table $table, Fluent $command)
+ {
+ return $this->drop_key($table, $command);
+ }
+
+ /**
+ * Generate the SQL statement for a drop key command.
+ *
+ * @param Table $table
+ * @param Fluent $command
+ * @return string
+ */
+ protected function drop_key(Table $table, Fluent $command)
+ {
+ return "DROP INDEX {$command->name} ON ".$this->wrap($table);
+ }
+
+ /**
+ * Drop a foreign key constraint from the table.
+ *
+ * @param Table $table
+ * @param Fluent $fluent
+ * @return string
+ */
+ public function drop_foreign(Table $table, Fluent $command)
+ {
+ return $this->drop_constraint($table, $command);
+ }
+
+ /**
+ * Generate the data-type definition for a string.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_string(Fluent $column)
+ {
+ return 'NVARCHAR('.$column->length.')';
+ }
+
+ /**
+ * Generate the data-type definition for an integer.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_integer(Fluent $column)
+ {
+ return 'INT';
+ }
+
+ /**
+ * Generate the data-type definition for an integer.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_float(Fluent $column)
+ {
+ return 'FLOAT';
+ }
+
+ /**
+ * Generate the data-type definintion for a decimal.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_decimal(Fluent $column)
+ {
+ return "DECIMAL({$column->precision}, {$column->scale})";
+ }
+
+ /**
+ * Generate the data-type definition for a boolean.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_boolean(Fluent $column)
+ {
+ return 'TINYINT';
+ }
+
+ /**
+ * Generate the data-type definition for a date.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_date(Fluent $column)
+ {
+ return 'DATETIME';
+ }
+
+ /**
+ * Generate the data-type definition for a timestamp.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_timestamp(Fluent $column)
+ {
+ return 'TIMESTAMP';
+ }
+
+ /**
+ * Generate the data-type definition for a text column.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_text(Fluent $column)
+ {
+ return 'NVARCHAR(MAX)';
+ }
+
+ /**
+ * Generate the data-type definition for a blob.
+ *
+ * @param Fluent $column
+ * @return string
+ */
+ protected function type_blob(Fluent $column)
+ {
+ return 'VARBINARY(MAX)';
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/database/schema/table.php b/laravel/database/schema/table.php
new file mode 100644
index 0000000..570c540
--- /dev/null
+++ b/laravel/database/schema/table.php
@@ -0,0 +1,417 @@
+name = $name;
+ }
+
+ /**
+ * Indicate that the table should be created.
+ *
+ * @return Fluent
+ */
+ public function create()
+ {
+ return $this->command(__FUNCTION__);
+ }
+
+ /**
+ * Create a new primary key on the table.
+ *
+ * @param string|array $columns
+ * @param string $name
+ * @return Fluent
+ */
+ public function primary($columns, $name = null)
+ {
+ return $this->key(__FUNCTION__, $columns, $name);
+ }
+
+ /**
+ * Create a new unique index on the table.
+ *
+ * @param string|array $columns
+ * @param string $name
+ * @return Fluent
+ */
+ public function unique($columns, $name = null)
+ {
+ return $this->key(__FUNCTION__, $columns, $name);
+ }
+
+ /**
+ * Create a new full-text index on the table.
+ *
+ * @param string|array $columns
+ * @param string $name
+ * @return Fluent
+ */
+ public function fulltext($columns, $name = null)
+ {
+ return $this->key(__FUNCTION__, $columns, $name);
+ }
+
+ /**
+ * Create a new index on the table.
+ *
+ * @param string|array $columns
+ * @param string $name
+ * @return Fluent
+ */
+ public function index($columns, $name = null)
+ {
+ return $this->key(__FUNCTION__, $columns, $name);
+ }
+
+ /**
+ * Add a foreign key constraint to the table.
+ *
+ * @param string|array $columns
+ * @param string $name
+ */
+ public function foreign($columns, $name = null)
+ {
+ return $this->key(__FUNCTION__, $columns, $name);
+ }
+
+ /**
+ * Create a command for creating any index.
+ *
+ * @param string $type
+ * @param string|array $columns
+ * @param string $name
+ * @return Fluent
+ */
+ public function key($type, $columns, $name)
+ {
+ $columns = (array) $columns;
+
+ // If no index name was specified, we will concatenate the columns and
+ // append the index type to the name to generate a unique name for
+ // the index that can be used when dropping indexes.
+ if (is_null($name))
+ {
+ $name = str_replace(array('-', '.'), '_', $this->name);
+
+ $name = $name.'_'.implode('_', $columns).'_'.$type;
+ }
+
+ return $this->command($type, compact('name', 'columns'));
+ }
+
+ /**
+ * Drop the database table.
+ *
+ * @return Fluent
+ */
+ public function drop()
+ {
+ return $this->command(__FUNCTION__);
+ }
+
+ /**
+ * Drop a column from the table.
+ *
+ * @param string|array $columns
+ * @return void
+ */
+ public function drop_column($columns)
+ {
+ return $this->command(__FUNCTION__, array('columns' => (array) $columns));
+ }
+
+ /**
+ * Drop a primary key from the table.
+ *
+ * @param string $name
+ * @return void
+ */
+ public function drop_primary($name = null)
+ {
+ return $this->drop_key(__FUNCTION__, $name);
+ }
+
+ /**
+ * Drop a unique index from the table.
+ *
+ * @param string $name
+ * @return void
+ */
+ public function drop_unique($name)
+ {
+ return $this->drop_key(__FUNCTION__, $name);
+ }
+
+ /**
+ * Drop a full-text index from the table.
+ *
+ * @param string $name
+ * @return void
+ */
+ public function drop_fulltext($name)
+ {
+ return $this->drop_key(__FUNCTION__, $name);
+ }
+
+ /**
+ * Drop an index from the table.
+ *
+ * @param string $name
+ * @return void
+ */
+ public function drop_index($name)
+ {
+ return $this->drop_key(__FUNCTION__, $name);
+ }
+
+ /**
+ * Drop a foreign key constraint from the table.
+ *
+ * @param string $name
+ * @return void
+ */
+ public function drop_foreign($name)
+ {
+ return $this->drop_key(__FUNCTION__, $name);
+ }
+
+ /**
+ * Create a command to drop any type of index.
+ *
+ * @param string $type
+ * @param string $name
+ * @return Fluent
+ */
+ protected function drop_key($type, $name)
+ {
+ return $this->command($type, compact('name'));
+ }
+
+ /**
+ * Add an auto-incrementing integer to the table.
+ *
+ * @param string $name
+ * @return Fluent
+ */
+ public function increments($name)
+ {
+ return $this->integer($name, true);
+ }
+
+ /**
+ * Add a string column to the table.
+ *
+ * @param string $name
+ * @param int $length
+ * @return Fluent
+ */
+ public function string($name, $length = 200)
+ {
+ return $this->column(__FUNCTION__, compact('name', 'length'));
+ }
+
+ /**
+ * Add an integer column to the table.
+ *
+ * @param string $name
+ * @param bool $increment
+ * @return Fluent
+ */
+ public function integer($name, $increment = false)
+ {
+ return $this->column(__FUNCTION__, compact('name', 'increment'));
+ }
+
+ /**
+ * Add a float column to the table.
+ *
+ * @param string $name
+ * @return Fluent
+ */
+ public function float($name)
+ {
+ return $this->column(__FUNCTION__, compact('name'));
+ }
+
+ /**
+ * Add a decimal column to the table.
+ *
+ * @param string $name
+ * @param int $precision
+ * @param int $scale
+ * @return Fluent
+ */
+ public function decimal($name, $precision, $scale)
+ {
+ return $this->column(__FUNCTION__, compact('name', 'precision', 'scale'));
+ }
+
+ /**
+ * Add a boolean column to the table.
+ *
+ * @param string $name
+ * @return Fluent
+ */
+ public function boolean($name)
+ {
+ return $this->column(__FUNCTION__, compact('name'));
+ }
+
+ /**
+ * Create date-time columns for creation and update timestamps.
+ *
+ * @return void
+ */
+ public function timestamps()
+ {
+ $this->date('created_at');
+
+ $this->date('updated_at');
+ }
+
+ /**
+ * Add a date-time column to the table.
+ *
+ * @param string $name
+ * @return Fluent
+ */
+ public function date($name)
+ {
+ return $this->column(__FUNCTION__, compact('name'));
+ }
+
+ /**
+ * Add a timestamp column to the table.
+ *
+ * @param string $name
+ * @return Fluent
+ */
+ public function timestamp($name)
+ {
+ return $this->column(__FUNCTION__, compact('name'));
+ }
+
+ /**
+ * Add a text column to the table.
+ *
+ * @param string $name
+ * @return Fluent
+ */
+ public function text($name)
+ {
+ return $this->column(__FUNCTION__, compact('name'));
+ }
+
+ /**
+ * Add a blob column to the table.
+ *
+ * @param string $name
+ * @return Fluent
+ */
+ public function blob($name)
+ {
+ return $this->column(__FUNCTION__, compact('name'));
+ }
+
+ /**
+ * Set the database connection for the table operation.
+ *
+ * @param string $connection
+ * @return void
+ */
+ public function on($connection)
+ {
+ $this->connection = $connection;
+ }
+
+ /**
+ * Determine if the schema table has a creation command.
+ *
+ * @return bool
+ */
+ public function creating()
+ {
+ return ! is_null(array_first($this->commands, function($key, $value)
+ {
+ return $value->type == 'create';
+ }));
+ }
+
+ /**
+ * Create a new fluent command instance.
+ *
+ * @param string $type
+ * @param array $parameters
+ * @return Fluent
+ */
+ protected function command($type, $parameters = array())
+ {
+ $parameters = array_merge(compact('type'), $parameters);
+
+ $this->commands[] = new Fluent($parameters);
+
+ return end($this->commands);
+ }
+
+ /**
+ * Create a new fluent column instance.
+ *
+ * @param string $type
+ * @param array $parameters
+ * @return Fluent
+ */
+ protected function column($type, $parameters = array())
+ {
+ $parameters = array_merge(compact('type'), $parameters);
+
+ $this->columns[] = new Fluent($parameters);
+
+ return end($this->columns);
+ }
+
+}
\ No newline at end of file
diff --git a/laravel/documentation/artisan/commands.md b/laravel/documentation/artisan/commands.md
new file mode 100644
index 0000000..997e86c
--- /dev/null
+++ b/laravel/documentation/artisan/commands.md
@@ -0,0 +1,102 @@
+# Artisan Commands
+
+## Contents
+
+- [Application Configuration](#application-configuration)
+- [Sessions](#sessions)
+- [Migrations](#migrations)
+- [Bundles](#bundles)
+- [Tasks](#tasks)
+- [Unit Tests](#unit-tests)
+- [Routing](#routing)
+- [Application Keys](#keys)
+- [CLI Options](#cli-options)
+
+
+## Application Configuration [(More Information)](/docs/install#basic-configuration)
+
+Description | Command
+------------- | -------------
+Generate a secure application key. An application key will not be generated unless the field in **config/application.php** is empty. | `php artisan key:generate`
+
+
+## Database Sessions [(More Information)](/docs/session/config#database)
+
+Description | Command
+------------- | -------------
+Create a session table | `php artisan session:table`
+
+
+## Migrations [(More Information)](/docs/database/migrations)
+
+Description | Command
+------------- | -------------
+Create the Laravel migration table | `php artisan migrate:install`
+Creating a migration | `php artisan migrate:make create_users_table`
+Creating a migration for a bundle | `php artisan migrate:make bundle::tablename`
+Running outstanding migrations | `php artisan migrate`
+Running outstanding migrations in the application | `php artisan migrate application`
+Running all outstanding migrations in a bundle | `php artisan migrate bundle`
+Rolling back the last migration operation | `php artisan migrate:rollback`
+Roll back all migrations that have ever run | `php artisan migrate:reset`
+
+
+## Bundles [(More Information)](/docs/bundles)
+
+Description | Command
+------------- | -------------
+Install a bundle | `php artisan bundle:install eloquent`
+Upgrade a bundle | `php artisan bundle:upgrade eloquent`
+Upgrade all bundles | `php artisan bundle:upgrade`
+Publish a bundle assets | `php artisan bundle:publish bundle_name`
+Publish all bundles assets | `php artisan bundle:publish`
+
+
+> **Note:** After installing you need to [register the bundle](../bundles/#registering-bundles)
+
+
+## Tasks [(More Information)](/docs/artisan/tasks)
+
+Description | Command
+------------- | -------------
+Calling a task | `php artisan notify`
+Calling a task and passing arguments | `php artisan notify taylor`
+Calling a specific method on a task | `php artisan notify:urgent`
+Running a task on a bundle | `php artisan admin::generate`
+Running a specific method on a bundle | `php artisan admin::generate:list`
+
+
+## Unit Tests [(More Information)](/docs/testing)
+
+Description | Command
+------------- | -------------
+Running the application tests | `php artisan test`
+Running the bundle tests | `php artisan test bundle-name`
+
+
+## Routing [(More Information)](/docs/routing)
+
+Description | Command
+------------- | -------------
+Calling a route | `php artisan route:call get api/user/1`
+
+
+> **Note:** You can replace get with post, put, delete, etc.
+
+
+## Application Keys
+
+Description | Command
+------------- | -------------
+Generate an application key | `php artisan key:generate`
+
+
+> **Note:** You can specify an alternate key length by adding an extra argument to the command.
+
+
+## CLI Options
+
+Description | Command
+------------- | -------------
+Setting the Laravel environment | `php artisan foo --env=local`
+Setting the default database connection | `php artisan foo --database=sqlitename`
diff --git a/laravel/documentation/artisan/tasks.md b/laravel/documentation/artisan/tasks.md
new file mode 100644
index 0000000..08e6606
--- /dev/null
+++ b/laravel/documentation/artisan/tasks.md
@@ -0,0 +1,100 @@
+# Tasks
+
+## Contents
+
+- [The Basics](#the-basics)
+- [Creating & Running Tasks](#creating-tasks)
+- [Bundle Tasks](#bundle-tasks)
+- [CLI Options](#cli-options)
+
+
+## The Basics
+
+Laravel's command-line tool is called Artisan. Artisan can be used to run "tasks" such as migrations, cronjobs, unit-tests, or anything that want.
+
+
+## Creating & Running Tasks
+
+To create a task create a new class in your **application/tasks** directory. The class name should be suffixed with "_Task", and should at least have a "run" method, like this:
+
+#### Creating a task class:
+
+ class Notify_Task {
+
+ public function run($arguments)
+ {
+ // Do awesome notifying...
+ }
+
+ }
+
+Now you can call the "run" method of your task via the command-line. You can even pass arguments:
+
+#### Calling a task from the command line:
+
+ php artisan notify
+
+#### Calling a task and passing arguments:
+
+ php artisan notify taylor
+
+Remember, you can call specific methods on your task, so, let's add an "urgent" method to the notify task:
+
+#### Adding a method to the task:
+
+ class Notify_Task {
+
+ public function run($arguments)
+ {
+ // Do awesome notifying...
+ }
+
+ public function urgent($arguments)
+ {
+ // This is urgent!
+ }
+
+ }
+
+Now we can call our "urgent" method:
+
+#### Calling a specific method on a task:
+
+ php artisan notify:urgent
+
+
+## Bundle Tasks
+
+To create a task for your bundle just prefix the bundle name to the class name of your task. So, if your bundle was named "admin", a task might look like this:
+
+#### Creating a task class that belongs to a bundle:
+
+ class Admin_Generate_Task {
+
+ public function run($arguments)
+ {
+ // Generate the admin!
+ }
+
+ }
+
+To run your task just use the usual Laravel double-colon syntax to indicate the bundle:
+
+#### Running a task belonging to a bundle:
+
+ php artisan admin::generate
+
+#### Running a specific method on a task belonging to a bundle:
+
+ php artisan admin::generate:list
+
+
+## CLI Options
+
+#### Setting the Laravel environment:
+
+ php artisan foo --env=local
+
+#### Setting the default database connection:
+
+ php artisan foo --database=sqlite
\ No newline at end of file
diff --git a/laravel/documentation/auth/config.md b/laravel/documentation/auth/config.md
new file mode 100644
index 0000000..a160932
--- /dev/null
+++ b/laravel/documentation/auth/config.md
@@ -0,0 +1,38 @@
+# Auth Configuration
+
+## Contents
+
+- [The Basics](#the-basics)
+- [The Authentication Driver](#driver)
+- [The Default "Username"](#username)
+- [Authentication Model](#model)
+- [Authentication Table](#table)
+
+
+## The Basics
+
+Most interactive applications have the ability for users to login and logout. Laravel provides a simple class to help you validate user credentials and retrieve information about the current user of your application.
+
+To get started, let's look over the **application/config/auth.php** file. The authentication configuration contains some basic options to help you get started with authentication.
+
+
+## The Authentication Driver
+
+Laravel's authentication is driver based, meaning the responsibility for retrieving users during authentication is delegated to various "drivers". Two are included out of the box: Eloquent and Fluent, but you are free to write your own drivers if needed!
+
+The **Eloquent** driver uses the Eloquent ORM to load the users of your application, and is the default authentication driver. The **Fluent** driver uses the fluent query builder to load your users.
+
+
+## The Default "Username"
+
+The second option in the configuration file determines the default "username" of your users. This will typically correspond to a database column in your "users" table, and will usually be "email" or "username".
+
+
+## Authentication Model
+
+When using the **Eloquent** authentication driver, this option determines the Eloquent model that should be used when loading users.
+
+
+## Authentication Table
+
+When using the **Fluent** authentication drivers, this option determines the database table containing the users of your application.
\ No newline at end of file
diff --git a/laravel/documentation/auth/usage.md b/laravel/documentation/auth/usage.md
new file mode 100644
index 0000000..8a9a065
--- /dev/null
+++ b/laravel/documentation/auth/usage.md
@@ -0,0 +1,86 @@
+# Authentication Usage
+
+## Contents
+
+- [Salting & Hashing](#hash)
+- [Logging In](#login)
+- [Protecting Routes](#filter)
+- [Retrieving The Logged In User](#user)
+- [Logging Out](#logout)
+- [Writing Custom Drivers](#drivers)
+
+> **Note:** Before using the Auth class, you must [specify a session driver](/docs/session/config).
+
+
+## Salting & Hashing
+
+If you are using the Auth class, you are strongly encouraged to hash and salt all passwords. Web development must be done responsibly. Salted, hashed passwords make a rainbow table attack against your user's passwords impractical.
+
+Salting and hashing passwords is done using the **Hash** class. The Hash class is uses the **bcrypt** hashing algorithm. Check out this example:
+
+ $password = Hash::make('secret');
+
+The **make** method of the Hash class will return a 60 character hashed string.
+
+You can compare an unhashed value against a hashed one using the **check** method on the **Hash** class:
+
+ if (Hash::check('secret', $hashed_value))
+ {
+ return 'The password is valid!';
+ }
+
+
+## Logging In
+
+Logging a user into your application is simple using the **attempt** method on the Auth class. Simply pass the username and password of the user to the method. The credentials should be contained in an array, which allows for maximum flexibility across drivers, as some drivers may require a different number of arguments. The login method will return **true** if the credentials are valid. Otherwise, **false** will be returned:
+
+ $credentials = array('username' => 'example@gmail.com', 'password' => 'secret');
+
+ if (Auth::attempt($credentials))
+ {
+ return Redirect::to('user/profile');
+ }
+
+If the user's credentials are valid, the user ID will be stored in the session and the user will be considered "logged in" on subsequent requests to your application.
+
+To determine if the user of your application is logged in, call the **check** method:
+
+ if (Auth::check())
+ {
+ return "You're logged in!";
+ }
+
+Use the **login** method to login a user without checking their credentials, such as after a user first registers to use your application. Just pass your user object or the user's ID:
+
+ Auth::login($user);
+
+ Auth::login(15);
+
+
+## Protecting Routes
+
+It is common to limit access to certain routes only to logged in users. In Laravel this is accomplished using the [auth filter](/docs/routing#filters). If the user is logged in, the request will proceed as normal; however, if the user is not logged in, they will be redirected to the "login" [named route](/docs/routing#named-routes).
+
+To protect a route, simply attach the **auth** filter:
+
+ Route::get('admin', array('before' => 'auth', function() {}));
+
+> **Note:** You are free to edit the **auth** filter however you like. A default implementation is located in **application/routes.php**.
+
+
+## Retrieving The Logged In User
+
+Once a user has logged in to your application, you can access the user model via the **user** method on the Auth class:
+
+ return Auth::user()->email;
+
+> **Note:** If the user is not logged in, the **user** method will return NULL.
+
+
+## Logging Out
+
+Ready to log the user out of your application?
+
+ Auth::logout();
+
+This method will remove the user ID from the session, and the user will no longer be considered logged in on subsequent requests to your application.
\ No newline at end of file
diff --git a/laravel/documentation/bundles.md b/laravel/documentation/bundles.md
new file mode 100644
index 0000000..2f72dbb
--- /dev/null
+++ b/laravel/documentation/bundles.md
@@ -0,0 +1,214 @@
+# Bundles
+
+## Contents
+
+- [The Basics](#the-basics)
+- [Creating Bundles](#creating-bundles)
+- [Registering Bundles](#registering-bundles)
+- [Bundles & Class Loading](#bundles-and-class-loading)
+- [Starting Bundles](#starting-bundles)
+- [Routing To Bundles](#routing-to-bundles)
+- [Using Bundles](#using-bundles)
+- [Bundle Assets](#bundle-assets)
+- [Installing Bundles](#installing-bundles)
+- [Upgrading Bundles](#upgrading-bundles)
+
+
+## The Basics
+
+Bundles are the heart of the improvements that were made in Laravel 3.0. They are a simple way to group code into convenient "bundles". A bundle can have it's own views, configuration, routes, migrations, tasks, and more. A bundle could be everything from a database ORM to a robust authentication system. Modularity of this scope is an important aspect that has driven virtually all design decisions within Laravel. In many ways you can actually think of the application folder as the special default bundle with which Laravel is pre-programmed to load and use.
+
+
+## Creating Bundles
+
+The first step in creating a bundle is to create a folder for the bundle within your **bundles** directory. For this example, let's create an "admin" bundle, which could house the administrator back-end to our application. The **application/start.php** file provides some basic configuration that helps to define how our application will run. Likewise we'll create a **start.php** file within our new bundle folder for the same purpose. It is run everytime the bundle is loaded. Let's create it:
+
+#### Creating a bundle start.php file:
+
+ Bundle::path('admin').'models',
+ ));
+
+In this start file we've told the auto-loader that classes that are namespaced to "Admin" should be loaded out of our bundle's models directory. You can do anything you want in your start file, but typically it is used for registering classes with the auto-loader. **In fact, you aren't required to create a start file for your bundle.**
+
+Next, we'll look at how to register this bundle with our application!
+
+
+## Registering Bundles
+
+Now that we have our admin bundle, we need to register it with Laravel. Pull open your **application/bundles.php** file. This is where you register all bundles used by your application. Let's add ours:
+
+#### Registering a simple bundle:
+
+ return array('admin'),
+
+By convention, Laravel will assume that the Admin bundle is located at the root level of the bundle directory, but we can specify another location if we wish:
+
+#### Registering a bundle with a custom location:
+
+ return array(
+
+ 'admin' => array('location' => 'userscape/admin'),
+
+ );
+
+Now Laravel will look for our bundle in **bundles/userscape/admin**.
+
+
+## Bundles & Class Loading
+
+Typically, a bundle's **start.php** file only contains auto-loader registrations. So, you may want to just skip **start.php** and declare your bundle's mappings right in its registration array. Here's how:
+
+#### Defining auto-loader mappings in a bundle registration:
+
+ return array(
+
+ 'admin' => array(
+ 'autoloads' => array(
+ 'map' => array(
+ 'Admin' => '(:bundle)/admin.php',
+ ),
+ 'namespaces' => array(
+ 'Admin' => '(:bundle)/lib',
+ ),
+ 'directories' => array(
+ '(:bundle)/models',
+ ),
+ ),
+ ),
+
+ );
+
+Notice that each of these options corresponds to a function on the Laravel [auto-loader](/docs/loading). In fact, the value of the option will automatically be passed to the corresponding function on the auto-loader.
+
+You may have also noticed the **(:bundle)** place-holder. For convenience, this will automatically be replaced with the path to the bundle. It's a piece of cake.
+
+
+## Starting Bundles
+
+So our bundle is created and registered, but we can't use it yet. First, we need to start it:
+
+#### Starting a bundle:
+
+ Bundle::start('admin');
+
+This tells Laravel to run the **start.php** file for the bundle, which will register its classes in the auto-loader. The start method will also load the **routes.php** file for the bundle if it is present.
+
+> **Note:** The bundle will only be started once. Subsequent calls to the start method will be ignored.
+
+If you use a bundle throughout your application, you may want it to start on every request. If this is the case, you can configure the bundle to auto-start in your **application/bundles.php** file:
+
+#### Configuration a bundle to auto-start:
+
+ return array(
+
+ 'admin' => array('auto' => true),
+
+ );
+
+You do not always need to explicitly start a bundle. In fact, you can usually code as if the bundle was auto-started and Laravel will take care of the rest. For example, if you attempt to use a bundle views, configurations, languages, routes or filters, the bundle will automatically be started!
+
+Each time a bundle is started, it fires an event. You can listen for the starting of bundles like so:
+
+#### Listen for a bundle's start event:
+
+ Event::listen('laravel.started: admin', function()
+ {
+ // The "admin" bundle has started...
+ });
+
+It is also possible to "disable" a bundle so that it will never be started.
+
+#### Disabling a bundle so it can't be started:
+
+ Bundle::disable('admin');
+
+
+## Routing To Bundles
+
+Refer to the documentation on [bundle routing](/docs/routing#bundle-routes) and [bundle controllers](/docs/controllers#bundle-controllers) for more information on routing and bundles.
+
+
+## Using Bundles
+
+As mentioned previously, bundles can have views, configuration, language files and more. Laravel uses a double-colon syntax for loading these items. So, let's look at some examples:
+
+#### Loading a bundle view:
+
+ return View::make('bundle::view');
+
+#### Loading a bundle configuration item:
+
+ return Config::get('bundle::file.option');
+
+#### Loading a bundle language line:
+
+ return Lang::line('bundle::file.line');
+
+Sometimes you may need to gather more "meta" information about a bundle, such as whether it exists, its location, or perhaps its entire configuration array. Here's how:
+
+#### Determine whether a bundle exists:
+
+ Bundle::exists('admin');
+
+#### Retrieving the installation location of a bundle:
+
+ $location = Bundle::path('admin');
+
+#### Retrieving the configuration array for a bundle:
+
+ $config = Bundle::get('admin');
+
+#### Retrieving the names of all installed bundles:
+
+ $names = Bundle::names();
+
+
+## Bundle Assets
+
+If your bundle contains views, it is likely you have assets such as JavaScript and images that need to be available in the **public** directory of the application. No problem. Just create **public** folder within your bundle and place all of your assets in this folder.
+
+Great! But, how do they get into the application's **public** folder. The Laravel "Artisan" command-line provides a simple command to copy all of your bundle's assets to the public directory. Here it is:
+
+#### Publish bundle assets into the public directory:
+
+ php artisan bundle:publish
+
+This command will create a folder for the bundle's assets within the application's **public/bundles** directory. For example, if your bundle is named "admin", a **public/bundles/admin** folder will be created, which will contain all of the files in your bundle's public folder.
+
+For more information on conveniently getting the path to your bundle assets once they are in the public directory, refer to the documentation on [asset management](/docs/views/assets#bundle-assets).
+
+
+## Installing Bundles
+
+Of course, you may always install bundles manually; however, the "Artisan" CLI provides an awesome method of installing and upgrading your bundle. The framework uses simple Zip extraction to install the bundle. Here's how it works.
+
+#### Installing a bundle via Artisan:
+
+ php artisan bundle:install eloquent
+
+Great! Now that you're bundle is installed, you're ready to [register it](#registering-bundles) and [publish its assets](#bundle-assets).
+
+Need a list of available bundles? Check out the Laravel [bundle directory](http://bundles.laravel.com)
+
+
+## Upgrading Bundles
+
+When you upgrade a bundle, Laravel will automatically remove the old bundle and install a fresh copy.
+
+#### Upgrading a bundle via Artisan:
+
+ php artisan bundle:upgrade eloquent
+
+> **Note:** After upgrading the bundle, you may need to [re-publish its assets](#bundle-assets).
+
+**Important:** Since the bundle is totally removed on an upgrade, you must be aware of any changes you have made to the bundle code before upgrading. You may need to change some configuration options in a bundle. Instead of modifying the bundle code directly, use the bundle start events to set them. Place something like this in your **application/start.php** file.
+
+#### Listening for a bundle's start event:
+
+ Event::listen('laravel.started: admin', function()
+ {
+ Config::set('admin::file.option', true);
+ });
\ No newline at end of file
diff --git a/laravel/documentation/cache/config.md b/laravel/documentation/cache/config.md
new file mode 100644
index 0000000..39f80c4
--- /dev/null
+++ b/laravel/documentation/cache/config.md
@@ -0,0 +1,79 @@
+# Cache Configuration
+
+## Contents
+
+- [The Basics](#the-basics)
+- [Database](#database)
+- [Memcached](#memcached)
+- [Redis](#redis)
+- [Cache Keys](#keys)
+- [In-Memory Cache](#memory)
+
+
+## The Basics
+
+Imagine your application displays the ten most popular songs as voted on by your users. Do you really need to look up these ten songs every time someone visits your site? What if you could store them for 10 minutes, or even an hour, allowing you to dramatically speed up your application? Laravel's caching makes it simple.
+
+Laravel provides five cache drivers out of the box:
+
+- File System
+- Database
+- Memcached
+- APC
+- Redis
+- Memory (Arrays)
+
+By default, Laravel is configured to use the **file** system cache driver. It's ready to go out of the box with no configuration. The file system driver stores cached items as files in the **cache** directory. If you're satisfied with this driver, no other configuration is required. You're ready to start using it.
+
+> **Note:** Before using the file system cache driver, make sure your **storage/cache** directory is writeable.
+
+
+## Database
+
+The database cache driver uses a given database table as a simple key-value store. To get started, first set the name of the database table in **application/config/cache.php**:
+
+ 'database' => array('table' => 'laravel_cache'),
+
+Next, create the table on your database. The table should have three columns:
+
+- key (varchar)
+- value (text)
+- expiration (integer)
+
+That's it. Once your configuration and table is setup, you're ready to start caching!
+
+
+## Memcached
+
+[Memcached](http://memcached.org) is an ultra-fast, open-source distributed memory object caching system used by sites such as Wikipedia and Facebook. Before using Laravel's Memcached driver, you will need to install and configure Memcached and the PHP Memcache extension on your server.
+
+Once Memcached is installed on your server you must set the **driver** in the **application/config/cache.php** file:
+
+ 'driver' => 'memcached'
+
+Then, add your Memcached servers to the **servers** array:
+
+ 'servers' => array(
+ array('host' => '127.0.0.1', 'port' => 11211, 'weight' => 100),
+ )
+
+
+## Redis
+
+[Redis](http://redis.io) is an open source, advanced key-value store. It is often referred to as a data structure server since keys can contain [strings](http://redis.io/topics/data-types#strings), [hashes](http://redis.io/topics/data-types#hashes), [lists](http://redis.io/topics/data-types#lists), [sets](http://redis.io/topics/data-types#sets), and [sorted sets](http://redis.io/topics/data-types#sorted-sets).
+
+Before using the Redis cache driver, you must [configure your Redis servers](/docs/database/redis#config). Now you can just set the **driver** in the **application/config/cache.php** file:
+
+ 'driver' => 'redis'
+
+
+### Cache Keys
+
+To avoid naming collisions with other applications using APC, Redis, or a Memcached server, Laravel prepends a **key** to each item stored in the cache using these drivers. Feel free to change this value:
+
+ 'key' => 'laravel'
+
+
+### In-Memory Cache
+
+The "memory" cache driver does not actually cache anything to disk. It simply maintains an internal array of the cache data for the current request. This makes it perfect for unit testing your application in isolation from any storage mechanism. It should never be used as a "real" cache driver.
\ No newline at end of file
diff --git a/laravel/documentation/cache/usage.md b/laravel/documentation/cache/usage.md
new file mode 100644
index 0000000..adc2f2e
--- /dev/null
+++ b/laravel/documentation/cache/usage.md
@@ -0,0 +1,59 @@
+# Cache Usage
+
+## Contents
+
+- [Storing Items](#put)
+- [Retrieving Items](#get)
+- [Removing Items](#forget)
+
+
+## Storing Items
+
+Storing items in the cache is simple. Simply call the **put** method on the Cache class:
+
+ Cache::put('name', 'Taylor', 10);
+
+The first parameter is the **key** to the cache item. You will use this key to retrieve the item from the cache. The second parameter is the **value** of the item. The third parameter is the number of **minutes** you want the item to be cached.
+
+You may also cache something "forever" if you do not want the cache to expire:
+
+ Cache::forever('name', 'Taylor');
+
+> **Note:** It is not necessary to serialize objects when storing them in the cache.
+
+
+## Retrieving Items
+
+Retrieving items from the cache is even more simple than storing them. It is done using the **get** method. Just mention the key of the item you wish to retrieve:
+
+ $name = Cache::get('name');
+
+By default, NULL will be returned if the cached item has expired or does not exist. However, you may pass a different default value as a second parameter to the method:
+
+ $name = Cache::get('name', 'Fred');
+
+Now, "Fred" will be returned if the "name" cache item has expired or does not exist.
+
+What if you need a value from your database if a cache item doesn't exist? The solution is simple. You can pass a closure into the **get** method as a default value. The closure will only be executed if the cached item doesn't exist:
+
+ $users = Cache::get('count', function() {return DB::table('users')->count();});
+
+Let's take this example a step further. Imagine you want to retrieve the number of registered users for your application; however, if the value is not cached, you want to store the default value in the cache using the **remember** method:
+
+ $users = Cache::remember('count', function() {return DB::table('users')->count();}, 5);
+
+Let's talk through that example. If the **count** item exists in the cache, it will be returned. If it doesn't exist, the result of the closure will be stored in the cache for five minutes **and** be returned by the method. Slick, huh?
+
+Laravel even gives you a simple way to determine if a cached item exists using the **has** method:
+
+ if (Cache::has('name'))
+ {
+ $name = Cache::get('name');
+ }
+
+
+## Removing Items
+
+Need to get rid of a cached item? No problem. Just mention the name of the item to the **forget** method:
+
+ Cache::forget('name');
\ No newline at end of file
diff --git a/laravel/documentation/changes.md b/laravel/documentation/changes.md
new file mode 100644
index 0000000..d4e12da
--- /dev/null
+++ b/laravel/documentation/changes.md
@@ -0,0 +1,326 @@
+# Laravel Change Log
+
+## Contents
+
+- [Laravel 3.2.3](#3.2.3)
+- [Upgrading From 3.2.2](#upgrade-3.2.3)
+- [Laravel 3.2.2](#3.2.2)
+- [Upgrading From 3.2.1](#upgrade-3.2.2)
+- [Laravel 3.2.1](#3.2.1)
+- [Upgrading From 3.2](#upgrade-3.2.1)
+- [Laravel 3.2](#3.2)
+- [Upgrading From 3.1](#upgrade-3.2)
+- [Laravel 3.1.9](#3.1.9)
+- [Upgrading From 3.1.8](#upgrade-3.1.9)
+- [Laravel 3.1.8](#3.1.8)
+- [Upgrading From 3.1.7](#upgrade-3.1.8)
+- [Laravel 3.1.7](#3.1.7)
+- [Upgrading From 3.1.6](#upgrade-3.1.7)
+- [Laravel 3.1.6](#3.1.6)
+- [Upgrading From 3.1.5](#upgrade-3.1.6)
+- [Laravel 3.1.5](#3.1.5)
+- [Upgrading From 3.1.4](#upgrade-3.1.5)
+- [Laravel 3.1.4](#3.1.4)
+- [Upgrading From 3.1.3](#upgrade-3.1.4)
+- [Laravel 3.1.3](#3.1.3)
+- [Upgrading From 3.1.2](#uprade-3.1.3)
+- [Laravel 3.1.2](#3.1.2)
+- [Upgrading From 3.1.1](#upgrade-3.1.2)
+- [Laravel 3.1.1](#3.1.1)
+- [Upgrading From 3.1](#upgrade-3.1.1)
+- [Laravel 3.1](#3.1)
+- [Upgrading From 3.0](#upgrade-3.1)
+
+
+## Laravel 3.2.3
+
+- Fixed eager loading bug in Eloquent.
+- Added `laravel.resolving` event for all IoC resolutions.
+
+
+## Upgrading From 3.2.2
+
+- Replace the **laravel** folder.
+
+
+## Laravel 3.2.2
+
+- Overall improvement of Postgres support.
+- Fix issue in SQL Server Schema grammar.
+- Fix issue with eager loading and `first` or `find`.
+- Fix bug causing parameters to not be passed to `IoC::resolve`.
+- Allow the specification of hostnames in environment setup.
+- Added `DB::last_query` method.
+- Added `password` option to Auth configuration.
+
+
+## Upgrading From 3.2.1
+
+- Replace the **laravel** folder.
+
+
+## Laravel 3.2.1
+
+- Fixed bug in cookie retrieval when cookie is set on same request.
+- Fixed bug in SQL Server grammar for primary keys.
+- Fixed bug in Validator on PHP 5.4.
+- If HTTP / HTTPS is not specified for generated links, current protocol is used.
+- Fix bug in Eloquent auth driver.
+- Added `format` method to message container.
+
+
+## Upgrading From 3.2
+
+- Replace the **laravel** folder.
+
+
+## Laravel 3.2
+
+- [Added `to_array` method to the base Eloquent model](/docs/database/eloquent#to-array).
+- [Added `$hidden` static variable to the base Eloquent model](/docs/database/eloquent#to-array).
+- [Added `sync` method to has\_many\_and\_belongs\_to Eloquent relationship](/docs/database/eloquent#sync-method).
+- [Added `save` method to has\_many Eloquent relationship](/docs/database/eloquent#has-many-save).
+- [Added `unless` structure to Blade template engine](/docs/views/templating#blade-unless).
+- [Added Blade comments](/docs/views/templating#blade-comments).
+- [Added simpler environment management](/docs/install#environments).
+- Added `Blade::extend()` method to define custom blade compilers.
+- Added `View::exists` method.
+- Use [Memcached](http://php.net/manual/en/book.memcached.php) API instead of older [Memcache](http://php.net/manual/en/book.memcache.php) API.
+- Added support for bundles outside of the bundle directory.
+- Added support for DateTime database query bindings.
+- Migrated to the Symfony HttpFoundation component for core request / response handling.
+- Fixed the passing of strings into the `Input::except` method.
+- Fixed replacement of optional parameters in `URL::transpose` method.
+- Improved `update` handling on `Has_Many` and `Has_One` relationships.
+- Improved View performance by only loading contents from file once.
+- Fix handling of URLs beginning with hashes in `URL::to`.
+- Fix the resolution of unset Eloquent attributes.
+- Allows pivot table timestamps to be disabled.
+- Made the `get_timestamp` Eloquent method static.
+- `Request::secure` now takes `application.ssl` configuration option into consideration.
+- Simplified the `paths.php` file.
+- Only write file caches if number of minutes is greater than zero.
+- Added `$default` parameter to Bundle::option method.
+- Fixed bug present when using Eloquent models with Twig.
+- Allow multiple views to be registered for a single composer.
+- Added `Request::set_env` method.
+- `Schema::drop` now accepts `$connection` as second parameter.
+- Added `Input::merge` method.
+- Added `Input::replace` method.
+- Added saving, saved, updating, creating, deleting, and deleted events to Eloquent.
+- Added new `Sectionable` interface to allow cache drivers to simulate namespacing.
+- Added support for `HAVING` SQL clauses.
+- Added `array_pluck` helper, similar to pluck method in Underscore.js.
+- Allow the registration of custom cache and session drivers.
+- Allow the specification of a separate asset base URL for using CDNs.
+- Allow a `starter` Closure to be defined in `bundles.php` to be run on Bundle::start.
+- Allow the registration of custom database drivers.
+- New, driver based authentication system.
+- Added Input::json() method for working with applications using Backbone.js or similar.
+- Added Response::json method for creating JSON responses.
+- Added Response::eloquent method for creating Eloquent responses.
+- Fixed bug when using many-to-many relationships on non-default database connection.
+- Added true reflection based IoC to container.
+- Added `Request::route()->controller` and `Request::route()->controller_action`.
+- Added `Event::queue`, `Event::flusher`, and `Event::flush` methods to Event class.
+- Added `array_except` and `array_only` helpers, similar to `Input::except` and `Input::only` but for arbitrary arrays.
+
+
+## Upgrading From 3.1
+
+- Add new `asset_url` and `profiler` options to application configuration.
+- Replace **auth** configuration file.
+
+Add the following entry to the `aliases` array in `config/application.php`..
+
+ 'Profiler' => 'Laravel\\Profiling\\Profiler',
+
+Add the following code above `Blade::sharpen()` in `application/start.php`..
+
+ if (Config::get('application.profiler'))
+ {
+ Profiler::attach();
+ }
+
+- Upgrade the **paths.php** file.
+- Replace the **laravel** folder.
+
+
+## Laravel 3.1.9
+
+- Fixes cookie session driver bug that caused infinite loop on some occasions.
+
+
+## Upgrading From 3.1.8
+
+- Replace the **laravel** folder.
+
+
+## Laravel 3.1.8
+
+- Fixes possible WSOD when using Blade's @include expression.
+
+
+## Upgrading From 3.1.7
+
+- Replace the **laravel** folder.
+
+
+## Laravel 3.1.7
+
+- Fixes custom validation language line loading from bundles.
+- Fixes double-loading of classes when overriding the core.
+- Classify migration names.
+
+
+## Upgrading From 3.1.6
+
+- Replace the **laravel** folder.
+
+
+## Laravel 3.1.6
+
+- Fixes many-to-many eager loading in Eloquent.
+
+
+## Upgrading From 3.1.5
+
+- Replace the **laravel** folder.
+
+
+## Laravel 3.1.5
+
+- Fixes bug that could allow secure cookies to be sent over HTTP.
+
+
+## Upgrading From 3.1.4
+
+- Replace the **laravel** folder.
+
+
+## Laravel 3.1.4
+
+- Fixes Response header casing bug.
+- Fixes SQL "where in" (...) short-cut bug.
+
+
+## Upgrading From 3.1.3
+
+- Replace the **laravel** folder.
+
+
+## Laravel 3.1.3
+
+- Fixes **delete** method in Eloquent models.
+
+
+## Upgrade From 3.1.2
+
+- Replace the **laravel** folder.
+
+
+## Laravel 3.1.2
+
+- Fixes Eloquent query method constructor conflict.
+
+
+## Upgrade From 3.1.1
+
+- Replace the **laravel** folder.
+
+
+## Laravel 3.1.1
+
+- Fixes Eloquent model hydration bug involving custom setters.
+
+
+## Upgrading From 3.1
+
+- Replace the **laravel** folder.
+
+
+## Laravel 3.1
+
+- Added events to logger for more flexibility.
+- Added **database.fetch** configuration option.
+- Added controller factories for injecting any IoC.
+- Added **link_to_action** HTML helpers.
+- Added ability to set default value on Config::get.
+- Added the ability to add pattern based filters.
+- Improved session ID assignment.
+- Added support for "unsigned" integers in schema builder.
+- Added config, view, and lang loaders.
+- Added more logic to **application/start.php** for more flexibility.
+- Added foreign key support to schema builder.
+- Postgres "unique" indexes are now added with ADD CONSTRAINT.
+- Added "Event::until" method.
+- Added "memory" cache and session drivers.
+- Added Controller::detect method.
+- Added Cache::forever method.
+- Controller layouts now resolved in Laravel\Controller __construct.
+- Rewrote Eloquent and included in core.
+- Added "match" validation rule.
+- Fixed table prefix bug.
+- Added Form::macro method.
+- Added HTML::macro method.
+- Added Route::forward method.
+- Prepend table name to default index names in schema.
+- Added "forelse" to Blade.
+- Added View::render_each.
+- Able to specify full path to view (path: ).
+- Added support for Blade template inheritance.
+- Added "before" and "after" validation checks for dates.
+
+
+## Upgrading From 3.0
+
+### Replace your **application/start.php** file.
+
+The default **start.php** file has been expanded in order to give you more flexibility over the loading of your language, configuration, and view files. To upgrade your file, copy your current file and paste it at the bottom of a copy of the new Laravel 3.1 start file. Next, scroll up in the **start** file until you see the default Autoloader registrations (line 61 and line 76). Delete both of these sections since you just pasted your previous auto-loader registrations at the bottom of the file.
+
+### Remove the **display** option from your **errors** configuration file.
+
+This option is now set at the beginning of your **application/start** file.
+
+### Call the parent controller's constructor from your controller.
+
+Simply add a **parent::__construct();** to to any of your controllers that have a constructor.
+
+### Prefix Laravel migration created indexes with their table name.
+
+If you have created indexes on tables using the Laravel migration system and you used to the default index naming scheme provided by Laravel, prefix the index names with their table name on your database. So, if the current index name is "id_unique" on the "users" table, make the index name "users_id_unique".
+
+### Add alias for Eloquent in your application configuration.
+
+Add the following to the **aliases** array in your **application/config/application.php** file:
+
+ 'Eloquent' => 'Laravel\\Database\\Eloquent\\Model',
+ 'Blade' => 'Laravel\\Blade',
+
+### Update Eloquent many-to-many tables.
+
+Eloquent now maintains **created_at** and **updated_at** column on many-to-many intermediate tables by default. Simply add these columns to your tables. Also, many-to-many tables are now the singular model names concatenated with an underscore. For example, if the relationship is between User and Role, the intermediate table name should be **role_user**.
+
+### Remove Eloquent bundle.
+
+If you are using the Eloquent bundle with your installation, you can remove it from your bundles directory and your **application/bundles.php** file. Eloquent version 2 is included in the core in Laravel 3.1. Your models can also now extend simply **Eloquent** instead of **Eloquent\Model**.
+
+### Update your **config/strings.php** file.
+
+English pluralization and singularization is now automatic. Just completely replace your **application/config/strings.php** file.
+
+### Add the **fetch** option to your database configuration file.
+
+A new **fetch** option allows you to specify in which format you receive your database results. Just copy and paste the option from the new **application/config/database.php** file.
+
+### Add **database** option to your Redis configuration.
+
+If you are using Redis, add the "database" option to your Redis connection configurations. The "database" value can be zero by default.
+
+ 'redis' => array(
+ 'default' => array(
+ 'host' => '127.0.0.1',
+ 'port' => 6379,
+ 'database' => 0
+ ),
+ ),
diff --git a/laravel/documentation/config.md b/laravel/documentation/config.md
new file mode 100644
index 0000000..ae74138
--- /dev/null
+++ b/laravel/documentation/config.md
@@ -0,0 +1,34 @@
+# Runtime Configuration
+
+## Contents
+
+- [The Basics](#the-basics)
+- [Retrieving Options](#retrieving-options)
+- [Setting Options](#setting-options)
+
+
+## The Basics
+
+Sometimes you may need to get and set configuration options at runtime. For this you'll use the **Config** class, which utilizes Laravel's "dot" syntax for accessing configuration files and items.
+
+
+## Retrieving Options
+
+#### Retrieve a configuration option:
+
+ $value = Config::get('application.url');
+
+#### Return a default value if the option doesn't exist:
+
+ $value = Config::get('application.timezone', 'UTC');
+
+#### Retrieve an entire configuration array:
+
+ $options = Config::get('database');
+
+
+## Setting Options
+
+#### Set a configuration option:
+
+ Config::set('cache.driver', 'apc');
\ No newline at end of file
diff --git a/laravel/documentation/contents.md b/laravel/documentation/contents.md
new file mode 100644
index 0000000..63a2b86
--- /dev/null
+++ b/laravel/documentation/contents.md
@@ -0,0 +1,111 @@
+### General
+- [Laravel Overview](/docs/home)
+- [Change Log](/docs/changes)
+- [Installation & Setup](/docs/install)
+ - [Requirements](/docs/install#requirements)
+ - [Installation](/docs/install#installation)
+ - [Server Configuration](/docs/install#server-configuration)
+ - [Basic Configuration](/docs/install#basic-configuration)
+ - [Environments](/docs/install#environments)
+ - [Cleaner URLs](/docs/install#cleaner-urls)
+- [Routing](/docs/routing)
+ - [The Basics](/docs/routing#the-basics)
+ - [Wildcards](/docs/routing#wildcards)
+ - [The 404 Event](/docs/routing#the-404-event)
+ - [Filters](/docs/routing#filters)
+ - [Pattern Filters](/docs/routing#pattern-filters)
+ - [Global Filters](/docs/routing#global-filters)
+ - [Route Groups](/docs/routing#groups)
+ - [Named Routes](/docs/routing#named-routes)
+ - [HTTPS Routes](/docs/routing#https-routes)
+ - [Bundle Routing](/docs/routing#bundle-routing)
+ - [CLI Route Testing](/docs/routing#cli-route-testing)
+- [Controllers](/docs/controllers)
+ - [The Basics](/docs/controllers#the-basics)
+ - [Controller Routing](/docs/controllers#controller-routing)
+ - [Bundle Controllers](/docs/controllers#bundle-controllers)
+ - [Action Filters](/docs/controllers#action-filters)
+ - [Nested Controllers](/docs/controllers#nested-controllers)
+ - [RESTful Controllers](/docs/controllers#restful-controllers)
+ - [Dependency Injection](/docs/controllers#dependency-injection)
+ - [Controller Factory](/docs/controllers#controller-factory)
+- [Models & Libraries](/docs/models)
+- [Views & Responses](/docs/views)
+ - [The Basics](/docs/views#basics)
+ - [Binding Data To Views](/docs/views#binding-data-to-views)
+ - [Nesting Views](/docs/views#nesting-views)
+ - [Named Views](/docs/views#named-views)
+ - [View Composers](/docs/views#view-composers)
+ - [Redirects](/docs/views#redirects)
+ - [Redirecting With Data](/docs/views#redirecting-with-flash-data)
+ - [Downloads](/docs/views#downloads)
+ - [Errors](/docs/views#errors)
+ - [Managing Assets](/docs/views/assets)
+ - [Templating](/docs/views/templating)
+ - [Pagination](/docs/views/pagination)
+ - [Building HTML](/docs/views/html)
+ - [Building Forms](/docs/views/forms)
+- [Input & Cookies](/docs/input)
+ - [Input](/docs/input#input)
+ - [Files](/docs/input#files)
+ - [Old Input](/docs/input#old-input)
+ - [Redirecting With Old Input](/docs/input#redirecting-with-old-input)
+ - [Cookies](/docs/input#cookies)
+- [Bundles](/docs/bundles)
+ - [The Basics](/docs/bundles#the-basics)
+ - [Creating Bundles](/docs/bundles#creating-bundles)
+ - [Registering Bundles](/docs/bundles#registering-bundles)
+ - [Bundles & Class Loading](/docs/bundles#bundles-and-class-loading)
+ - [Starting Bundles](/docs/bundles#starting-bundles)
+ - [Routing To Bundles](/docs/bundles#routing-to-bundles)
+ - [Using Bundles](/docs/bundles#using-bundles)
+ - [Bundle Assets](/docs/bundles#bundle-assets)
+ - [Installing Bundles](/docs/bundles#installing-bundles)
+ - [Upgrading Bundles](/docs/bundles#upgrading-bundles)
+- [Class Auto Loading](/docs/loading)
+- [Errors & Logging](/docs/logging)
+- [Runtime Configuration](/docs/config)
+- [Examining Requests](/docs/requests)
+- [Generating URLs](/docs/urls)
+- [Events](/docs/events)
+- [Validation](/docs/validation)
+- [Working With Files](/docs/files)
+- [Working With Strings](/docs/strings)
+- [Localization](/docs/localization)
+- [Encryption](/docs/encryption)
+- [IoC Container](/docs/ioc)
+- [Unit Testing](/docs/testing)
+
+### Database
+
+- [Configuration](/docs/database/config)
+- [Raw Queries](/docs/database/raw)
+- [Fluent Query Builder](/docs/database/fluent)
+- [Eloquent ORM](/docs/database/eloquent)
+- [Schema Builder](/docs/database/schema)
+- [Migrations](/docs/database/migrations)
+- [Redis](/docs/database/redis)
+
+### Caching
+
+- [Configuration](/docs/cache/config)
+- [Usage](/docs/cache/usage)
+
+### Sessions
+
+- [Configuration](/docs/session/config)
+- [Usage](/docs/session/usage)
+
+### Authentication
+
+- [Configuration](/docs/auth/config)
+- [Usage](/docs/auth/usage)
+
+### Artisan CLI
+
+- [Tasks](/docs/artisan/tasks)
+ - [The Basics](/docs/artisan/tasks#the-basics)
+ - [Creating & Running Tasks](/docs/artisan/tasks#creating-tasks)
+ - [Bundle Tasks](/docs/artisan/tasks#bundle-tasks)
+ - [CLI Options](/docs/artisan/tasks#cli-options)
+- [Commands](/docs/artisan/commands)
\ No newline at end of file
diff --git a/laravel/documentation/controllers.md b/laravel/documentation/controllers.md
new file mode 100644
index 0000000..220c10a
--- /dev/null
+++ b/laravel/documentation/controllers.md
@@ -0,0 +1,206 @@
+# Controllers
+
+## Contents
+
+- [The Basics](#the-basics)
+- [Controller Routing](#controller-routing)
+- [Bundle Controllers](#bundle-controllers)
+- [Action Filters](#action-filters)
+- [Nested Controllers](#nested-controllers)
+- [Controller Layouts](#controller-layouts)
+- [RESTful Controllers](#restful-controllers)
+- [Dependency Injection](#dependency-injection)
+- [Controller Factory](#controller-factory)
+
+
+## The Basics
+
+Controllers are classes that are responsible for accepting user input and managing interactions between models, libraries, and views. Typically, they will ask a model for data, and then return a view that presents that data to the user.
+
+The usage of controllers is the most common method of implementing application logic in modern web-development. However, Laravel also empowers developers to implement their application logic within routing declarations. This is explored in detail in the [routing document](/docs/routing). New users are encourage to start with controllers. There is nothing that route-based application logic can do that controllers can't.
+
+Controller classes should be stored in **application/controllers** and should extend the Base\_Controller class. A Home\_Controller class is included with Laravel.
+
+#### Creating a simple controller:
+
+ class Admin_Controller extends Base_Controller
+ {
+
+ public function action_index()
+ {
+ //
+ }
+
+ }
+
+**Actions** are the name of controller methods that are intended to be web-accessible. Actions should be prefixed with "action\_". All other methods, regardless of scope, will not be web-accessible.
+
+> **Note:** The Base\_Controller class extends the main Laravel Controller class, and gives you a convenient place to put methods that are common to many controllers.
+
+
+## Controller Routing
+
+It is important to be aware that all routes in Laravel must be explicitly defined, including routes to controllers.
+
+This means that controller methods that have not been exposed through route registration **cannot** be accessed. It's possible to automatically expose all methods within a controller using controller route registration. Controller route registrations are typically defined in **application/routes.php**.
+
+Check [the routing page](/docs/routing#controller-routing) for more information on routing to controllers.
+
+
+## Bundle Controllers
+
+Bundles are Laravel's modular package system. Bundles can easily configured to handle requests to your application. We'll be going over [bundles in more detail](/docs/bundles) in another document.
+
+Creating controllers that belong to bundles is almost identical to creating your application controllers. Just prefix the controller class name with the name of the bundle, so if your bundle is named "admin", your controller classes would look like this:
+
+#### Creating a bundle controller class:
+
+ class Admin_Home_Controller extends Base_Controller
+ {
+
+ public function action_index()
+ {
+ return "Hello Admin!";
+ }
+
+ }
+
+But, how do you register a bundle controller with the router? It's simple. Here's what it looks like:
+
+#### Registering a bundle's controller with the router:
+
+ Route::controller('admin::home');
+
+Great! Now we can access our "admin" bundle's home controller from the web!
+
+> **Note:** Throughout Laravel the double-colon syntax is used to denote bundles. More information on bundles can be found in the [bundle documentation](/docs/bundles).
+
+
+## Action Filters
+
+Action filters are methods that can be run before or after a controller action. With Laravel you don't only have control over which filters are assigned to which actions. But, you can also choose which http verbs (post, get, put, and delete) will activate a filter.
+
+You can assign "before" and "after" filters to controller actions within the controller's constructor.
+
+#### Attaching a filter to all actions:
+
+ $this->filter('before', 'auth');
+
+In this example the 'auth' filter will be run before every action within this controller. The auth action comes out-of-the-box with Laravel and can be found in **application/routes.php**. The auth filter verifies that a user is logged in and redirects them to 'login' if they are not.
+
+#### Attaching a filter to only some actions:
+
+ $this->filter('before', 'auth')->only(array('index', 'list'));
+
+In this example the auth filter will be run before the action_index() or action_list() methods are run. Users must be logged in before having access to these pages. However, no other actions within this controller require an authenticated session.
+
+#### Attaching a filter to all except a few actions:
+
+ $this->filter('before', 'auth')->except(array('add', 'posts'));
+
+Much like the previous example, this declaration ensures that the auth filter is run on only some of this controller's actions. Instead of declaring to which actions the filter applies we are instead declaring the actions that will not require authenticated sessions. It can sometimes be safer to use the 'except' method as it's possible to add new actions to this controller and to forget to add them to only(). This could potentially lead your controller's action being unintentionally accessible by users who haven't been authenticated.
+
+#### Attaching a filter to run on POST:
+
+ $this->filter('before', 'csrf')->on('post');
+
+This example shows how a filter can be run only on a specific http verb. In this case we're running the csrf filter only when a form post is made. The csrf filter is designed to prevent form posts from other systems (spam bots for example) and comes by default with Laravel. You can find the csrf filter in **application/routes.php**.
+
+*Further Reading:*
+
+- *[Route Filters](/docs/routing#filters)*
+
+
+## Nested Controllers
+
+Controllers may be located within any number of sub-directories within the main **application/controllers** folder.
+
+Define the controller class and store it in **controllers/admin/panel.php**.
+
+ class Admin_Panel_Controller extends Base_Controller
+ {
+
+ public function action_index()
+ {
+ //
+ }
+
+ }
+
+#### Register the nested controller with the router using "dot" syntax:
+
+ Route::controller('admin.panel');
+
+> **Note:** When using nested controllers, always register your controllers from most nested to least nested in order to avoid shadowing controller routes.
+
+#### Access the "index" action of the controller:
+
+ http://localhost/admin/panel
+
+
+## Controller Layouts
+
+Full documentation on using layouts with Controllers [can be found on the Templating page](http://laravel.com/docs/views/templating).
+
+
+## RESTful Controllers
+
+Instead of prefixing controller actions with "action_", you may prefix them with the HTTP verb they should respond to.
+
+#### Adding the RESTful property to the controller:
+
+ class Home_Controller extends Base_Controller
+ {
+
+ public $restful = true;
+
+ }
+
+#### Building RESTful controller actions:
+
+ class Home_Controller extends Base_Controller
+ {
+
+ public $restful = true;
+
+ public function get_index()
+ {
+ //
+ }
+
+ public function post_index()
+ {
+ //
+ }
+
+ }
+
+This is particularly useful when building CRUD methods as you can separate the logic which populates and renders a form from the logic that validates and stores the results.
+
+
+## Dependency Injection
+
+If you are focusing on writing testable code, you will probably want to inject dependencies into the constructor of your controller. No problem. Just register your controller in the [IoC container](/docs/ioc). When registering the controller with the container, prefix the key with **controller**. So, in our **application/start.php** file, we could register our user controller like so:
+
+ IoC::register('controller: user', function()
+ {
+ return new User_Controller;
+ });
+
+When a request to a controller enters your application, Laravel will automatically determine if the controller is registered in the container, and if it is, will use the container to resolve an instance of the controller.
+
+> **Note:** Before diving into controller dependency injection, you may wish to read the documentation on Laravel's beautiful [IoC container](/docs/ioc).
+
+
+## Controller Factory
+
+If you want even more control over the instantiation of your controllers, such as using a third-party IoC container, you'll need to use the Laravel controller factory.
+
+**Register an event to handle controller instantiation:**
+
+ Event::listen(Controller::factory, function($controller)
+ {
+ return new $controller;
+ });
+
+The event will receive the class name of the controller that needs to be resolved. All you need to do is return an instance of the controller.
diff --git a/laravel/documentation/database/config.md b/laravel/documentation/database/config.md
new file mode 100644
index 0000000..a4eddb6
--- /dev/null
+++ b/laravel/documentation/database/config.md
@@ -0,0 +1,46 @@
+# Database Configuration
+
+## Contents
+
+- [Quick Start Using SQLite](#quick)
+- [Configuring Other Databases](#server)
+- [Setting The Default Connection Name](#default)
+
+Laravel supports the following databases out of the box:
+
+- MySQL
+- PostgreSQL
+- SQLite
+- SQL Server
+
+All of the database configuration options live in the **application/config/database.php** file.
+
+
+## Quick Start Using SQLite
+
+[SQLite](http://sqlite.org) is an awesome, zero-configuration database system. By default, Laravel is configured to use a SQLite database. Really, you don't have to change anything. Just drop a SQLite database named **application.sqlite** into the **application/storage/database** directory. You're done.
+
+Of course, if you want to name your database something besides "application", you can modify the database option in the SQLite section of the **application/config/database.php** file:
+
+ 'sqlite' => array(
+ 'driver' => 'sqlite',
+ 'database' => 'your_database_name',
+ )
+
+If your application receives less than 100,000 hits per day, SQLite should be suitable for production use in your application. Otherwise, consider using MySQL or PostgreSQL.
+
+> **Note:** Need a good SQLite manager? Check out this [Firefox extension](https://addons.mozilla.org/en-US/firefox/addon/sqlite-manager/).
+
+
+## Configuring Other Databases
+
+If you are using MySQL, SQL Server, or PostgreSQL, you will need to edit the configuration options in **application/config/database.php**. In the configuration file you can find sample configurations for each of these systems. Just change the options as necessary for your server and set the default connection name.
+
+
+## Setting The Default Connection Name
+
+As you have probably noticed, each database connection defined in the **application/config/database.php** file has a name. By default, there are three connections defined: **sqlite**, **mysql**, **sqlsrv**, and **pgsql**. You are free to change these connection names. The default connection can be specified via the **default** option:
+
+ 'default' => 'sqlite';
+
+The default connection will always be used by the [fluent query builder](/docs/database/fluent). If you need to change the default connection during a request, use the **Config::set** method.
\ No newline at end of file
diff --git a/laravel/documentation/database/eloquent.md b/laravel/documentation/database/eloquent.md
new file mode 100644
index 0000000..0706b7d
--- /dev/null
+++ b/laravel/documentation/database/eloquent.md
@@ -0,0 +1,501 @@
+# Eloquent ORM
+
+## Contents
+
+- [The Basics](#the-basics)
+- [Conventions](#conventions)
+- [Retrieving Models](#get)
+- [Aggregates](#aggregates)
+- [Inserting & Updating Models](#save)
+- [Relationships](#relationships)
+- [Inserting Related Models](#inserting-related-models)
+- [Working With Intermediate Tables](#intermediate-tables)
+- [Eager Loading](#eager)
+- [Constraining Eager Loads](#constraining-eager-loads)
+- [Setter & Getter Methods](#getter-and-setter-methods)
+- [Mass-Assignment](#mass-assignment)
+- [Converting Models To Arrays](#to-array)
+
+
+## The Basics
+
+An ORM is an [object-relational mapper](http://en.wikipedia.org/wiki/Object-relational_mapping), and Laravel has one that you will absolutely love to use. It is named "Eloquent" because it allows you to work with your database objects and relationships using an eloquent and expressive syntax. In general, you will define one Eloquent model for each table in your database. To get started, let's define a simple model:
+
+ class User extends Eloquent {}
+
+Nice! Notice that our model extends the **Eloquent** class. This class will provide all of the functionality you need to start working eloquently with your database.
+
+> **Note:** Typically, Eloquent models live in the **application/models** directory.
+
+
+## Conventions
+
+Eloquent makes a few basic assumptions about your database structure:
+
+- Each table should have a primary key named **id**.
+- Each table name should be the plural form of its corresponding model name.
+
+Sometimes you may wish to use a table name other than the plural form of your model. No problem. Just add a static **table** property your model:
+
+ class User extends Eloquent {
+
+ public static $table = 'my_users';
+
+ }
+
+
+## Retrieving Models
+
+Retrieving models using Eloquent is refreshingly simple. The most basic way to retrieve an Eloquent model is the static **find** method. This method will return a single model by primary key with properties corresponding to each column on the table:
+
+ $user = User::find(1);
+
+ echo $user->email;
+
+The find method will execute a query that looks something like this:
+
+ SELECT * FROM "users" WHERE "id" = 1
+
+Need to retrieve an entire table? Just use the static **all** method:
+
+ $users = User::all();
+
+ foreach ($users as $user)
+ {
+ echo $user->email;
+ }
+
+Of course, retrieving an entire table isn't very helpful. Thankfully, **every method that is available through the fluent query builder is available in Eloquent**. Just begin querying your model with a static call to one of the [query builder](/docs/database/query) methods, and execute the query using the **get** or **first** method. The get method will return an array of models, while the first method will return a single model:
+
+ $user = User::where('email', '=', $email)->first();
+
+ $user = User::where_email($email)->first();
+
+ $users = User::where_in('id', array(1, 2, 3))->or_where('email', '=', $email)->get();
+
+ $users = User::order_by('votes', 'desc')->take(10)->get();
+
+> **Note:** If no results are found, the **first** method will return NULL. The **all** and **get** methods return an empty array.
+
+
+## Aggregates
+
+Need to get a **MIN**, **MAX**, **AVG**, **SUM**, or **COUNT** value? Just pass the column to the appropriate method:
+
+ $min = User::min('id');
+
+ $max = User::max('id');
+
+ $avg = User::avg('id');
+
+ $sum = User::sum('id');
+
+ $count = User::count();
+
+Of course, you may wish to limit the query using a WHERE clause first:
+
+ $count = User::where('id', '>', 10)->count();
+
+
+## Inserting & Updating Models
+
+Inserting Eloquent models into your tables couldn't be easier. First, instantiate a new model. Second, set its properties. Third, call the **save** method:
+
+ $user = new User;
+
+ $user->email = 'example@gmail.com';
+ $user->password = 'secret';
+
+ $user->save();
+
+Alternatively, you may use the **create** method, which will insert a new record into the database and return the model instance for the newly inserted record, or **false** if the insert failed.
+
+ $user = User::create(array('email' => 'example@gmail.com'));
+
+Updating models is just as simple. Instead of instantiating a new model, retrieve one from your database. Then, set its properties and save:
+
+ $user = User::find(1);
+
+ $user->email = 'new_email@gmail.com';
+ $user->password = 'new_secret';
+
+ $user->save();
+
+Need to maintain creation and update timestamps on your database records? With Eloquent, you don't have to worry about it. Just add a static **timestamps** property to your model:
+
+ class User extends Eloquent {
+
+ public static $timestamps = true;
+
+ }
+
+Next, add **created_at** and **updated_at** date columns to your table. Now, whenever you save the model, the creation and update timestamps will be set automatically. You're welcome.
+
+> **Note:** You can change the default timezone of your application in the **application/config/application.php** file.
+
+
+## Relationships
+
+Unless you're doing it wrong, your database tables are probably related to one another. For instance, an order may belong to a user. Or, a post may have many comments. Eloquent makes defining relationships and retrieving related models simple and intuitive. Laravel supports three types of relationships:
+
+- [One-To-One](#one-to-one)
+- [One-To-Many](#one-to-many)
+- [Many-To-Many](#many-to-many)
+
+To define a relationship on an Eloquent model, you simply create a method that returns the result of either the **has\_one**, **has\_many**, **belongs\_to**, or **has\_many\_and\_belongs\_to** method. Let's examine each one in detail.
+
+
+### One-To-One
+
+A one-to-one relationship is the most basic form of relationship. For example, let's pretend a user has one phone. Simply describe this relationship to Eloquent:
+
+ class User extends Eloquent {
+
+ public function phone()
+ {
+ return $this->has_one('Phone');
+ }
+
+ }
+
+Notice that the name of the related model is passed to the **has_one** method. You can now retrieve the phone of a user through the **phone** method:
+
+ $phone = User::find(1)->phone()->first();
+
+Let's examine the SQL performed by this statement. Two queries will be performed: one to retrieve the user and one to retrieve the user's phone:
+
+ SELECT * FROM "users" WHERE "id" = 1
+
+ SELECT * FROM "phones" WHERE "user_id" = 1
+
+Note that Eloquent assumes the foreign key of the relationship will be **user\_id**. Most foreign keys will follow this **model\_id** convention; however, if you want to use a different column name as the foreign key, just pass it in the second parameter to the method:
+
+ return $this->has_one('Phone', 'my_foreign_key');
+
+Want to just retrieve the user's phone without calling the first method? No problem. Just use the **dynamic phone property**. Eloquent will automatically load the relationship for you, and is even smart enough to know whether to call the get (for one-to-many relationships) or first (for one-to-one relationships) method:
+
+ $phone = User::find(1)->phone;
+
+What if you need to retrieve a phone's user? Since the foreign key (**user\_id**) is on the phones table, we should describe this relationship using the **belongs\_to** method. It makes sense, right? Phones belong to users. When using the **belongs\_to** method, the name of the relationship method should correspond to the foreign key (sans the **\_id**). Since the foreign key is **user\_id**, your relationship method should be named **user**:
+
+ class Phone extends Eloquent {
+
+ public function user()
+ {
+ return $this->belongs_to('User');
+ }
+
+ }
+
+Great! You can now access a User model through a Phone model using either your relationship method or dynamic property:
+
+ echo Phone::find(1)->user()->first()->email;
+
+ echo Phone::find(1)->user->email;
+
+
+### One-To-Many
+
+Assume a blog post has many comments. It's easy to define this relationship using the **has_many** method:
+
+ class Post extends Eloquent {
+
+ public function comments()
+ {
+ return $this->has_many('Comment');
+ }
+
+ }
+
+Now, simply access the post comments through the relationship method or dynamic property:
+
+ $comments = Post::find(1)->comments()->get();
+
+ $comments = Post::find(1)->comments;
+
+Both of these statements will execute the following SQL:
+
+ SELECT * FROM "posts" WHERE "id" = 1
+
+ SELECT * FROM "comments" WHERE "post_id" = 1
+
+Want to join on a different foreign key? No problem. Just pass it in the second parameter to the method:
+
+ return $this->has_many('Comment', 'my_foreign_key');
+
+You may be wondering: _If the dynamic properties return the relationship and require less keystokes, why would I ever use the relationship methods?_ Actually, relationship methods are very powerful. They allow you to continue to chain query methods before retrieving the relationship. Check this out:
+
+ echo Post::find(1)->comments()->order_by('votes', 'desc')->take(10)->get();
+
+
+### Many-To-Many
+
+Many-to-many relationships are the most complicated of the three relationships. But don't worry, you can do this. For example, assume a User has many Roles, but a Role can also belong to many Users. Three database tables must be created to accomplish this relationship: a **users** table, a **roles** table, and a **role_user** table. The structure for each table looks like this:
+
+**Users:**
+
+ id - INTEGER
+ email - VARCHAR
+
+**Roles:**
+
+ id - INTEGER
+ name - VARCHAR
+
+**Roles_Users:**
+
+ user_id - INTEGER
+ role_id - INTEGER
+
+Now you're ready to define the relationship on your models using the **has\_many\_and\_belongs\_to** method:
+
+ class User extends Eloquent {
+
+ public function roles()
+ {
+ return $this->has_many_and_belongs_to('Role');
+ }
+
+ }
+
+Great! Now it's time to retrieve a user's roles:
+
+ $roles = User::find(1)->roles()->get();
+
+Or, as usual, you may retrieve the relationship through the dynamic roles property:
+
+ $roles = User::find(1)->roles;
+
+As you may have noticed, the default name of the intermediate table is the singular names of the two related models arranged alphabetically and concatenated by an underscore. However, you are free to specify your own table name. Simply pass the table name in the second parameter to the **has\_and\_belongs\_to\_many** method:
+
+ class User extends Eloquent {
+
+ public function roles()
+ {
+ return $this->has_many_and_belongs_to('Role', 'user_roles');
+ }
+
+ }
+
+
+## Inserting Related Models
+
+Let's assume you have a **Post** model that has many comments. Often you may want to insert a new comment for a given post. Instead of manually setting the **post_id** foreign key on your model, you may insert the new comment from it's owning Post model. Here's what it looks like:
+
+ $comment = new Comment(array('message' => 'A new comment.'));
+
+ $post = Post::find(1);
+
+ $post->comments()->insert($comment);
+
+When inserting related models through their parent model, the foreign key will automatically be set. So, in this case, the "post_id" was automatically set to "1" on the newly inserted comment.
+
+
+When working with `has_many` relationships, you may use the `save` method to insert / update related models:
+
+ $comments = array(
+ array('message' => 'A new comment.'),
+ array('message' => 'A second comment.'),
+ );
+
+ $post = Post::find(1);
+
+ $post->comments()->save($comments);
+
+### Inserting Related Models (Many-To-Many)
+
+This is even more helpful when working with many-to-many relationships. For example, consider a **User** model that has many roles. Likewise, the **Role** model may have many users. So, the intermediate table for this relationship has "user_id" and "role_id" columns. Now, let's insert a new Role for a User:
+
+ $role = new Role(array('title' => 'Admin'));
+
+ $user = User::find(1);
+
+ $user->roles()->insert($role);
+
+Now, when the Role is inserted, not only is the Role inserted into the "roles" table, but a record in the intermediate table is also inserted for you. It couldn't be easier!
+
+However, you may often only want to insert a new record into the intermediate table. For example, perhaps the role you wish to attach to the user already exists. Just use the attach method:
+
+ $user->roles()->attach($role_id);
+
+
+Alternatively, you can use the `sync` method, which accepts an array of IDs to "sync" with the intermediate table. After this operation is complete, only the IDs in the array will be on the intermediate table.
+
+ $user->roles()->sync(array(1, 2, 3));
+
+
+## Working With Intermediate Tables
+
+As your probably know, many-to-many relationships require the presence of an intermediate table. Eloquent makes it a breeze to maintain this table. For example, let's assume we have a **User** model that has many roles. And, likewise, a **Role** model that has many users. So the intermediate table has "user_id" and "role_id" columns. We can access the pivot table for the relationship like so:
+
+ $user = User::find(1);
+
+ $pivot = $user->roles()->pivot();
+
+Once we have an instance of the pivot table, we can use it just like any other Eloquent model:
+
+ foreach ($user->roles()->pivot()->get() as $row)
+ {
+ //
+ }
+
+You may also access the specific intermediate table row associated with a given record. For example:
+
+ $user = User::find(1);
+
+ foreach ($user->roles as $role)
+ {
+ echo $role->pivot->created_at;
+ }
+
+Notice that each related **Role** model we retrieved is automatically assigned a **pivot** attribute. This attribute contains a model representing the intermediate table record associated with that related model.
+
+Sometimes you may wish to remove all of the record from the intermediate table for a given model relationship. For instance, perhaps you want to remove all of the assigned roles from a user. Here's how to do it:
+
+ $user = User::find(1);
+
+ $user->roles()->delete();
+
+Note that this does not delete the roles from the "roles" table, but only removes the records from the intermediate table which associated the roles with the given user.
+
+
+## Eager Loading
+
+Eager loading exists to alleviate the N + 1 query problem. Exactly what is this problem? Well, pretend each Book belongs to an Author. We would describe this relationship like so:
+
+ class Book extends Eloquent {
+
+ public function author()
+ {
+ return $this->belongs_to('Author');
+ }
+
+ }
+
+Now, examine the following code:
+
+ foreach (Book::all() as $book)
+ {
+ echo $book->author->name;
+ }
+
+How many queries will be executed? Well, one query will be executed to retrieve all of the books from the table. However, another query will be required for each book to retrieve the author. To display the author name for 25 books would require **26 queries**. See how the queries can add up fast?
+
+Thankfully, you can eager load the author models using the **with** method. Simply mention the **function name** of the relationship you wish to eager load:
+
+ foreach (Book::with('author')->get() as $book)
+ {
+ echo $book->author->name;
+ }
+
+In this example, **only two queries will be executed**!
+
+ SELECT * FROM "books"
+
+ SELECT * FROM "authors" WHERE "id" IN (1, 2, 3, 4, 5, ...)
+
+Obviously, wise use of eager loading can dramatically increase the performance of your application. In the example above, eager loading cut the execution time in half.
+
+Need to eager load more than one relationship? It's easy:
+
+ $books = Book::with(array('author', 'publisher'))->get();
+
+> **Note:** When eager loading, the call to the static **with** method must always be at the beginning of the query.
+
+You may even eager load nested relationships. For example, let's assume our **Author** model has a "contacts" relationship. We can eager load both of the relationships from our Book model like so:
+
+ $books = Book::with(array('author', 'author.contacts'))->get();
+
+
+## Constraining Eager Loads
+
+Sometimes you may wish to eager load a relationship, but also specify a condition for the eager load. It's simple. Here's what it looks like:
+
+ $users = User::with(array('posts' => function($query)
+ {
+ $query->where('title', 'like', '%first%');
+
+ }))->get();
+
+In this example, we're eager loading the posts for the users, but only if the post's "title" column contains the word "first".
+
+
+## Getter & Setter Methods
+
+Setters allow you to handle attribute assignment with custom methods. Define a setter by appending "set_" to the intended attribute's name.
+
+ public function set_password($password)
+ {
+ $this->set_attribute('hashed_password', Hash::make($password));
+ }
+
+Call a setter method as a variable (without parenthesis) using the name of the method without the "set_" prefix.
+
+ $this->password = "my new password";
+
+Getters are very similar. They can be used to modify attributes before they're returned. Define a getter by appending "get_" to the intended attribute's name.
+
+ public function get_published_date()
+ {
+ return date('M j, Y', $this->get_attribute('published_at'));
+ }
+
+Call the getter method as a variable (without parenthesis) using the name of the method without the "get_" prefix.
+
+ echo $this->published_date;
+
+
+## Mass-Assignment
+
+Mass-assignment is the practice of passing an associative array to a model method which then fills the model's attributes with the values from the array. Mass-assignment can be done by passing an array to the model's constructor:
+
+ $user = new User(array(
+ 'username' => 'first last',
+ 'password' => 'disgaea'
+ ));
+
+ $user->save();
+
+Or, mass-assignment may be accomplished using the **fill** method.
+
+ $user = new User;
+
+ $user->fill(array(
+ 'username' => 'first last',
+ 'password' => 'disgaea'
+ ));
+
+ $user->save();
+
+By default, all attribute key/value pairs will be store during mass-assignment. However, it is possible to create a white-list of attributes that will be set. If the accessible attribute white-list is set then no attributes other than those specified will be set during mass-assignment.
+
+You can specify accessible attributes by assigning the **$accessible** static array. Each element contains the name of a white-listed attribute.
+
+ public static $accessible = array('email', 'password', 'name');
+
+Alternatively, you may use the **accessible** method from your model:
+
+ User::accessible(array('email', 'password', 'name'));
+
+> **Note:** Utmost caution should be taken when mass-assigning using user-input. Technical oversights could cause serious security vulnerabilities.
+
+
+## Converting Models To Arrays
+
+When building JSON APIs, you will often need to convert your models to array so they can be easily serialized. It's really simple.
+
+#### Convert a model to an array:
+
+ return json_encode($user->to_array());
+
+The `to_array` method will automatically grab all of the attributes on your model, as well as any loaded relationships.
+
+Sometimes you may wish to limit the attributes that are included in your model's array, such as passwords. To do this, add a `hidden` attribute definition to your model:
+
+#### Excluding attributes from the array:
+
+ class User extends Eloquent {
+
+ public static $hidden = array('password');
+
+ }
\ No newline at end of file
diff --git a/laravel/documentation/database/fluent.md b/laravel/documentation/database/fluent.md
new file mode 100644
index 0000000..6ab3447
--- /dev/null
+++ b/laravel/documentation/database/fluent.md
@@ -0,0 +1,270 @@
+# Fluent Query Builder
+
+## Contents
+
+- [The Basics](#the-basics)
+- [Retrieving Records](#get)
+- [Building Where Clauses](#where)
+- [Nested Where Clauses](#nested-where)
+- [Dynamic Where Clauses](#dynamic)
+- [Table Joins](#joins)
+- [Ordering Results](#ordering)
+- [Skip & Take](#limit)
+- [Aggregates](#aggregates)
+- [Expressions](#expressions)
+- [Inserting Records](#insert)
+- [Updating Records](#update)
+- [Deleting Records](#delete)
+
+## The Basics
+
+The Fluent Query Builder is Laravel's powerful fluent interface for building SQL queries and working with your database. All queries use prepared statements and are protected against SQL injection.
+
+You can begin a fluent query using the **table** method on the DB class. Just mention the table you wish to query:
+
+ $query = DB::table('users');
+
+You now have a fluent query builder for the "users" table. Using this query builder, you can retrieve, insert, update, or delete records from the table.
+
+
+## Retrieving Records
+
+#### Retrieving an array of records from the database:
+
+ $users = DB::table('users')->get();
+
+> **Note:** The **get** method returns an array of objects with properties corresponding to the column on the table.
+
+#### Retrieving a single record from the database:
+
+ $user = DB::table('users')->first();
+
+#### Retrieving a single record by its primary key:
+
+ $user = DB::table('users')->find($id);
+
+> **Note:** If no results are found, the **first** method will return NULL. The **get** method will return an empty array.
+
+#### Retrieving the value of a single column from the database:
+
+ $email = DB::table('users')->where('id', '=', 1)->only('email');
+
+#### Only selecting certain columns from the database:
+
+ $user = DB::table('users')->get(array('id', 'email as user_email'));
+
+#### Selecting distinct results from the database:
+
+ $user = DB::table('users')->distinct()->get();
+
+
+## Building Where Clauses
+
+### where and or\_where
+
+There are a variety of methods to assist you in building where clauses. The most basic of these methods are the **where** and **or_where** methods. Here is how to use them:
+
+ return DB::table('users')
+ ->where('id', '=', 1)
+ ->or_where('email', '=', 'example@gmail.com')
+ ->first();
+
+Of course, you are not limited to simply checking equality. You may also use **greater-than**, **less-than**, **not-equal**, and **like**:
+
+ return DB::table('users')
+ ->where('id', '>', 1)
+ ->or_where('name', 'LIKE', '%Taylor%')
+ ->first();
+
+As you may have assumed, the **where** method will add to the query using an AND condition, while the **or_where** method will use an OR condition.
+
+### where\_in, where\_not\_in, or\_where\_in, and or\_where\_not\_in
+
+The suite of **where_in** methods allows you to easily construct queries that search an array of values:
+
+ DB::table('users')->where_in('id', array(1, 2, 3))->get();
+
+ DB::table('users')->where_not_in('id', array(1, 2, 3))->get();
+
+ DB::table('users')
+ ->where('email', '=', 'example@gmail.com')
+ ->or_where_in('id', array(1, 2, 3))
+ ->get();
+
+ DB::table('users')
+ ->where('email', '=', 'example@gmail.com')
+ ->or_where_not_in('id', array(1, 2, 3))
+ ->get();
+
+### where\_null, where\_not\_null, or\_where\_null, and or\_where\_not\_null
+
+The suite of **where_null** methods makes checking for NULL values a piece of cake:
+
+ return DB::table('users')->where_null('updated_at')->get();
+
+ return DB::table('users')->where_not_null('updated_at')->get();
+
+ return DB::table('users')
+ ->where('email', '=', 'example@gmail.com')
+ ->or_where_null('updated_at')
+ ->get();
+
+ return DB::table('users')
+ ->where('email', '=', 'example@gmail.com')
+ ->or_where_not_null('updated_at')
+ ->get();
+
+
+## Nested Where Clauses
+
+You may discover the need to group portions of a WHERE clause within parentheses. Just pass a Closure as parameter to the **where** or **or_where** methods:
+
+ $users = DB::table('users')
+ ->where('id', '=', 1)
+ ->or_where(function($query)
+ {
+ $query->where('age', '>', 25);
+ $query->where('votes' '>', 100);
+ })
+ ->get();
+
+The example above would generate a query that looks like:
+
+ SELECT * FROM "users" WHERE "id" = ? OR ("age" > ? AND "votes" > ?)
+
+
+## Dynamic Where Clauses
+
+Dynamic where methods are great way to increase the readability of your code. Here are some examples:
+
+ $user = DB::table('users')->where_email('example@gmail.com')->first();
+
+ $user = DB::table('users')->where_email_and_password('example@gmail.com', 'secret');
+
+ $user = DB::table('users')->where_id_or_name(1, 'Fred');
+
+
+
+## Table Joins
+
+Need to join to another table? Try the **join** and **left\_join** methods:
+
+ DB::table('users')
+ ->join('phone', 'users.id', '=', 'phone.user_id')
+ ->get(array('users.email', 'phone.number'));
+
+The **table** you wish to join is passed as the first parameter. The remaining three parameters are used to construct the **ON** clause of the join.
+
+Once you know how to use the join method, you know how to **left_join**. The method signatures are the same:
+
+ DB::table('users')
+ ->left_join('phone', 'users.id', '=', 'phone.user_id')
+ ->get(array('users.email', 'phone.number'));
+
+You may also specify multiple conditions for an **ON** clause by passing a Closure as the second parameter of the join:
+
+ DB::table('users')
+ ->join('phone', function($join)
+ {
+ $join->on('users.id', '=', 'phone.user_id');
+ $join->or_on('users.id', '=', 'phone.contact_id');
+ })
+ ->get(array('users.email', 'phone.numer'));
+
+
+## Ordering Results
+
+You can easily order the results of your query using the **order_by** method. Simply mention the column and direction (desc or asc) of the sort:
+
+ return DB::table('users')->order_by('email', 'desc')->get();
+
+Of course, you may sort on as many columns as you wish:
+
+ return DB::table('users')
+ ->order_by('email', 'desc')
+ ->order_by('name', 'asc')
+ ->get();
+
+
+## Skip & Take
+
+If you would like to **LIMIT** the number of results returned by your query, you can use the **take** method:
+
+ return DB::table('users')->take(10)->get();
+
+To set the **OFFSET** of your query, use the **skip** method:
+
+ return DB::table('users')->skip(10)->get();
+
+
+## Aggregates
+
+Need to get a **MIN**, **MAX**, **AVG**, **SUM**, or **COUNT** value? Just pass the column to the query:
+
+ $min = DB::table('users')->min('age');
+
+ $max = DB::table('users')->max('weight');
+
+ $avg = DB::table('users')->avg('salary');
+
+ $sum = DB::table('users')->sum('votes');
+
+ $count = DB::table('users')->count();
+
+Of course, you may wish to limit the query using a WHERE clause first:
+
+ $count = DB::table('users')->where('id', '>', 10)->count();
+
+
+## Expressions
+
+Sometimes you may need to set the value of a column to a SQL function such as **NOW()**. Usually a reference to now() would automatically be quoted and escaped. To prevent this use the **raw** method on the **DB** class. Here's what it looks like:
+
+ DB::table('users')->update(array('updated_at' => DB::raw('NOW()')));
+
+The **raw** method tells the query to inject the contents of the expression into the query as a string rather than a bound parameter. For example, you can also use expressions to increment column values:
+
+ DB::table('users')->update(array('votes' => DB::raw('votes + 1')));
+
+Of course, convenient methods are provided for **increment** and **decrement**:
+
+ DB::table('users')->increment('votes');
+
+ DB::table('users')->decrement('votes');
+
+
+## Inserting Records
+
+The insert method expects an array of values to insert. The insert method will return true or false, indicating whether the query was successful:
+
+ DB::table('users')->insert(array('email' => 'example@gmail.com'));
+
+Inserting a record that has an auto-incrementing ID? You can use the **insert\_get\_id** method to insert a record and retrieve the ID:
+
+ $id = DB::table('users')->insert_get_id(array('email' => 'example@gmail.com'));
+
+> **Note:** The **insert\_get\_id** method expects the name of the auto-incrementing column to be "id".
+
+
+## Updating Records
+
+To update records simply pass an array of values to the **update** method:
+
+ $affected = DB::table('users')->update(array('email' => 'new_email@gmail.com'));
+
+Of course, when you only want to update a few records, you should add a WHERE clause before calling the update method:
+
+ $affected = DB::table('users')
+ ->where('id', '=', 1)
+ ->update(array('email' => 'new_email@gmail.com'));
+
+
+## Deleting Records
+
+When you want to delete records from your database, simply call the **delete** method:
+
+ $affected = DB::table('users')->where('id', '=', 1)->delete();
+
+Want to quickly delete a record by its ID? No problem. Just pass the ID into the delete method:
+
+ $affected = DB::table('users')->delete(1);
\ No newline at end of file
diff --git a/laravel/documentation/database/migrations.md b/laravel/documentation/database/migrations.md
new file mode 100644
index 0000000..8c09563
--- /dev/null
+++ b/laravel/documentation/database/migrations.md
@@ -0,0 +1,72 @@
+# Migrations
+
+## Contents
+
+- [The Basics](#the-basics)
+- [Prepping Your Database](#prepping-your-database)
+- [Creating Migrations](#creating-migrations)
+- [Running Migrations](#running-migrations)
+- [Rolling Back](#rolling-back)
+
+
+## The Basics
+
+Think of migrations as a type of version control for your database. Let's say your working on a team, and you all have local databases for development. Good ole' Eric makes a change to the database and checks in his code that uses the new column. You pull in the code, and your application breaks because you don't have the new column. What do you do? Migrations are the answer. Let's dig in deeper to find out how to use them!
+
+
+## Prepping Your Database
+
+Before you can run migrations, we need to do some work on your database. Laravel uses a special table to keep track of which migrations have already run. To create this table, just use the Artisan command-line:
+
+**Creating the Laravel migrations table:**
+
+ php artisan migrate:install
+
+
+## Creating Migrations
+
+You can easily create migrations through Laravel's "Artisan" CLI. It looks like this:
+
+**Creating a migration**
+
+ php artisan migrate:make create_users_table
+
+Now, check your **application/migrations** folder. You should see your brand new migration! Notice that it also contains a timestamp. This allows Laravel to run your migrations in the correct order.
+
+You may also create migrations for a bundle.
+
+**Creating a migration for a bundle:**
+
+ php artisan migrate:make bundle::create_users_table
+
+*Further Reading:*
+
+- [Schema Builder](/docs/database/schema)
+
+
+## Running Migrations
+
+**Running all outstanding migrations in application and bundles:**
+
+ php artisan migrate
+
+**Running all outstanding migrations in the application:**
+
+ php artisan migrate application
+
+**Running all outstanding migrations in a bundle:**
+
+ php artisan migrate bundle
+
+
+## Rolling Back
+
+When you roll back a migration, Laravel rolls back the entire migration "operation". So, if the last migration command ran 122 migrations, all 122 migrations would be rolled back.
+
+**Rolling back the last migration operation:**
+
+ php artisan migrate:rollback
+
+**Roll back all migrations that have ever run:**
+
+ php artisan migrate:reset
\ No newline at end of file
diff --git a/laravel/documentation/database/raw.md b/laravel/documentation/database/raw.md
new file mode 100644
index 0000000..424ba27
--- /dev/null
+++ b/laravel/documentation/database/raw.md
@@ -0,0 +1,56 @@
+# Raw Queries
+
+## Contents
+
+- [The Basics](#the-basics)
+- [Other Query Methods](#other-query-methods)
+- [PDO Connections](#pdo-connections)
+
+
+## The Basics
+
+The **query** method is used to execute arbitrary, raw SQL against your database connection.
+
+#### Selecting records from the database:
+
+ $users = DB::query('select * from users');
+
+#### Selecting records from the database using bindings:
+
+ $users = DB::query('select * from users where name = ?', array('test'));
+
+#### Inserting a record into the database
+
+ $success = DB::query('insert into users values (?, ?)', $bindings);
+
+#### Updating table records and getting the number of affected rows:
+
+ $affected = DB::query('update users set name = ?', $bindings);
+
+#### Deleting from a table and getting the number of affected rows:
+
+ $affected = DB::query('delete from users where id = ?', array(1));
+
+
+## Other Query Methods
+
+Laravel provides a few other methods to make querying your database simple. Here's an overview:
+
+#### Running a SELECT query and returning the first result:
+
+ $user = DB::first('select * from users where id = 1');
+
+#### Running a SELECT query and getting the value of a single column:
+
+ $email = DB::only('select email from users where id = 1');
+
+
+## PDO Connections
+
+Sometimes you may wish to access the raw PDO connection behind the Laravel Connection object.
+
+#### Get the raw PDO connection for a database:
+
+ $pdo = DB::connection('sqlite')->pdo;
+
+> **Note:** If no connection name is specified, the **default** connection will be returned.
\ No newline at end of file
diff --git a/laravel/documentation/database/redis.md b/laravel/documentation/database/redis.md
new file mode 100644
index 0000000..8abdd5c
--- /dev/null
+++ b/laravel/documentation/database/redis.md
@@ -0,0 +1,58 @@
+# Redis
+
+## Contents
+
+- [The Basics](#the-basics)
+- [Configuration](#config)
+- [Usage](#usage)
+
+
+## The Basics
+
+[Redis](http://redis.io) is an open source, advanced key-value store. It is often referred to as a data structure server since keys can contain [strings](http://redis.io/topics/data-types#strings), [hashes](http://redis.io/topics/data-types#hashes), [lists](http://redis.io/topics/data-types#lists), [sets](http://redis.io/topics/data-types#sets), and [sorted sets](http://redis.io/topics/data-types#sorted-sets).
+
+
+## Configuration
+
+The Redis configuration for your application lives in the **application/config/database.php** file. Within this file, you will see a **redis** array containing the Redis servers used by your application:
+
+ 'redis' => array(
+
+ 'default' => array('host' => '127.0.0.1', 'port' => 6379),
+
+ ),
+
+The default server configuration should suffice for development. However, you are free to modify this array based on your environment. Simply give each Redis server a name, and specify the host and port used by the server.
+
+
+## Usage
+
+You may get a Redis instance by calling the **db** method on the **Redis** class:
+
+ $redis = Redis::db();
+
+This will give you an instance of the **default** Redis server. You may pass the server name to the **db** method to get a specific server as defined in your Redis configuration:
+
+ $redis = Redis::db('redis_2');
+
+Great! Now that we have an instance of the Redis client, we may issue any of the [Redis commands](http://redis.io/commands) to the instance. Laravel uses magic methods to pass the commands to the Redis server:
+
+ $redis->set('name', 'Taylor');
+
+ $name = $redis->get('name');
+
+ $values = $redis->lrange('names', 5, 10);
+
+Notice the arguments to the comment are simply passed into the magic method. Of course, you are not required to use the magic methods, you may also pass commands to the server using the **run** method:
+
+ $values = $redis->run('lrange', array(5, 10));
+
+Just want to execute commands on the default Redis server? You can just use static magic methods on the Redis class:
+
+ Redis::set('name', 'Taylor');
+
+ $name = Redis::get('name');
+
+ $values = Redis::lrange('names', 5, 10);
+
+> **Note:** Redis [cache](/docs/cache/config#redis) and [session](/docs/session/config#redis) drivers are included with Laravel.
\ No newline at end of file
diff --git a/laravel/documentation/database/schema.md b/laravel/documentation/database/schema.md
new file mode 100644
index 0000000..16ed318
--- /dev/null
+++ b/laravel/documentation/database/schema.md
@@ -0,0 +1,145 @@
+# Schema Builder
+
+## Contents
+
+- [The Basics](#the-basics)
+- [Creating & Dropping Tables](#creating-dropping-tables)
+- [Adding Columns](#adding-columns)
+- [Dropping Columns](#dropping-columns)
+- [Adding Indexes](#adding-indexes)
+- [Dropping Indexes](#dropping-indexes)
+- [Foreign Keys](#foreign-keys)
+
+
+## The Basics
+
+The Schema Bulder provides methods for creating and modifying your database tables. Using a fluent syntax, you can work with your tables without using any vendor specific SQL.
+
+*Further Reading:*
+
+- [Migrations](/docs/database/migrations)
+
+
+## Creating & Dropping Tables
+
+The **Schema** class is used to create and modify tables. Let's jump right into an example:
+
+#### Creating a simple database table:
+
+ Schema::create('users', function($table)
+ {
+ $table->increments('id');
+ });
+
+Let's go over this example. The **create** method tells the Schema builder that this is a new table, so it should be created. In the second argument, we passed a Closure which receives a Table instance. Using this Table object, we can fluently add and drop columns and indexes on the table.
+
+#### Dropping a table from the database:
+
+ Schema::drop('users');
+
+#### Dropping a table from a given database connection:
+
+ Schema::drop('users', 'connection_name');
+
+Sometimes you may need to specify the database connection on which the schema operation should be performed.
+
+#### Specifying the connection to run the operation on:
+
+ Schema::create('users', function($table)
+ {
+ $table->on('connection');
+ });
+
+
+## Adding Columns
+
+The fluent table builder's methods allow you to add columns without using vendor specific SQL. Let's go over it's methods:
+
+Command | Description
+------------- | -------------
+`$table->increments('id');` | Incrementing ID to the table
+`$table->string('email');` | VARCHAR equivalent column
+`$table->string('name', 100);` | VARCHAR equivalent with a length
+`$table->integer('votes');` | INTEGER equivalent to the table
+`$table->float('amount');` | FLOAT equivalent to the table
+`$table->boolean('confirmed');` | BOOLEAN equivalent to the table
+`$table->date('created_at');` | DATE equivalent to the table
+`$table->timestamp('added_on');` | TIMESTAMP equivalent to the table
+`$table->timestamps();` | Adds **created\_at** and **updated\_at** columns
+`$table->text('description');` | TEXT equivalent to the table
+`$table->blob('data');` | BLOB equivalent to the table
+`->nullable()` | Designate that the column allows NULL values
+
+> **Note:** Laravel's "boolean" type maps to a small integer column on all database systems.
+
+#### Example of creating a table and adding columns
+
+ Schema::table('users', function($table)
+ {
+ $table->create();
+ $table->increments('id');
+ $table->string('username');
+ $table->string('email');
+ $table->string('phone')->nullable();
+ $table->text('about');
+ $table->timestamps();
+ });
+
+
+## Dropping Columns
+
+#### Dropping a column from a database table:
+
+ $table->drop_column('name');
+
+#### Dropping several columns from a database table:
+
+ $table->drop_column(array('name', 'email'));
+
+
+## Adding Indexes
+
+The Schema builder supports several types of indexes. There are two ways to add the indexes. Each type of index has its method; however, you can also fluently define an index on the same line as a column addition. Let's take a look:
+
+#### Fluently creating a string column with an index:
+
+ $table->string('email')->unique();
+
+If defining the indexes on a separate line is more your style, here are example of using each of the index methods:
+
+Command | Description
+------------- | -------------
+`$table->primary('id');` | Adding a primary key
+`$table->primary(array('fname', 'lname'));` | Adding composite keys
+`$table->unique('email');` | Adding a unique index
+`$table->fulltext('description');` | Adding a full-text index
+`$table->index('state');` | Adding a basic index
+
+
+## Dropping Indexes
+
+To drop indexes you must specify the index's name. Laravel assigns a reasonable name to all indexes. Simply concatenate the table name and the names of the columns in the index, then append the type of the index. Let's take a look at some examples:
+
+Command | Description
+------------- | -------------
+`$table->drop_primary('users_id_primary');` | Dropping a primary key from the "users" table
+`$table->drop_unique('users_email_unique');` | Dropping a unique index from the "users" table
+`$table->drop_fulltext('profile_description_fulltext');` | Dropping a full-text index from the "profile" table
+`$table->drop_index('geo_state_index');` | Dropping a basic index from the "geo" table
+
+
+## Foreign Keys
+
+You may easily add foreign key constraints to your table using Schema's fluent interface. For example, let's assume you have a **user_id** on a **posts** table, which references the **id** column of the **users** table. Here's how to add a foreign key constraint for the column:
+
+ $table->foreign('user_id')->references('id')->on('users');
+
+You may also specify options for the "on delete" and "on update" actions of the foreign key:
+
+ $table->foreign('user_id')->references('id')->on('users')->on_delete('restrict');
+
+ $table->foreign('user_id')->references('id')->on('users')->on_update('cascade');
+
+You may also easily drop a foreign key constraint. The default foreign key names follow the [same convention](#dropping-indexes) as the other indexes created by the Schema builder. Here's an example:
+
+ $table->drop_foreign('posts_user_id_foreign');
\ No newline at end of file
diff --git a/laravel/documentation/encryption.md b/laravel/documentation/encryption.md
new file mode 100644
index 0000000..9d7e6ce
--- /dev/null
+++ b/laravel/documentation/encryption.md
@@ -0,0 +1,30 @@
+# Encryption
+
+## Contents
+
+- [The Basics](#the-basics)
+- [Encrypting A String](#encrypt)
+- [Decrypting A String](#decrypt)
+
+
+## The Basics
+
+Laravel's **Crypter** class provides a simple interface for handling secure, two-way encryption. By default, the Crypter class provides strong AES-256 encryption and decryption out of the box via the Mcrypt PHP extension.
+
+> **Note:** Don't forget to install the Mcrypt PHP extension on your server.
+
+
+## Encrypting A String
+
+#### Encrypting a given string:
+
+ $encrypted = Crypter::encrypt($value);
+
+
+## Decrypting A String
+
+#### Decrypting a string:
+
+ $decrypted = Crypter::decrypt($encrypted);
+
+> **Note:** It's incredibly important to point out that the decrypt method will only decrypt strings that were encrypted using **your** application key.
\ No newline at end of file
diff --git a/laravel/documentation/events.md b/laravel/documentation/events.md
new file mode 100644
index 0000000..e678bb5
--- /dev/null
+++ b/laravel/documentation/events.md
@@ -0,0 +1,100 @@
+# Events
+
+## Contents
+
+- [The Basics](#the-basics)
+- [Firing Events](#firing-events)
+- [Listening To Events](#listening-to-events)
+- [Queued Events](#queued-events)
+- [Laravel Events](#laravel-events)
+
+
+## The Basics
+
+Events can provide a great away to build de-coupled applications, and allow plug-ins to tap into the core of your application without modifying its code.
+
+
+## Firing Events
+
+To fire an event, just tell the **Event** class the name of the event you want to fire:
+
+#### Firing an event:
+
+ $responses = Event::fire('loaded');
+
+Notice that we assigned the result of the **fire** method to a variable. This method will return an array containing the responses of all the event's listeners.
+
+Sometimes you may want to fire an event, but just get the first response. Here's how:
+
+#### Firing an event and retrieving the first response:
+
+ $response = Event::first('loaded');
+
+> **Note:** The **first** method will still fire all of the handlers listening to the event, but will only return the first response.
+
+The **Event::until** method will execute the event handlers until the first non-null response is returned.
+
+#### Firing an event until the first non-null response:
+
+ $response = Event::until('loaded');
+
+
+## Listening To Events
+
+So, what good are events if nobody is listening? Register an event handler that will be called when an event fires:
+
+#### Registering an event handler:
+
+ Event::listen('loaded', function()
+ {
+ // I'm executed on the "loaded" event!
+ });
+
+The Closure we provided to the method will be executed each time the "loaded" event is fired.
+
+
+## Queued Events
+
+Sometimes you may wish to "queue" an event for firing, but not fire it immediately. This is possible using the `queue` and `flush` methods. First, throw an event on a given queue with a unique identifier:
+
+#### Registering a queued event:
+
+ Event::queue('foo', $user->id, array($user));
+
+This method accepts three parameters. The first is the name of the queue, the second is a unique identifier for this item on the queue, and the third is an array of data to pass to the queue flusher.
+
+Next, we'll register a flusher for the `foo` queue:
+
+#### Registering an event flusher:
+
+ Event::flusher('foo', function($key, $user)
+ {
+ //
+ });
+
+Note that the event flusher receives two arguments. The first, is the unique identifier for the queued event, which in this case would be the user's ID. The second (and any remaining) parameters would be the payload items for the queued event.
+
+Finally, we can run our flusher and flush all queued events using the `flush` method:
+
+ Event::flush('foo');
+
+
+## Laravel Events
+
+There are several events that are fired by the Laravel core. Here they are:
+
+#### Event fired when a bundle is started:
+
+ Event::listen('laravel.started: bundle', function() {});
+
+#### Event fired when a database query is executed:
+
+ Event::listen('laravel.query', function($sql, $bindings, $time) {});
+
+#### Event fired right before response is sent to browser:
+
+ Event::listen('laravel.done', function($response) {});
+
+#### Event fired when a messaged is logged using the Log class:
+
+ Event::listen('laravel.log', function($type, $message) {});
\ No newline at end of file
diff --git a/laravel/documentation/files.md b/laravel/documentation/files.md
new file mode 100644
index 0000000..d0ed3f8
--- /dev/null
+++ b/laravel/documentation/files.md
@@ -0,0 +1,84 @@
+# Working With Files
+
+## Contents
+
+- [Reading Files](#get)
+- [Writing Files](#put)
+- [File Uploads](#upload)
+- [File Extensions](#ext)
+- [Checking File Types](#is)
+- [Getting MIME Types](#mime)
+- [Copying Directories](#cpdir)
+- [Removing Directories](#rmdir)
+
+
+## Reading Files
+
+#### Getting the contents of a file:
+
+ $contents = File::get('path/to/file');
+
+
+## Writing Files
+
+#### Writing to a file:
+
+ File::put('path/to/file', 'file contents');
+
+#### Appending to a file:
+
+ File::append('path/to/file', 'appended file content');
+
+
+## File Uploads
+
+#### Moving a $_FILE to a permanent location:
+
+ Input::upload('picture', 'path/to/pictures', 'filename.ext');
+
+> **Note:** You can easily validate file uploads using the [Validator class](/docs/validation).
+
+
+## File Extensions
+
+#### Getting the extension from a filename:
+
+ File::extension('picture.png');
+
+
+## Checking File Types
+
+#### Determining if a file is given type:
+
+ if (File::is('jpg', 'path/to/file.jpg'))
+ {
+ //
+ }
+
+The **is** method does not simply check the file extension. The Fileinfo PHP extension will be used to read the content of the file and determine the actual MIME type.
+
+> **Note:** You may pass any of the extensions defined in the **application/config/mimes.php** file to the **is** method.
+> **Note:** The Fileinfo PHP extension is required for this functionality. More information can be found on the [PHP Fileinfo page](http://php.net/manual/en/book.fileinfo.php).
+
+
+## Getting MIME Types
+
+#### Getting the MIME type associated with an extension:
+
+ echo File::mime('gif');
+
+> **Note:** This method simply returns the MIME type defined for the extension in the **application/config/mimes.php** file.
+
+
+## Copying Directories
+
+#### Recursively copy a directory to a given location:
+
+ File::cpdir($directory, $destination);
+
+
+## Removing Directories
+
+#### Recursively delete a directory:
+
+ File::rmdir($directory);
\ No newline at end of file
diff --git a/laravel/documentation/home.md b/laravel/documentation/home.md
new file mode 100644
index 0000000..5545a49
--- /dev/null
+++ b/laravel/documentation/home.md
@@ -0,0 +1,59 @@
+# Laravel Documentation
+
+- [The Basics](#the-basics)
+- [Who Will Enjoy Laravel?](#who-will-enjoy-laravel)
+- [What Makes Laravel Different?](#laravel-is-different)
+- [Application Structure](#application-structure)
+- [Laravel's Community](#laravel-community)
+- [License Information](#laravel-license)
+
+
+## The Basics
+
+Welcome to the Laravel documentation. These documents were designed to function both as a getting-started guide and as a feature reference. Even though you may jump into any section and start learning, we recommend reading the documentation in order as it allows us to progressively establish concepts that will be used in later documents.
+
+
+## Who Will Enjoy Laravel?
+
+Laravel is a powerful framework that emphasizes flexibility and expressiveness. Users new to Laravel will enjoy the same ease of development that is found in the most popular and lightweight PHP frameworks. More experienced users will appreciate the opportunity to modularize their code in ways that are not possible with other frameworks. Laravel's flexibility will allow your organization to update and mold the application over time as is needed and its expressiveness will allow you and your team to develop code that is both concise and easily read.
+
+
+
+## What Makes Laravel Different?
+
+There are many ways in which Laravel differentiates itself from other frameworks. Here are a few examples that we think make good bullet points:
+
+- **Bundles** are Laravel's modular packaging system. [The Laravel Bundle Repository](http://bundles.laravel.com/) is already populated with quite a few features that can be easily added to your application. You can either download a bundle repository to your bundles directory or use the "Artisan" command-line tool to automatically install them.
+- **The Eloquent ORM** is the most advanced PHP ActiveRecord implementation available. With the capacity to easily apply constraints to both relationships and nested eager-loading you'll have complete control over your data with all of the conveniences of ActiveRecord. Eloquent natively supports all of the methods from Laravel's Fluent query-builder.
+- **Application Logic** can be implemented within your application either using controllers (which many web-developers are already familiar with) or directly into route declarations using syntax similar to the Sinatra framework. Laravel is designed with the philosophy of giving a developer the flexibility that they need to create everything from very small sites to massive enterprise applications.
+- **Reverse Routing** allows you to create links to named routes. When creating links just use the route's name and Laravel will automatically insert the correct URI. This allows you to change your routes at a later time and Laravel will update all of the relevant links site-wide.
+- **Restful Controllers** are an optional way to separate your GET and POST request logic. In a login example your controller's get_login() action would serve up the form and your controller's post_login() action would accept the posted form, validate, and either redirect to the login form with an error message or redirect your user to their dashboard.
+- **Class Auto Loading** keeps you from having to maintain an autoloader configuration and from loading unnecessary components when they won't be used. Want to use a library or model? Don't bother loading it, just use it. Laravel will handle the rest.
+- **View Composers** are blocks of code that can be run when a view is loaded. A good example of this would be a blog side-navigation view that contains a list of random blog posts. Your composer would contain the logic to load the blog posts so that all you have to do i load the view and it's all ready for you. This keeps you from having to make sure that your controllers load the a bunch of data from your models for views that are unrelated to that method's page content.
+- **The IoC container** (Inversion of Control) gives you a method for generating new objects and optionally instantiating and referencing singletons. IoC means that you'll rarely ever need to bootstrap any external libraries. It also means that you can access these objects from anywhere in your code without needing to deal with an inflexible monolithic structure.
+- **Migrations** are version control for your database schemas and they are directly integrated into Laravel. You can both generate and run migrations using the "Artisan" command-line utility. Once another member makes schema changes you can update your local copy from the repository and run migrations. Now you're up to date, too!
+- **Unit-Testing** is an important part of Laravel. Laravel itself sports hundreds of tests to help ensure that new changes don't unexpectedly break anything. This is one of the reasons why Laravel is widely considered to have some of the most stable releases in the industry. Laravel also makes it easy for you to write unit-tests for your own code. You can then run tests with the "Artisan" command-line utility.
+- **Automatic Pagination** prevents your application logic from being cluttered up with a bunch of pagination configuration. Instead of pulling in the current page, getting a count of db records, and selected your data using a limit/offset just call 'paginate' and tell Laravel where to output the paging links in your view. Laravel automatically does the rest. Laravel's pagination system was designed to be easy to implement and easy to change. It's also important to note that just because Laravel can handle these things automatically doesn't mean that you can't call and configure these systems manually if you prefer.
+
+These are just a few ways in which Laravel differentiates itself from other PHP frameworks. All of these features and many more are discussed thoroughly in this documentation.
+
+
+## Application Structure
+
+Laravel's directory structure is designed to be familiar to users of other popular PHP frameworks. Web applications of any shape or size can easily be created using this structure similarly to the way that they would be created in other frameworks.
+
+However due to Laravel's unique architecture, it is possible for developers to create their own infrastructure that is specifically designed for their application. This may be most beneficial to large projects such as content-management-systems. This kind of architectural flexibility is unique to Laravel.
+
+Throughout the documentation we'll specify the default locations for declarations where appropriate.
+
+
+## Laravel's Community
+
+Laravel is lucky to be supported by rapidly growing, friendly and enthusiastic community. The [Laravel Forums](http://forums.laravel.com) are a great place to find help, make a suggestion, or just see what other people are saying.
+
+Many of us hang out every day in the #laravel IRC channel on FreeNode. [Here's a forum post explaining how you can join us.](http://forums.laravel.com/viewtopic.php?id=671) Hanging out in the IRC channel is a really great way to learn more about web-development using Laravel. You're welcome to ask questions, answer other people's questions, or just hang out and learn from other people's questions being answered. We love Laravel and would love to talk to you about it, so don't be a stranger!
+
+
+## License Information
+
+Laravel is open-sourced software licensed under the [MIT License](http://www.opensource.org/licenses/mit-license.php).
\ No newline at end of file
diff --git a/laravel/documentation/input.md b/laravel/documentation/input.md
new file mode 100644
index 0000000..14221ec
--- /dev/null
+++ b/laravel/documentation/input.md
@@ -0,0 +1,148 @@
+# Input & Cookies
+
+## Contents
+
+- [Input](#input)
+- [JSON Input](#json)
+- [Files](#files)
+- [Old Input](#old-input)
+- [Redirecting With Old Input](#redirecting-with-old-input)
+- [Cookies](#cookies)
+- [Merging & Replacing](#merge)
+
+
+## Input
+
+The **Input** class handles input that comes into your application via GET, POST, PUT, or DELETE requests. Here are some examples of how to access input data using the Input class:
+
+#### Retrieve a value from the input array:
+
+ $email = Input::get('email');
+
+> **Note:** The "get" method is used for all request types (GET, POST, PUT, and DELETE), not just GET requests.
+
+#### Retrieve all input from the input array:
+
+ $input = Input::get();
+
+#### Retrieve all input including the $_FILES array:
+
+ $input = Input::all();
+
+By default, *null* will be returned if the input item does not exist. However, you may pass a different default value as a second parameter to the method:
+
+#### Returning a default value if the requested input item doesn't exist:
+
+ $name = Input::get('name', 'Fred');
+
+#### Using a Closure to return a default value:
+
+ $name = Input::get('name', function() {return 'Fred';});
+
+#### Determining if the input contains a given item:
+
+ if (Input::has('name')) ...
+
+> **Note:** The "has" method will return *false* if the input item is an empty string.
+
+
+## JSON Input
+
+When working with JavaScript MVC frameworks like Backbone.js, you will need to get the JSON posted by the application. To make your life easier, we've included the `Input::json` method:
+
+#### Get JSON input to the application:
+
+ $data = Input::json();
+
+
+## Files
+
+#### Retrieving all items from the $_FILES array:
+
+ $files = Input::file();
+
+#### Retrieving an item from the $_FILES array:
+
+ $picture = Input::file('picture');
+
+#### Retrieving a specific item from a $_FILES array:
+
+ $size = Input::file('picture.size');
+
+
+## Old Input
+
+You'll commonly need to re-populate forms after invalid form submissions. Laravel's Input class was designed with this problem in mind. Here's an example of how you can easily retrieve the input from the previous request. First, you need to flash the input data to the session:
+
+#### Flashing input to the session:
+
+ Input::flash();
+
+#### Flashing selected input to the session:
+
+ Input::flash('only', array('username', 'email'));
+
+ Input::flash('except', array('password', 'credit_card'));
+
+#### Retrieving a flashed input item from the previous request:
+
+ $name = Input::old('name');
+
+> **Note:** You must specify a session driver before using the "old" method.
+
+*Further Reading:*
+
+- *[Sessions](/docs/session/config)*
+
+
+## Redirecting With Old Input
+
+Now that you know how to flash input to the session. Here's a shortcut that you can use when redirecting that prevents you from having to micro-manage your old input in that way:
+
+#### Flashing input from a Redirect instance:
+
+ return Redirect::to('login')->with_input();
+
+#### Flashing selected input from a Redirect instance:
+
+ return Redirect::to('login')->with_input('only', array('username'));
+
+ return Redirect::to('login')->with_input('except', array('password'));
+
+
+## Cookies
+
+Laravel provides a nice wrapper around the $_COOKIE array. However, there are a few things you should be aware of before using it. First, all Laravel cookies contain a "signature hash". This allows the framework to verify that the cookie has not been modified on the client. Secondly, when setting cookies, the cookies are not immediately sent to the browser, but are pooled until the end of the request and then sent together. This means that you will not be able to both set a cookie and retrieve the value that you set in the same request.
+
+#### Retrieving a cookie value:
+
+ $name = Cookie::get('name');
+
+#### Returning a default value if the requested cookie doesn't exist:
+
+ $name = Cookie::get('name', 'Fred');
+
+#### Setting a cookie that lasts for 60 minutes:
+
+ Cookie::put('name', 'Fred', 60);
+
+#### Creating a "permanent" cookie that lasts five years:
+
+ Cookie::forever('name', 'Fred');
+
+#### Deleting a cookie:
+
+ Cookie::forget('name');
+
+
+## Merging & Replacing
+
+Sometimes you may wish to merge or replace the current input. Here's how:
+
+#### Merging new data into the current input:
+
+ Input::merge(array('name' => 'Spock'));
+
+#### Replacing the entire input array with new data:
+
+ Input::merge(array('doctor' => 'Bones', 'captain' => 'Kirk'));
\ No newline at end of file
diff --git a/laravel/documentation/install.md b/laravel/documentation/install.md
new file mode 100644
index 0000000..1e051e0
--- /dev/null
+++ b/laravel/documentation/install.md
@@ -0,0 +1,124 @@
+# Installation & Setup
+
+## Contents
+
+- [Requirements](#requirements)
+- [Installation](#installation)
+- [Server Configuration](#server-configuration)
+- [Basic Configuration](#basic-configuration)
+- [Environments](#environments)
+- [Cleaner URLs](#cleaner-urls)
+
+
+## Requirements
+
+- Apache, nginx, or another compatible web server.
+- Laravel takes advantage of the powerful features that have become available in PHP 5.3. Consequently, PHP 5.3 is a requirement.
+- Laravel uses the [FileInfo library](http://php.net/manual/en/book.fileinfo.php) to detect files' mime-types. This is included by default with PHP 5.3. However, Windows users may need to add a line to their php.ini file before the Fileinfo module is enabled. For more information check out the [installation / configuration details on PHP.net](http://php.net/manual/en/fileinfo.installation.php).
+- Laravel uses the [Mcrypt library](http://php.net/manual/en/book.mcrypt.php) for encryption and hash generation. Mcrypt typically comes pre-installed. If you can't find Mcrypt in the output of phpinfo() then check the vendor site of your LAMP installation or check out the [installation / configuration details on PHP.net](http://php.net/manual/en/book.mcrypt.php).
+
+
+## Installation
+
+1. [Download Laravel](http://laravel.com/download)
+2. Extract the Laravel archive and upload the contents to your web server.
+3. Set the value of the **key** option in the **config/application.php** file to a random, 32 character string.
+4. Verify that the `storage/views` directory is writable.
+5. Navigate to your application in a web browser.
+
+If all is well, you should see a pretty Laravel splash page. Get ready, there is lots more to learn!
+
+### Extra Goodies
+
+Installing the following goodies will help you take full advantage of Laravel, but they are not required:
+
+- SQLite, MySQL, PostgreSQL, or SQL Server PDO drivers.
+- Memcached or APC.
+
+### Problems?
+
+If you are having problems installing, try the following:
+
+- Make sure the **public** directory is the document root of your web server. (see: Server Configuration below)
+- If you are using mod_rewrite, set the **index** option in **application/config/application.php** to an empty string.
+- Verify that your storage folder and the folders within are writable by your web server.
+
+
+## Server Configuration
+
+Like most web-development frameworks, Laravel is designed to protect your application code, bundles, and local storage by placing only files that are necessarily public in the web server's DocumentRoot. This prevents some types of server misconfiguration from making your code (including database passwords and other configuration data) accessible through the web server. It's best to be safe.
+
+In this example let's imagine that we installed Laravel to the directory **/Users/JonSnow/Sites/MySite**.
+
+A very basic example of an Apache VirtualHost configuration for MySite might look like this.
+
+
+ DocumentRoot /Users/JonSnow/Sites/MySite/public
+ ServerName mysite.dev
+
+
+Notice that while we installed to **/Users/JonSnow/Sites/MySite** our DocumentRoot points to **/Users/JonSnow/Sites/MySite/public**.
+
+While pointing the DocumentRoot to the public folder is a commonly used best-practice, it's possible that you may need to use Laravel on a host that does not allow you to update your DocumentRoot. A collection of algorithms to circumvent this need can be found [on the Laravel forums.](http://forums.laravel.com/viewtopic.php?id=1258)
+
+
+## Basic Configuration
+
+All of the configuration provided are located in your applications config/ directory. We recommend that you read through these files just to get a basic understanding of the options available to you. Pay special attention to the **application/config/application.php** file as it contains the basic configuration options for your application.
+
+It's **extremely** important that you change the **application key** option before working on your site. This key is used throughout the framework for encryption, hashing, etc. It lives in the **config/application.php** file and should be set to a random, 32 character string. A standards-compliant application key can be automatically generated using the Artisan command-line utility. More information can be found in the [Artisan command index](/docs/artisan/commands).
+
+> **Note:** If you are using mod_rewrite, you should set the index option to an empty string.
+
+
+## Environments
+
+Most likely, the configuration options you need for local development are not the same as the options you need on your production server. Laravel's default environment handling mechanism is URL based, which will make setting up environments a breeze. Pop open the `paths.php` file in the root of your Laravel installation. You should see an array like this:
+
+ $environments = array(
+
+ 'local' => array('http://localhost*', '*.dev'),
+
+ );
+
+This tells Laravel that any URLs beginning with "localhost" or ending with ".dev" should be considered part of the "local" environment.
+
+Next, create an **application/config/local** directory. Any files and options you place in this directory will override the options in the base **application/config** directory. For example, you may wish to create an **application.php** file within your new **local** configuration directory:
+
+ return array(
+
+ 'url' => 'http://localhost/laravel/public',
+
+ );
+
+In this example, the local **URL** option will override the **URL** option in **application/config/application.php**. Notice that you only need to specify the options you wish to override.
+
+Isn't it easy? Of course, you are free to create as many environments as you wish!
+
+
+## Cleaner URLs
+
+Most likely, you do not want your application URLs to contain "index.php". You can remove it using HTTP rewrite rules. If you are using Apache to serve your application, make sure to enable mod_rewrite and create a **.htaccess** file like this one in your **public** directory:
+
+
+ RewriteEngine on
+
+ RewriteCond %{REQUEST_FILENAME} !-f
+ RewriteCond %{REQUEST_FILENAME} !-d
+
+ RewriteRule ^(.*)$ index.php/$1 [L]
+
+
+Is the .htaccess file above not working for you? Try this one:
+
+ Options +FollowSymLinks
+ RewriteEngine on
+
+ RewriteCond %{REQUEST_FILENAME} !-f
+ RewriteCond %{REQUEST_FILENAME} !-d
+
+ RewriteRule . index.php [L]
+
+After setting up HTTP rewriting, you should set the **index** configuration option in **application/config/application.php** to an empty string.
+
+> **Note:** Each web server has a different method of doing HTTP rewrites, and may require a slightly different .htaccess file.
\ No newline at end of file
diff --git a/laravel/documentation/ioc.md b/laravel/documentation/ioc.md
new file mode 100644
index 0000000..bd39317
--- /dev/null
+++ b/laravel/documentation/ioc.md
@@ -0,0 +1,49 @@
+# IoC Container
+
+- [Definition](/docs/ioc#definition)
+- [Registering Objects](/docs/ioc#register)
+- [Resolving Objects](/docs/ioc#resolve)
+
+
+## Definition
+
+An IoC container is simply a way of managing the creation of objects. You can use it to define the creation of complex objects, allowing you to resolve them throughout your application using a single line of code. You may also use it to "inject" dependencies into your classes and controllers.
+
+IoC containers help make your application more flexible and testable. Since you may register alternate implementations of an interface with the container, you may isolate the code you are testing from external dependencies using [stubs and mocks](http://martinfowler.com/articles/mocksArentStubs.html).
+
+
+## Registering Objects
+
+#### Registering a resolver in the IoC container:
+
+ IoC::register('mailer', function()
+ {
+ $transport = Swift_MailTransport::newInstance();
+
+ return Swift_Mailer::newInstance($transport);
+ });
+
+
+Great! Now we have registered a resolver for SwiftMailer in our container. But, what if we don't want the container to create a new mailer instance every time we need one? Maybe we just want the container to return the same instance after the intial instance is created. Just tell the container the object should be a singleton:
+
+#### Registering a singleton in the container:
+
+ IoC::singleton('mailer', function()
+ {
+ //
+ });
+
+You may also register an existing object instance as a singleton in the container.
+
+#### Registering an existing instance in the container:
+
+ IoC::instance('mailer', $instance);
+
+
+## Resolving Objects
+
+Now that we have SwiftMailer registered in the container, we can resolve it using the **resolve** method on the **IoC** class:
+
+ $mailer = IoC::resolve('mailer');
+
+> **Note:** You may also [register controllers in the container](/docs/controllers#dependency-injection).
\ No newline at end of file
diff --git a/laravel/documentation/loading.md b/laravel/documentation/loading.md
new file mode 100644
index 0000000..72919d4
--- /dev/null
+++ b/laravel/documentation/loading.md
@@ -0,0 +1,58 @@
+# Class Auto Loading
+
+## Contents
+
+- [The Basics](#the-basics)
+- [Registering Directories](#directories)
+- [Registering Mappings](#mappings)
+- [Registering Namespaces](#namespaces)
+
+
+## The Basics
+
+Auto-loading allows you to lazily load class files when they are needed without explicitly *requiring* or *including* them. So, only the classes you actually need are loaded for any given request to your application, and you can just jump right in and start using any class without loading it's related file.
+
+By default, the **models** and **libraries** directories are registered with the auto-loader in the **application/start.php** file. The loader uses a class to file name loading convention, where all file names are lower-cased. So for instance, a "User" class within the models directory should have a file name of "user.php". You may also nest classes within sub-directories. Just namespace the classes to match the directory structure. So, a "Entities\User" class would have a file name of "entities/user.php" within the models directory.
+
+
+## Registering Directories
+
+As noted above, the models and libraries directories are registered with the auto-loader by default; however, you may register any directories you like to use the same class to file name loading conventions:
+
+#### Registering directories with the auto-loader:
+
+ Autoloader::directories(array(
+ path('app').'entities',
+ path('app').'repositories',
+ ));
+
+
+## Registering Mappings
+
+Sometimes you may wish to manually map a class to its related file. This is the most performant way of loading classes:
+
+#### Registering a class to file mapping with the auto-loader:
+
+ Autoloader::map(array(
+ 'User' => path('app').'models/user.php',
+ 'Contact' => path('app').'models/contact.php',
+ ));
+
+
+## Registering Namespaces
+
+Many third-party libraries use the PSR-0 standard for their structure. PSR-0 states that class names should match their file names, and directory structure is indicated by namespaces. If you are using a PSR-0 library, just register it's root namespace and directory with the auto-loader:
+
+#### Registering a namespace with the auto-loader:
+
+ Autoloader::namespaces(array(
+ 'Doctrine' => path('libraries').'Doctrine',
+ ));
+
+Before namespaces were available in PHP, many projects used underscores to indicate directory structure. If you are using one of these legacy libraries, you can still easily register it with the auto-loader. For example, if you are using SwiftMailer, you may have noticed all classes begin with "Swift_". So, we'll register "Swift" with the auto-loader as the root of an underscored project.
+
+#### Registering an "underscored" library with the auto-loader:
+
+ Autoloader::underscored(array(
+ 'Swift' => path('libraries').'SwiftMailer',
+ ));
\ No newline at end of file
diff --git a/laravel/documentation/localization.md b/laravel/documentation/localization.md
new file mode 100644
index 0000000..c928a49
--- /dev/null
+++ b/laravel/documentation/localization.md
@@ -0,0 +1,70 @@
+# Localization
+
+## Contents
+
+- [The Basics](#the-basics)
+- [Retrieving A Language Line](#get)
+- [Place Holders & Replacements](#replace)
+
+
+## The Basics
+
+Localization is the process of translating your application into different languages. The **Lang** class provides a simple mechanism to help you organize and retrieve the text of your multilingual application.
+
+All of the language files for your application live under the **application/language** directory. Within the **application/language** directory, you should create a directory for each language your application speaks. So, for example, if your application speaks English and Spanish, you might create **en** and **sp** directories under the **language** directory.
+
+Each language directory may contain many different language files. Each language file is simply an array of string values in that language. In fact, language files are structured identically to configuration files. For example, within the **application/language/en** directory, you could create a **marketing.php** file that looks like this:
+
+#### Creating a language file:
+
+ return array(
+
+ 'welcome' => 'Welcome to our website!',
+
+ );
+
+Next, you should create a corresponding **marketing.php** file within the **application/language/sp** directory. The file would look something like this:
+
+ return array(
+
+ 'welcome' => 'Bienvenido a nuestro sitio web!',
+
+ );
+
+Nice! Now you know how to get started setting up your language files and directories. Let's keep localizing!
+
+
+## Retrieving A Language Line
+
+#### Retrieving a language line:
+
+ echo Lang::line('marketing.welcome')->get();
+
+#### Retrieving a language line using the "__" helper:
+
+ echo __('marketing.welcome');
+
+Notice how a dot was used to separate "marketing" and "welcome"? The text before the dot corresponds to the language file, while the text after the dot corresponds to a specific string within that file.
+
+Need to retrieve the line in a language other than your default? Not a problem. Just mention the language to the **get** method:
+
+#### Getting a language line in a given language:
+
+ echo Lang::line('marketing.welcome')->get('sp');
+
+
+## Place Holders & Replacements
+
+Now, let's work on our welcome message. "Welcome to our website!" is a pretty generic message. It would be helpful to be able to specify the name of the person we are welcoming. But, creating a language line for each user of our application would be time-consuming and ridiculous. Thankfully, you don't have to. You can specify "place-holders" within your language lines. Place-holders are preceeded by a colon:
+
+#### Creating a language line with place-holders:
+
+ 'welcome' => 'Welcome to our website, :name!'
+
+#### Retrieving a language line with replacements:
+
+ echo Lang::line('marketing.welcome', array('name' => 'Taylor'))->get();
+
+#### Retrieving a language line with replacements using "__":
+
+ echo __('marketing.welcome', array('name' => 'Taylor'));
\ No newline at end of file
diff --git a/laravel/documentation/logging.md b/laravel/documentation/logging.md
new file mode 100644
index 0000000..c153338
--- /dev/null
+++ b/laravel/documentation/logging.md
@@ -0,0 +1,40 @@
+# Errors & Logging
+
+## Contents
+
+- [Basic Configuration](#basic-configuration)
+- [Logging](#logging)
+- [The Logger Class](#the-logger-class)
+
+
+## Basic Configuration
+
+All of the configuration options regarding errors and logging live in the **application/config/errors.php** file. Let's jump right in.
+
+### Ignored Errors
+
+The **ignore** option contains an array of error levels that should be ignored by Laravel. By "ignored", we mean that we won't stop execution of the script on these errors. However, they will be logged when logging is enabled.
+
+### Error Detail
+
+The **detail** option indicates if the framework should display the error message and stack trace when an error occurs. For development, you will want this to be **true**. However, in a production environment, set this to **false**. When disabled, the view located in **application/views/error/500.php** will be displayed, which contains a generic error message.
+
+
+## Logging
+
+To enable logging, set the **log** option in the error configuration to "true". When enabled, the Closure defined by the **logger** configuration item will be executed when an error occurs. This gives you total flexibility in how the error should be logged. You can even e-mail the errors to your development team!
+
+By default, logs are stored in the **storage/logs** direcetory, and a new log file is created for each day. This keeps your log files from getting crowded with too many messages.
+
+
+## The Logger Class
+
+Sometimes you may wish to use Laravel's **Log** class for debugging, or just to log informational messages. Here's how to use it:
+
+#### Writing a message to the logs:
+
+ Log::write('info', 'This is just an informational message!');
+
+#### Using magic methods to specify the log message type:
+
+ Log::info('This is just an informational message!');
\ No newline at end of file
diff --git a/laravel/documentation/models.md b/laravel/documentation/models.md
new file mode 100644
index 0000000..a1f4620
--- /dev/null
+++ b/laravel/documentation/models.md
@@ -0,0 +1,116 @@
+# Models & Libraries
+
+## Contents
+
+- [Models](#models)
+- [Libraries](#libraries)
+- [Auto-Loading](#auto-loading)
+- [Best Practices](#best-practices)
+
+
+## Models
+
+Models are the heart of your application. Your application logic (controllers / routes) and views (html) are just the mediums with which users interact with your models. The most typical type of logic contained within a model is [Business Logic](http://en.wikipedia.org/wiki/Business_logic).
+
+*Some examples of functionality that would exist within a model are:*
+
+- Database Interactions
+- File I/O
+- Interactions with Web Services
+
+For instance, perhaps you are writing a blog. You will likely want to have a "Post" model. Users may want to comment on posts so you'd also have a "Comment" model. If users are going to be commenting then we'll also need a "User" model. Get the idea?
+
+
+## Libraries
+
+Libraries are classes that perform tasks that aren't specific to your application. For instance, consider a PDF generation library that converts HTML. That task, although complicated, is not specific to your application, so it is considered a "library".
+
+Creating a library is as easy as creating a class and storing it in the libraries folder. In the following example, we will create a simple library with a method that echos the text that is passed to it. We create the **printer.php** file in the libraries folder with the following code.
+
+
+## Auto Loading
+
+Libraries and Models are very easy to use thanks to the Laravel auto-loader. To learn more about the auto-loader check out the documentation on [Auto-Loading](/docs/loading).
+
+
+## Best Practices
+
+We've all head the mantra: "controllers should be thin!" But, how do we apply that in real life? It's possible that part of the problem is the word "model". What does it even mean? Is it even a useful term? Many associate "model" with "database", which leads to having very bloated controllers, with light models that access the database. Let's explore some alternatives.
+
+What if we just totally scrapped the "models" directory? Let's name it something more useful. In fact, let's just give it the same as our application. Perhaps are our satellite tracking site is named "Trackler", so let's create a "trackler" directory within the application folder.
+
+Great! Next, let's break our classes into "entities", "services", and "repositories". So, we'll create each of those three directories within our "trackler" folder. Let's explore each one:
+
+### Entities
+
+Think of entities as the data containers of your application. They primarily just contain properties. So, in our application, we may have a "Location" entity which has "latitude" and "longitude" properties. It could look something like this:
+
+ latitude = $latitude;
+ $this->longitude = $longitude;
+ }
+
+ }
+
+Looking good. Now that we have an entity, let's explore our other two folders.
+
+### Services
+
+Services contain the *processes* of your application. So, let's keep using our Trackler example. Our application might have a form on which a user may enter their GPS location. However, we need to validate that the coordinates are correctly formatted. We need to *validate* the *location entity*. So, within our "services" directory, we could create a "validators" folder with the following class:
+
+
+## Working With The URI
+
+#### Getting the current URI for the request:
+
+ echo URI::current();
+
+#### Getting a specific segment from the URI:
+
+ echo URI::segment(1);
+
+#### Returning a default value if the segment doesn't exist:
+
+ echo URI::segment(10, 'Foo');
+
+#### Getting the full request URI, including query string:
+
+ echo URI::full();
+
+Sometimes you may need to determine if the current URI is a given string, or begins with a given string. Here's an example of how you can use the is() method to accomplish this:
+
+#### Determine if the URI is "home":
+
+ if (URI::is('home'))
+ {
+ // The current URI is "home"!
+ }
+
+#### Determine if the current URI begins with "docs/":
+
+ if URI::is('docs/*'))
+ {
+ // The current URI begins with "docs/"!
+ }
+
+
+## Other Request Helpers
+
+#### Getting the current request method:
+
+ echo Request::method();
+
+#### Accessing the $_SERVER global array:
+
+ echo Request::server('http_referer');
+
+#### Retrieving the requester's IP address:
+
+ echo Request::ip();
+
+#### Determining if the current request is using HTTPS:
+
+ if (Request::secure())
+ {
+ // This request is over HTTPS!
+ }
+
+#### Determing if the current request is an AJAX request:
+
+ if (Request::ajax())
+ {
+ // This request is using AJAX!
+ }
+
+#### Determining if the current requst is via the Artisan CLI:
+
+ if (Request::cli())
+ {
+ // This request came from the CLI!
+ }
\ No newline at end of file
diff --git a/laravel/documentation/routing.md b/laravel/documentation/routing.md
new file mode 100644
index 0000000..18c9067
--- /dev/null
+++ b/laravel/documentation/routing.md
@@ -0,0 +1,321 @@
+# Routing
+
+## Contents
+
+- [The Basics](#the-basics)
+- [Wildcards](#wildcards)
+- [The 404 Events](#the-404-event)
+- [Filters](#filters)
+- [Pattern Filters](#pattern-filters)
+- [Global Filters](#global-filters)
+- [Route Groups](#route-groups)
+- [Named Routes](#named-routes)
+- [HTTPS Routes](#https-routes)
+- [Bundle Routes](#bundle-routes)
+- [Controller Routing](#controller-routing)
+- [CLI Route Testing](#cli-route-testing)
+
+
+## The Basics
+
+Laravel uses the latest features of PHP 5.3 to make routing simple and expressive. It's important that building everything from APIs to complex web applications is as easy as possible. Routes are typically defined in **application/routes.php**.
+
+Unlike many other frameworks with Laravel it's possible to embed application logic in two ways. While controllers are the most common way to implement application logic it's also possible to embed your logic directly into routes. This is **especially** nice for small sites that contain only a few pages as you don't have to create a bunch of controllers just to expose half a dozen methods or put a handful of unrelated methods into the same controller and then have to manually designate routes that point to them.
+
+In the following example the first parameter is the route that you're "registering" with the router. The second parameter is the function containing the logic for that route. Routes are defined without a front-slash. The only exception to this is the default route which is represented with **only** a front-slash.
+
+> **Note:** Routes are evaluated in the order that they are registered, so register any "catch-all" routes at the bottom of your **routes.php** file.
+
+#### Registering a route that responds to "GET /":
+
+ Route::get('/', function()
+ {
+ return "Hello World!";
+ });
+
+#### Registering a route that is valid for any HTTP verb (GET, POST, PUT, and DELETE):
+
+ Route::any('/', function()
+ {
+ return "Hello World!";
+ });
+
+#### Registering routes for other request methods:
+
+ Route::post('user', function()
+ {
+ //
+ });
+
+ Route::put('user/(:num)', function($id)
+ {
+ //
+ });
+
+ Route::delete('user/(:num)', function($id)
+ {
+ //
+ });
+
+**Registering a single URI for multiple HTTP verbs:**
+
+ Router::register(array('GET', 'POST'), $uri, $callback);
+
+
+## Wildcards
+
+#### Forcing a URI segment to be any digit:
+
+ Route::get('user/(:num)', function($id)
+ {
+ //
+ });
+
+#### Allowing a URI segment to be any alpha-numeric string:
+
+ Route::get('post/(:any)', function($title)
+ {
+ //
+ });
+
+#### Allowing a URI segment to be optional:
+
+ Route::get('page/(:any?)', function($page = 'index')
+ {
+ //
+ });
+
+
+## The 404 Event
+
+If a request enters your application but does not match any existing route, the 404 event will be raised. You can find the default event handler in your **application/routes.php** file.
+
+#### The default 404 event handler:
+
+ Event::listen('404', function()
+ {
+ return Response::error('404');
+ });
+
+You are free to change this to fit the needs of your application!
+
+*Futher Reading:*
+
+- *[Events](/docs/events)*
+
+
+## Filters
+
+Route filters may be run before or after a route is executed. If a "before" filter returns a value, that value is considered the response to the request and the route is not executed, which is conveniont when implementing authentication filters, etc. Filters are typically defined in **application/routes.php**.
+
+#### Registering a filter:
+
+ Route::filter('filter', function()
+ {
+ return Redirect::to('home');
+ });
+
+#### Attaching a filter to a route:
+
+ Route::get('blocked', array('before' => 'filter', function()
+ {
+ return View::make('blocked');
+ }));
+
+#### Attaching an "after" filter to a route:
+
+ Route::get('download', array('after' => 'log', function()
+ {
+ //
+ }));
+
+#### Attaching multiple filters to a route:
+
+ Route::get('create', array('before' => 'auth|csrf', function()
+ {
+ //
+ }));
+
+#### Passing parameters to filters:
+
+ Route::get('panel', array('before' => 'role:admin', function()
+ {
+ //
+ }));
+
+
+## Pattern Filters
+
+Sometimes you may want to attach a filter to all requests that begin with a given URI. For example, you may want to attach the "auth" filter to all requests with URIs that begin with "admin". Here's how to do it:
+
+#### Defining a URI pattern based filter:
+
+ Route::filter('pattern: admin/*', 'auth');
+
+
+## Global Filters
+
+Laravel has two "global" filters that run **before** and **after** every request to your application. You can find them both in the **application/routes.php** file. These filters make great places to start common bundles or add global assets.
+
+> **Note:** The **after** filter receives the **Response** object for the current request.
+
+
+## Route Groups
+
+Route groups allow you to attach a set of attributes to a group of routes, allowing you to keep your code neat and tidy.
+
+ Route::group(array('before' => 'auth'), function()
+ {
+ Route::get('panel', function()
+ {
+ //
+ });
+
+ Route::get('dashboard', function()
+ {
+ //
+ });
+ });
+
+
+## Named Routes
+
+Constantly generating URLs or redirects using a route's URI can cause problems when routes are later changed. Assigning the route a name gives you a convenient way to refer to the route throughout your application. When a route change occurs the generated links will point to the new route with no further configuration needed.
+
+#### Registering a named route:
+
+ Route::get('/', array('as' => 'home', function()
+ {
+ return "Hello World";
+ }));
+
+#### Generating a URL to a named route:
+
+ $url = URL::to_route('home');
+
+#### Redirecting to the named route:
+
+ return Redirect::to_route('home');
+
+Once you have named a route, you may easily check if the route handling the current request has a given name.
+
+#### Determine if the route handling the request has a given name:
+
+ if (Request::route()->is('home'))
+ {
+ // The "home" route is handling the request!
+ }
+
+
+## HTTPS Routes
+
+When defining routes, you may use the "https" attribute to indicate that the HTTPS protocol should be used when generating a URL or Redirect to that route.
+
+#### Defining an HTTPS route:
+
+ Route::get('login', array('https' => true, function()
+ {
+ return View::make('login');
+ }));
+
+#### Using the "secure" short-cut method:
+
+ Route::secure('GET', 'login', function()
+ {
+ return View::make('login');
+ });
+
+
+## Bundle Routes
+
+Bundles are Laravel's modular package system. Bundles can easily be configured to handle requests to your application. We'll be going over [bundles in more detail](/docs/bundles) in another document. For now, read through this section and just be aware that not only can routes be used to expose functionality in bundles, but they can also be registered from within bundles.
+
+Let's open the **application/bundles.php** file and add something:
+
+#### Registering a bundle to handle routes:
+
+ return array(
+
+ 'admin' => array('handles' => 'admin'),
+
+ );
+
+Notice the new **handles** option in our bundle configuration array? This tells Laravel to load the Admin bundle on any requests where the URI begins with "admin".
+
+Now you're ready to register some routes for your bundle, so create a **routes.php** file within the root directory of your bundle and add the following:
+
+#### Registering a root route for a bundle:
+
+ Route::get('(:bundle)', function()
+ {
+ return 'Welcome to the Admin bundle!';
+ });
+
+Let's explore this example. Notice the **(:bundle)** place-holder? That will be replaced with the value of the **handles** clause that you used to register your bundle. This keeps your code [D.R.Y.](http://en.wikipedia.org/wiki/Don't_repeat_yourself) and allows those who use your bundle to change it's root URI without breaking your routes! Nice, right?
+
+Of course, you can use the **(:bundle)** place-holder for all of your routes, not just your root route.
+
+#### Registering bundle routes:
+
+ Route::get('(:bundle)/panel', function()
+ {
+ return "I handle requests to admin/panel!";
+ });
+
+
+## Controller Routing
+
+Controllers provide another way to manage your application logic. If you're unfamiliar with controllers you may want to [read about controllers](/docs/controllers) and return to this section.
+
+It is important to be aware that all routes in Laravel must be explicitly defined, including routes to controllers. This means that controller methods that have not been exposed through route registration **cannot** be accessed. It's possible to automatically expose all methods within a controller using controller route registration. Controller route registrations are typically defined in **application/routes.php**.
+
+Most likely, you just want to register all of the controllers in your application's "controllers" directory. You can do it in one simple statement. Here's how:
+
+#### Register all controllers for the application:
+
+ Route::controller(Controller::detect());
+
+The **Controller::detect** method simply returns an array of all of the controllers defined for the application.
+
+If you wish to automatically detect the controllers in a bundle, just pass the bundle name to the method. If no bundle is specified, the application folder's controller directory will be searched.
+
+#### Register all controllers for the "admin" bundle:
+
+ Route::controller(Controller::detect('admin'));
+
+#### Registering the "home" controller with the Router:
+
+ Route::controller('home');
+
+#### Registering several controllers with the router:
+
+ Route::controller(array('dashboard.panel', 'admin'));
+
+Once a controller is registered, you may access its methods using a simple URI convention:
+
+ http://localhost/controller/method/arguments
+
+This convention is similar to that employed by CodeIgniter and other popular frameworks, where the first segment is the controller name, the second is the method, and the remaining segments are passed to the method as arguments. If no method segment is present, the "index" method will be used.
+
+This routing convention may not be desirable for every situation, so you may also explicitly route URIs to controller actions using a simple, intuitive syntax.
+
+#### Registering a route that points to a controller action:
+
+ Route::get('welcome', 'home@index');
+
+#### Registering a filtered route that points to a controller action:
+
+ Route::get('welcome', array('after' => 'log', 'uses' => 'home@index'));
+
+#### Registering a named route that points to a controller action:
+
+ Route::get('welcome', array('as' => 'home.welcome', 'uses' => 'home@index'));
+
+
+## CLI Route Testing
+
+You may test your routes using Laravel's "Artisan" CLI. Simple specify the request method and URI you want to use. The route response will be var_dump'd back to the CLI.
+
+#### Calling a route via the Artisan CLI:
+
+ php artisan route:call get api/user/1
\ No newline at end of file
diff --git a/laravel/documentation/session/config.md b/laravel/documentation/session/config.md
new file mode 100644
index 0000000..094148c
--- /dev/null
+++ b/laravel/documentation/session/config.md
@@ -0,0 +1,109 @@
+
+# Session Configuration
+
+## Contents
+
+- [The Basics](#the-basics)
+- [Cookie Sessions](#cookie)
+- [File System Sessions](#file)
+- [Database Sessions](#database)
+- [Memcached Sessions](#memcached)
+- [Redis Sessions](#redis)
+- [In-Memory Sessions](#memory)
+
+
+## The Basics
+
+The web is a stateless environment. This means that each request to your application is considered unrelated to any previous request. However, **sessions** allow you to store arbitrary data for each visitor to your application. The session data for each visitor is stored on your web server, while a cookie containing a **session ID** is stored on the visitor's machine. This cookie allows your application to "remember" the session for that user and retrieve their session data on subsequent requests to your application.
+
+> **Note:** Before using sessions, make sure an application key has been specified in the **application/config/application.php** file.
+
+Six session drivers are available out of the box:
+
+- Cookie
+- File System
+- Database
+- Memcached
+- Redis
+- Memory (Arrays)
+
+
+## Cookie Sessions
+
+Cookie based sessions provide a light-weight and fast mechanism for storing session information. They are also secure. Each cookie is encrypted using strong AES-256 encryption. However, cookies have a four kilobyte storage limit, so you may wish to use another driver if you are storing a lot of data in the session.
+
+To get started using cookie sessions, just set the driver option in the **application/config/session.php** file:
+
+ 'driver' => 'cookie'
+
+
+## File System Sessions
+
+Most likely, your application will work great using file system sessions. However, if your application receives heavy traffic or runs on a server farm, use database or Memcached sessions.
+
+To get started using file system sessions, just set the driver option in the **application/config/session.php** file:
+
+ 'driver' => 'file'
+
+That's it. You're ready to go!
+
+> **Note:** File system sessions are stored in the **storage/sessions** directory, so make sure it's writeable.
+
+
+## Database Sessions
+
+To start using database sessions, you will first need to [configure your database connection](/docs/database/config).
+
+Next, you will need to create a session table. Below are some SQL statements to help you get started. However, you may also use Laravel's "Artisan" command-line to generate the table for you!
+
+### Artisan
+
+ php artisan session:table
+
+### SQLite
+
+ CREATE TABLE "sessions" (
+ "id" VARCHAR PRIMARY KEY NOT NULL UNIQUE,
+ "last_activity" INTEGER NOT NULL,
+ "data" TEXT NOT NULL
+ );
+
+### MySQL
+
+ CREATE TABLE `sessions` (
+ `id` VARCHAR(40) NOT NULL,
+ `last_activity` INT(10) NOT NULL,
+ `data` TEXT NOT NULL,
+ PRIMARY KEY (`id`)
+ );
+
+If you would like to use a different table name, simply change the **table** option in the **application/config/session.php** file:
+
+ 'table' => 'sessions'
+
+All you need to do now is set the driver in the **application/config/session.php** file:
+
+ 'driver' => 'database'
+
+
+## Memcached Sessions
+
+Before using Memcached sessions, you must [configure your Memcached servers](/docs/database/config#memcached).
+
+Just set the driver in the **application/config/session.php** file:
+
+ 'driver' => 'memcached'
+
+
+## Redis Sessions
+
+Before using Redis sessions, you must [configure your Redis servers](/docs/database/redis#config).
+
+Just set the driver in the **application/config/session.php** file:
+
+ 'driver' => 'redis'
+
+
+## In-Memory Sessions
+
+The "memory" session driver just uses a simple array to store your session data for the current request. This driver is perfect for unit testing your application since nothing is written to disk. It shouldn't ever be used as a "real" session driver.
\ No newline at end of file
diff --git a/laravel/documentation/session/usage.md b/laravel/documentation/session/usage.md
new file mode 100644
index 0000000..5f9aad5
--- /dev/null
+++ b/laravel/documentation/session/usage.md
@@ -0,0 +1,61 @@
+# Session Usage
+
+## Contents
+
+- [Storing Items](#put)
+- [Retrieving Items](#get)
+- [Removing Items](#forget)
+- [Regeneration](#regeneration)
+
+
+## Storing Items
+
+To store items in the session call the put method on the Session class:
+
+ Session::put('name', 'Taylor');
+
+The first parameter is the **key** to the session item. You will use this key to retrieve the item from the session. The second parameter is the **value** of the item.
+
+The **flash** method stores an item in the session that will expire after the next request. It's useful for storing temporary data like status or error messages:
+
+ Session::flash('status', 'Welcome Back!');
+
+
+## Retrieving Items
+
+You can use the **get** method on the Session class to retrieve any item in the session, including flash data. Just pass the key of the item you wish to retrieve:
+
+ $name = Session::get('name');
+
+By default, NULL will be returned if the session item does not exist. However, you may pass a default value as a second parameter to the get method:
+
+ $name = Session::get('name', 'Fred');
+
+ $name = Session::get('name', function() {return 'Fred';});
+
+Now, "Fred" will be returned if the "name" item does not exist in the session.
+
+Laravel even provides a simple way to determine if a session item exists using the **has** method:
+
+ if (Session::has('name'))
+ {
+ $name = Session::get('name');
+ }
+
+
+## Removing Items
+
+To remove an item from the session use the **forget** method on the Session class:
+
+ Session::forget('name');
+
+You can even remove all of the items from the session using the **flush** method:
+
+ Session::flush();
+
+
+## Regeneration
+
+Sometimes you may want to "regenerate" the session ID. This simply means that a new, random session ID will be assigned to the session. Here's how to do it:
+
+ Session::regenerate();
\ No newline at end of file
diff --git a/laravel/documentation/strings.md b/laravel/documentation/strings.md
new file mode 100644
index 0000000..002d914
--- /dev/null
+++ b/laravel/documentation/strings.md
@@ -0,0 +1,71 @@
+# Working With Strings
+
+## Contents
+
+- [Capitalization, Etc.](#capitalization)
+- [Word & Character Limiting](#limits)
+- [Generating Random Strings](#random)
+- [Singular & Plural](#singular-and-plural)
+- [Slugs](#slugs)
+
+
+## Capitalization, Etc.
+
+The **Str** class also provides three convenient methods for manipulating string capitalization: **upper**, **lower**, and **title**. These are more intelligent versions of the PHP [strtoupper](http://php.net/manual/en/function.strtoupper.php), [strtolower](http://php.net/manual/en/function.strtolower.php), and [ucwords](http://php.net/manual/en/function.ucwords.php) methods. More intelligent because they can handle UTF-8 input if the [multi-byte string](http://php.net/manual/en/book.mbstring.php) PHP extension is installed on your web server. To use them, just pass a string to the method:
+
+ echo Str::lower('I am a string.');
+
+ echo Str::upper('I am a string.');
+
+ echo Str::title('I am a string.');
+
+
+## Word & Character Limiting
+
+#### Limiting the number of characters in a string:
+
+ echo Str::limit($string, 10);
+
+#### Limiting the number of words in a string:
+
+ echo Str::words($string, 10);
+
+
+## Generating Random Strings
+
+#### Generating a random string of alpha-numeric characters:
+
+ echo Str::random(32);
+
+#### Generating a random string of alphabetic characters:
+
+ echo Str::random(32, 'alpha');
+
+
+## Singular & Plural
+
+The String class is capable of transforming your strings from singular to plural, and vice versa.
+
+#### Getting the plural form of a word:
+
+ echo Str::plural('user');
+
+#### Getting the singular form of a word:
+
+ echo Str::singular('users');
+
+#### Getting the plural form if given value is greater than one:
+
+ echo Str::plural('comment', count($comments));
+
+
+## Slugs
+
+#### Generating a URL friendly slug:
+
+ return Str::slug('My First Blog Post!');
+
+#### Generating a URL friendly slug using a given separator:
+
+ return Str::slug('My First Blog Post!', '_');
+
diff --git a/laravel/documentation/testing.md b/laravel/documentation/testing.md
new file mode 100644
index 0000000..a7d958c
--- /dev/null
+++ b/laravel/documentation/testing.md
@@ -0,0 +1,68 @@
+# Unit Testing
+
+## Contents
+
+- [The Basics](#the-basics)
+- [Creating Test Classes](#creating-test-classes)
+- [Running Tests](#running-tests)
+- [Calling Controllers From Tests](#calling-controllers-from-tests)
+
+
+## The Basics
+
+Unit Testing allows you to test your code and verify that it is working correctly. In fact, many advocate that you should even write your tests before you write your code! Laravel provides beautiful integration with the popular [PHPUnit](http://www.phpunit.de/manual/current/en/) testing library, making it easy to get started writing your tests. In fact, the Laravel framework itself has hundreds of unit tests!
+
+
+## Creating Test Classes
+
+All of your application's tests live in the **application/tests** directory. In this directory, you will find a basic **example.test.php** file. Pop it open and look at the class it contains:
+
+ assertTrue(true);
+ }
+
+ }
+
+Take special note of the **.test.php** file suffix. This tells Laravel that it should include this class as a test case when running your test. Any files in the test directory that are not named with this suffix will not be considered a test case.
+
+If you are writing tests for a bundle, just place them in a **tests** directory within the bundle. Laravel will take care of the rest!
+
+For more information regarding creating test cases, check out the [PHPUnit documentation](http://www.phpunit.de/manual/current/en/).
+
+
+## Running Tests
+
+To run your tests, you can use Laravel's Artisan command-line utility:
+
+#### Running the application's tests via the Artisan CLI:
+
+ php artisan test
+
+#### Running the unit tests for a bundle:
+
+ php artisan test bundle-name
+
+
+## Calling Controllers From Tests
+
+Here's an example of how you can call your controllers from your tests:
+
+#### Calling a controller from a test:
+
+ $response = Controller::call('home@index', $parameters);
+
+#### Resolving an instance of a controller from a test:
+
+ $controller = Controller::resolve('application', 'home@index');
+
+> **Note:** The controller's action filters will still run when using Controller::call to execute controller actions.
\ No newline at end of file
diff --git a/laravel/documentation/urls.md b/laravel/documentation/urls.md
new file mode 100644
index 0000000..4263712
--- /dev/null
+++ b/laravel/documentation/urls.md
@@ -0,0 +1,98 @@
+# Generating URLs
+
+## Contents
+
+- [The Basics](#the-basics)
+- [URLs To Routes](#urls-to-routes)
+- [URLs To Controller Actions](#urls-to-controller-actions)
+- [URLs To Assets](#urls-to-assets)
+- [URL Helpers](#url-helpers)
+
+
+## The Basics
+
+#### Retrieving the application's base URL:
+
+ $url = URL::base();
+
+#### Generating a URL relative to the base URL:
+
+ $url = URL::to('user/profile');
+
+#### Generating a HTTPS URL:
+
+ $url = URL::to_secure('user/login');
+
+#### Retrieving the current URL:
+
+ $url = URL::current();
+
+#### Retrieving the current URL including query string:
+
+ $url = URL::full();
+
+
+## URLs To Routes
+
+#### Generating a URL to a named route:
+
+ $url = URL::to_route('profile');
+
+Sometimes you may need to generate a URL to a named route, but also need to specify the values that should be used instead of the route's URI wildcards. It's easy to replace the wildcards with proper values:
+
+#### Generating a URL to a named route with wildcard values:
+
+ $url = URL::to_route('profile', array($username));
+
+*Further Reading:*
+
+- [Named Routes](/docs/routing#named-routes)
+
+
+## URLs To Controller Actions
+
+#### Generating a URL to a controller action:
+
+ $url = URL::to_action('user@profile');
+
+#### Generating a URL to an action with wildcard values:
+
+ $url = URL::to_action('user@profile', array($username));
+
+
+## URLs To Assets
+
+URLs generated for assets will not contain the "application.index" configuration option.
+
+#### Generating a URL to an asset:
+
+ $url = URL::to_asset('js/jquery.js');
+
+
+## URL Helpers
+
+There are several global functions for generating URLs designed to make your life easier and your code cleaner:
+
+#### Generating a URL relative to the base URL:
+
+ $url = url('user/profile');
+
+#### Generating a URL to an asset:
+
+ $url = asset('js/jquery.js');
+
+#### Generating a URL to a named route:
+
+ $url = route('profile');
+
+#### Generating a URL to a named route with wildcard values:
+
+ $url = route('profile', array($username));
+
+#### Generating a URL to a controller action:
+
+ $url = action('user@profile');
+
+#### Generating a URL to an action with wildcard values:
+
+ $url = action('user@profile', array($username));
\ No newline at end of file
diff --git a/laravel/documentation/validation.md b/laravel/documentation/validation.md
new file mode 100644
index 0000000..4da4683
--- /dev/null
+++ b/laravel/documentation/validation.md
@@ -0,0 +1,431 @@
+# Validation
+
+## Contents
+
+- [The Basics](#the-basics)
+- [Validation Rules](#validation-rules)
+- [Retrieving Error Message](#retrieving-error-messages)
+- [Validation Walkthrough](#validation-walkthrough)
+- [Custom Error Messages](#custom-error-messages)
+- [Custom Validation Rules](#custom-validation-rules)
+
+
+## The Basics
+
+Almost every interactive web application needs to validate data. For instance, a registration form probably requires the password to be confirmed. Maybe the e-mail address must be unique. Validating data can be a cumbersome process. Thankfully, it isn't in Laravel. The Validator class provides an awesome array of validation helpers to make validating your data a breeze. Let's walk through an example:
+
+#### Get an array of data you want to validate:
+
+ $input = Input::all();
+
+#### Define the validation rules for your data:
+
+ $rules = array(
+ 'name' => 'required|max:50',
+ 'email' => 'required|email|unique:users',
+ );
+
+#### Create a Validator instance and validate the data:
+
+ $validation = Validator::make($input, $rules);
+
+ if ($validation->fails())
+ {
+ return $validation->errors;
+ }
+
+With the *errors* property, you can access a simple message collector class that makes working with your error messages a piece of cake. Of course, default error messages have been setup for all validation rules. The default messages live at **language/en/validation.php**.
+
+Now you are familiar with the basic usage of the Validator class. You're ready to dig in and learn about the rules you can use to validate your data!
+
+
+## Validation Rules
+
+- [Required](#rule-required)
+- [Alpha, Alpha Numeric, & Alpha Dash](#rule-alpha)
+- [Size](#rule-size)
+- [Numeric](#rule-numeric)
+- [Inclusion & Exclusion](#rule-in)
+- [Confirmation](#rule-confirmation)
+- [Acceptance](#rule-acceptance)
+- [Same & Different](#same-and-different)
+- [Regular Expression Match](#regex-match)
+- [Uniqueness & Existence](#rule-unique)
+- [Dates](#dates)
+- [E-Mail Addresses](#rule-email)
+- [URLs](#rule-url)
+- [Uploads](#rule-uploads)
+
+
+### Required
+
+#### Validate that an attribute is present and is not an empty string:
+
+ 'name' => 'required'
+
+
+### Alpha, Alpha Numeric, & Alpha Dash
+
+#### Validate that an attribute consists solely of letters:
+
+ 'name' => 'alpha'
+
+#### Validate that an attribute consists of letters and numbers:
+
+ 'username' => 'alpha_num'
+
+#### Validate that an attribute only contains letters, numbers, dashes, or underscores:
+
+ 'username' => 'alpha_dash'
+
+
+### Size
+
+#### Validate that an attribute is a given length, or, if an attribute is numeric, is a given value:
+
+ 'name' => 'size:10'
+
+#### Validate that an attribute size is within a given range:
+
+ 'payment' => 'between:10,50'
+
+> **Note:** All minimum and maximum checks are inclusive.
+
+#### Validate that an attribute is at least a given size:
+
+ 'payment' => 'min:10'
+
+#### Validate that an attribute is no greater than a given size:
+
+ 'payment' => 'max:50'
+
+
+### Numeric
+
+#### Validate that an attribute is numeric:
+
+ 'payment' => 'numeric'
+
+#### Validate that an attribute is an integer:
+
+ 'payment' => 'integer'
+
+
+### Inclusion & Exclusion
+
+#### Validate that an attribute is contained in a list of values:
+
+ 'size' => 'in:small,medium,large'
+
+#### Validate that an attribute is not contained in a list of values:
+
+ 'language' => 'not_in:cobol,assembler'
+
+
+### Confirmation
+
+The *confirmed* rule validates that, for a given attribute, a matching *attribute_confirmation* attribute exists.
+
+#### Validate that an attribute is confirmed:
+
+ 'password' => 'confirmed'
+
+Given this example, the Validator will make sure that the *password* attribute matches the *password_confirmation* attribute in the array being validated.
+
+
+### Acceptance
+
+The *accepted* rule validates that an attribute is equal to *yes* or *1*. This rule is helpful for validating checkbox form fields such as "terms of service".
+
+#### Validate that an attribute is accepted:
+
+ 'terms' => 'accepted'
+
+
+## Same & Different
+
+#### Validate that an attribute matches another attribute:
+
+ 'token1' => 'same:token2'
+
+#### Validate that two attributes have different values:
+
+ 'password' => 'different:old_password',
+
+
+### Regular Expression Match
+
+The *match* rule validates that an attribute matches a given regular expression.
+
+#### Validate that an attribute matches a regular expression:
+
+ 'username' => 'match:/[a-z]+/';
+
+
+### Uniqueness & Existence
+
+#### Validate that an attribute is unique on a given database table:
+
+ 'email' => 'unique:users'
+
+In the example above, the *email* attribute will be checked for uniqueness on the *users* table. Need to verify uniqueness on a column name other than the attribute name? No problem:
+
+#### Specify a custom column name for the unique rule:
+
+ 'email' => 'unique:users,email_address'
+
+Many times, when updating a record, you want to use the unique rule, but exclude the row being updated. For example, when updating a user's profile, you may allow them to change their e-mail address. But, when the *unique* rule runs, you want it to skip the given user since they may not have changed their address, thus causing the *unique* rule to fail. It's easy:
+
+#### Forcing the unique rule to ignore a given ID:
+
+ 'email' => 'unique:users,email_address,10'
+
+#### Validate that an attribute exists on a given database table:
+
+ 'state' => 'exists:states'
+
+#### Specify a custom column name for the exists rule:
+
+ 'state' => 'exists:states,abbreviation'
+
+
+### Dates
+
+#### Validate that a date attribute is before a given date:
+
+ 'birthdate' => 'before:1986-28-05';
+
+#### Validate that a date attribute is after a given date:
+
+ 'birthdate' => 'after:1986-28-05';
+
+> **Note:** The **before** and **after** validation rules use the **strtotime** PHP function to convert your date to something the rule can understand.
+
+
+### E-Mail Addresses
+
+#### Validate that an attribute is an e-mail address:
+
+ 'address' => 'email'
+
+> **Note:** This rule uses the PHP built-in *filter_var* method.
+
+
+### URLs
+
+#### Validate that an attribute is a URL:
+
+ 'link' => 'url'
+
+#### Validate that an attribute is an active URL:
+
+ 'link' => 'active_url'
+
+> **Note:** The *active_url* rule uses *checkdnsr* to verify the URL is active.
+
+
+### Uploads
+
+The *mimes* rule validates that an uploaded file has a given MIME type. This rule uses the PHP Fileinfo extension to read the contents of the file and determine the actual MIME type. Any extension defined in the *config/mimes.php* file may be passed to this rule as a parameter:
+
+#### Validate that a file is one of the given types:
+
+ 'picture' => 'mimes:jpg,gif'
+
+> **Note:** When validating files, be sure to use Input::file() or Input::all() to gather the input.
+
+#### Validate that a file is an image:
+
+ 'picture' => 'image'
+
+#### Validate that a file is no more than a given size in kilobytes:
+
+ 'picture' => 'image|max:100'
+
+
+## Retrieving Error Messages
+
+Laravel makes working with your error messages a cinch using a simple error collector class. After calling the *passes* or *fails* method on a Validator instance, you may access the errors via the *errors* property. The error collector has several simple functions for retrieving your messages:
+
+#### Determine if an attribute has an error message:
+
+ if ($validation->errors->has('email'))
+ {
+ // The e-mail attribute has errors...
+ }
+
+#### Retrieve the first error message for an attribute:
+
+ echo $validation->errors->first('email');
+
+Sometimes you may need to format the error message by wrapping it in HTML. No problem. Along with the :message place-holder, pass the format as the second parameter to the method.
+
+#### Format an error message:
+
+ echo $validation->errors->first('email', '
:message
');
+
+#### Get all of the error messages for a given attribute:
+
+ $messages = $validation->errors->get('email');
+
+#### Format all of the error messages for an attribute:
+
+ $messages = $validation->errors->get('email', '
:message
');
+
+#### Get all of the error messages for all attributes:
+
+ $messages = $validation->errors->all();
+
+#### Format all of the error messages for all attributes:
+
+ $messages = $validation->errors->all('
:message
');
+
+
+## Validation Walkthrough
+
+Once you have performed your validation, you need an easy way to get the errors back to the view. Laravel makes it amazingly simple. Let's walk through a typical scenario. We'll define two routes:
+
+ Route::get('register', function()
+ {
+ return View::make('user.register');
+ });
+
+ Route::post('register', function()
+ {
+ $rules = array(...);
+
+ $validation = Validator::make(Input::all(), $rules);
+
+ if ($validation->fails())
+ {
+ return Redirect::to('register')->with_errors($validation);
+ }
+ });
+
+Great! So, we have two simple registration routes. One to handle displaying the form, and one to handle the posting of the form. In the POST route, we run some validation over the input. If the validation fails, we redirect back to the registration form and flash the validation errors to the session so they will be available for us to display.
+
+**But, notice we are not explicitly binding the errors to the view in our GET route**. However, an errors variable will still be available in the view. Laravel intelligently determines if errors exist in the session, and if they do, binds them to the view for you. If no errors exist in the session, an empty message container will still be bound to the view. In your views, this allows you to always assume you have a message container available via the errors variable. We love making your life easier.
+
+
+## Custom Error Messages
+
+Want to use an error message other than the default? Maybe you even want to use a custom error message for a given attribute and rule. Either way, the Validator class makes it easy.
+
+#### Create an array of custom messages for the Validator:
+
+ $messages = array(
+ 'required' => 'The :attribute field is required.',
+ );
+
+ $validation = Validator::make(Input::get(), $rules, $messages);
+
+Great! Now our custom message will be used anytime a required validation check fails. But, what is this **:attribute** stuff in our message? To make your life easier, the Validator class will replace the **:attribute** place-holder with the actual name of the attribute! It will even remove underscores from the attribute name.
+
+You may also use the **:other**, **:size**, **:min**, **:max**, and **:values** place-holders when constructing your error messages:
+
+#### Other validation message place-holders:
+
+ $messages = array(
+ 'same' => 'The :attribute and :other must match.',
+ 'size' => 'The :attribute must be exactly :size.',
+ 'between' => 'The :attribute must be between :min - :max.',
+ 'in' => 'The :attribute must be one of the following types: :values',
+ );
+
+So, what if you need to specify a custom required message, but only for the email attribute? No problem. Just specify the message using an **attribute_rule** naming convention:
+
+#### Specifying a custom error message for a given attribute:
+
+ $messages = array(
+ 'email_required' => 'We need to know your e-mail address!',
+ );
+
+In the example above, the custom required message will be used for the email attribute, while the default message will be used for all other attributes.
+
+However, if you are using many custom error messages, specifying inline may become cumbersome and messy. For that reason, you can specify your custom messages in the **custom** array within the validation language file:
+
+#### Adding custom error messages to the validation langauge file:
+
+ 'custom' => array(
+ 'email_required' => 'We need to know your e-mail address!',
+ )
+
+
+## Custom Validation Rules
+
+Laravel provides a number of powerful validation rules. However, it's very likely that you'll need to eventually create some of your own. There are two simple methods for creating validation rules. Both are solid so use whichever you think best fits your project.
+
+#### Registering a custom validation rule:
+
+ Validator::register('awesome', function($attribute, $value, $parameters)
+ {
+ return $value == 'awesome';
+ });
+
+In this example we're registering a new validation rule with the validator. The rule receives three arguments. The first is the name of the attribute being validated, the second is the value of the attribute being validated, and the third is an array of parameters that were specified for the rule.
+
+Here is how your custom validation rule looks when called:
+
+ $rules = array(
+ 'username' => 'required|awesome',
+ );
+
+Of course, you will need to define an error message for your new rule. You can do this either in an ad-hoc messages array:
+
+ $messages = array(
+ 'awesome' => 'The attribute value must be awesome!',
+ );
+
+ $validator = Validator::make(Input::get(), $rules, $messages);
+
+Or by adding an entry for your rule in the **language/en/validation.php** file:
+
+ 'awesome' => 'The attribute value must be awesome!',
+
+As mentioned above, you may even specify and receive a list of parameters in your custom rule:
+
+ // When building your rules array...
+
+ $rules = array(
+ 'username' => 'required|awesome:yes',
+ );
+
+ // In your custom rule...
+
+ Validator::register('awesome', function($attribute, $value, $parameters)
+ {
+ return $value == $parameters[0];
+ }
+
+In this case, the parameters argument of your validation rule would receive an array containing one element: "yes".
+
+Another method for creating and storing custom validation rules is to extend the Validator class itself. By extending the class you create a new version of the validator that has all of the pre-existing functionality combined with your own custom additions. You can even choose to replace some of the default methods if you'd like. Let's look at an example:
+
+First, create a class that extends **Laravel\Validator** and place it in your **application/libraries** directory:
+
+#### Defining a custom validator class:
+
+
+## Registering Assets
+
+The **Asset** class provides a simple way to manage the CSS and JavaScript used by your application. To register an asset just call the **add** method on the **Asset** class:
+
+#### Registering an asset:
+
+ Asset::add('jquery', 'js/jquery.js');
+
+The **add** method accepts three parameters. The first is the name of the asset, the second is the path to the asset relative to the **public** directory, and the third is a list of asset dependencies (more on that later). Notice that we did not tell the method if we were registering JavaScript or CSS. The **add** method will use the file extension to determine the type of file we are registering.
+
+
+## Dumping Assets
+
+When you are ready to place the links to the registered assets on your view, you may use the **styles** or **scripts** methods:
+
+#### Dumping assets into a view:
+
+
+
+
+
+
+
+## Asset Dependencies
+
+Sometimes you may need to specify that an asset has dependencies. This means that the asset requires other assets to be declared in your view before it can be declared. Managing asset dependencies couldn't be easier in Laravel. Remember the "names" you gave to your assets? You can pass them as the third parameter to the **add** method to declare dependencies:
+
+#### Registering a bundle that has dependencies:
+
+ Asset::add('jquery-ui', 'js/jquery-ui.js', 'jquery');
+
+In this example, we are registering the **jquery-ui** asset, as well as specifying that it is dependent on the **jquery** asset. Now, when you place the asset links on your views, the jQuery asset will always be declared before the jQuery UI asset. Need to declare more than one dependency? No problem:
+
+#### Registering an asset that has multiple dependencies:
+
+ Asset::add('jquery-ui', 'js/jquery-ui.js', array('first', 'second'));
+
+
+## Asset Containers
+
+To increase response time, it is common to place JavaScript at the bottom of HTML documents. But, what if you also need to place some assets in the head of your document? No problem. The asset class provides a simple way to manage asset **containers**. Simply call the **container** method on the Asset class and mention the container name. Once you have a container instance, you are free to add any assets you wish to the container using the same syntax you are used to:
+
+#### Retrieving an instance of an asset container:
+
+ Asset::container('footer')->add('example', 'js/example.js');
+
+#### Dumping that assets from a given container:
+
+ echo Asset::container('footer')->scripts();
+
+
+## Bundle Assets
+
+Before learning how to conveniently add and dump bundle assets, you may wish to read the documentation on [creating and publishing bundle assets](/docs/bundles#bundle-assets).
+
+When registering assets, the paths are typically relative to the **public** directory. However, this is inconvenient when dealing with bundle assets, since they live in the **public/bundles** directory. But, remember, Laravel is here to make your life easier. So, it is simple to specify the bundle which the Asset container is managing.
+
+#### Specifying the bundle the asset container is managing:
+
+ Asset::container('foo')->bundle('admin');
+
+Now, when you add an asset, you can use paths relative to the bundle's public directory. Laravel will automatically generate the correct full paths.
\ No newline at end of file
diff --git a/laravel/documentation/views/forms.md b/laravel/documentation/views/forms.md
new file mode 100644
index 0000000..7efaed2
--- /dev/null
+++ b/laravel/documentation/views/forms.md
@@ -0,0 +1,153 @@
+# Building Forms
+
+## Contents
+
+- [Opening A Form](#opening-a-form)
+- [CSRF Protection](#csrf-protection)
+- [Labels](#labels)
+- [Text, Text Area, Password & Hidden Fields](#text)
+- [Checkboxes and Radio Buttons](#checkboxes-and-radio-buttons)
+- [Drop-Down Lists](#drop-down-lists)
+- [Buttons](#buttons)
+- [Custom Macros](#custom-macros)
+
+> **Note:** All input data displayed in form elements is filtered through the HTML::entities method.
+
+
+## Opening A Form
+
+#### Opening a form to POST to the current URL:
+
+ echo Form::open();
+
+#### Opening a form using a given URI and request method:
+
+ echo Form::open('user/profile', 'PUT');
+
+#### Opening a Form that POSTS to a HTTPS URL:
+
+ echo Form::open_secure('user/profile');
+
+#### Specifying extra HTML attributes on a form open tag:
+
+ echo Form::open('user/profile', 'POST', array('class' => 'awesome'));
+
+#### Opening a form that accepts file uploads:
+
+ echo Form::open_for_files('users/profile');
+
+#### Opening a form that accepts file uploads and uses HTTPS:
+
+ echo Form::open_secure_for_files('users/profile');
+
+#### Closing a form:
+
+ echo Form::close();
+
+
+## CSRF Protection
+
+Laravel provides an easy method of protecting your application from cross-site request forgeries. First, a random token is placed in your user's session. Don't sweat it, this is done automatically. Next, use the token method to generate a hidden form input field containing the random token on your form:
+
+#### Generating a hidden field containing the session's CSRF token:
+
+ echo Form::token();
+
+#### Attaching the CSRF filter to a route:
+
+ Route::post('profile', array('before' => 'csrf', function()
+ {
+ //
+ }));
+
+#### Retrieving the CSRF token string:
+
+ $token = Session::token();
+
+> **Note:** You must specify a session driver before using the Laravel CSRF protection facilities.
+
+*Further Reading:*
+
+- [Route Filters](/docs/routing#filters)
+- [Cross-Site Request Forgery](http://en.wikipedia.org/wiki/Cross-site_request_forgery)
+
+
+## Labels
+
+#### Generating a label element:
+
+ echo Form::label('email', 'E-Mail Address');
+
+#### Specifying extra HTML attributes for a label:
+
+ echo Form::label('email', 'E-Mail Address', array('class' => 'awesome'));
+
+> **Note:** After creating a label, any form element you create with a name matching the label name will automatically receive an ID matching the label name as well.
+
+
+## Text, Text Area, Password & Hidden Fields
+
+#### Generate a text input element:
+
+ echo Form::text('username');
+
+#### Specifying a default value for a text input element:
+
+ echo Form::text('email', 'example@gmail.com');
+
+> **Note:** The *hidden* and *textarea* methods have the same signature as the *text* method. You just learned three methods for the price of one!
+
+#### Generating a password input element:
+
+ echo Form::password('password');
+
+
+## Checkboxes and Radio Buttons
+
+#### Generating a checkbox input element:
+
+ echo Form::checkbox('name', 'value');
+
+#### Generating a checkbox that is checked by default:
+
+ echo Form::checkbox('name', 'value', true);
+
+> **Note:** The *radio* method has the same signature as the *checkbox* method. Two for one!
+
+
+## Drop-Down Lists
+
+#### Generating a drop-down list from an array of items:
+
+ echo Form::select('size', array('L' => 'Large', 'S' => 'Small'));
+
+#### Generating a drop-down list with an item selected by default:
+
+ echo Form::select('size', array('L' => 'Large', 'S' => 'Small'), 'S');
+
+
+## Buttons
+
+#### Generating a submit button element:
+
+ echo Form::submit('Click Me!');
+
+> **Note:** Need to create a button element? Try the *button* method. It has the same signature as *submit*.
+
+
+## Custom Macros
+
+It's easy to define your own custom Form class helpers called "macros". Here's how it works. First, simply register the macro with a given name and a Closure:
+
+#### Registering a Form macro:
+
+ Form::macro('my_field', function()
+ {
+ return '';
+ });
+
+Now you can call your macro using its name:
+
+#### Calling a custom Form macro:
+
+ echo Form::my_field();
\ No newline at end of file
diff --git a/laravel/documentation/views/home.md b/laravel/documentation/views/home.md
new file mode 100644
index 0000000..be64639
--- /dev/null
+++ b/laravel/documentation/views/home.md
@@ -0,0 +1,260 @@
+# Views & Responses
+
+## Contents
+
+- [The Basics](#the-basics)
+- [Binding Data To Views](#binding-data-to-views)
+- [Nesting Views](#nesting-views)
+- [Named Views](#named-views)
+- [View Composers](#view-composers)
+- [Redirects](#redirects)
+- [Redirecting With Flash Data](#redirecting-with-flash-data)
+- [Downloads](#downloads)
+- [Errors](#errors)
+
+
+## The Basics
+
+Views contain the HTML that is sent to the person using your application. By separating your view from the business logic of your application, your code will be cleaner and easier to maintain.
+
+All views are stored within the **application/views** directory and use the PHP file extension. The **View** class provides a simple way to retrieve your views and return them to the client. Let's look at an example!
+
+#### Creating the view:
+
+
+ I'm stored in views/home/index.php!
+
+
+#### Returning the view from a route:
+
+ Route::get('/', function()
+ {
+ return View::make('home.index');
+ });
+
+#### Returning the view from a controller:
+
+ public function action_index()
+ {
+ return View::make('home.index');
+ });
+
+#### Determining if a view exists:
+
+ $exists = View::exists('home.index');
+
+Sometimes you will need a little more control over the response sent to the browser. For example, you may need to set a custom header on the response, or change the HTTP status code. Here's how:
+
+#### Returning a custom response:
+
+ Route::get('/', function()
+ {
+ $headers = array('foo' => 'bar');
+
+ return Response::make('Hello World!', 200, $headers);
+ });
+
+#### Returning a custom response containing a view:
+
+ return Response::view('home', 200, $headers);
+
+#### Returning a JSON response:
+
+ return Response::json(array('name' => 'Batman'));
+
+#### Returning Eloquent models as JSON:
+
+ return Response::eloquent(User::find(1));
+
+
+## Binding Data To Views
+
+Typically, a route or controller will request data from a model that the view needs to display. So, we need a way to pass the data to the view. There are several ways to accomplish this, so just pick the way that you like best!
+
+#### Binding data to a view:
+
+ Route::get('/', function()
+ {
+ return View::make('home')->with('name', 'James');
+ });
+
+#### Accessing the bound data within a view:
+
+
+ Hello, .
+
+
+#### Chaining the binding of data to a view:
+
+ View::make('home')
+ ->with('name', 'James')
+ ->with('votes', 25);
+
+#### Passing an array of data to bind data:
+
+ View::make('home', array('name' => 'James'));
+
+#### Using magic methods to bind data:
+
+ $view->name = 'James';
+ $view->email = 'example@example.com';
+
+#### Using the ArrayAccess interface methods to bind data:
+
+ $view['name'] = 'James';
+ $view['email'] = 'example@example.com';
+
+
+## Nesting Views
+
+Often you will want to nest views within views. Nested views are sometimes called "partials", and help you keep views small and modular.
+
+#### Binding a nested view using the "nest" method:
+
+ View::make('home')->nest('footer', 'partials.footer');
+
+#### Passing data to a nested view:
+
+ $view = View::make('home');
+
+ $view->nest('content', 'orders', array('orders' => $orders));
+
+Sometimes you may wish to directly include a view from within another view. You can use the **render** helper function:
+
+#### Using the "render" helper to display a view:
+
+
+
+
+
+It is also very common to have a partial view that is responsible for display an instance of data in a list. For example, you may create a partial view responsible for displaying the details about a single order. Then, for example, you may loop through an array of orders, rendering the partial view for each order. This is made simpler using the **render_each** helper:
+
+#### Rendering a partial view for each item in an array:
+
+
+
+
+The first argument is the name of the partial view, the second is the array of data, and the third is the variable name that should be used when each array item is passed to the partial view.
+
+
+## Named Views
+
+Named views can help to make your code more expressive and organized. Using them is simple:
+
+#### Registering a named view:
+
+ View::name('layouts.default', 'layout');
+
+#### Getting an instance of the named view:
+
+ return View::of('layout');
+
+#### Binding data to a named view:
+
+ return View::of('layout', array('orders' => $orders));
+
+
+## View Composers
+
+Each time a view is created, its "composer" event will be fired. You can listen for this event and use it to bind assets and common data to the view each time it is created. A common use-case for this functionality is a side-navigation partial that shows a list of random blog posts. You can nest your partial view by loading it in your layout view. Then, define a composer for that partial. The composer can then query the posts table and gather all of the necessary data to render your view. No more random logic strewn about! Composers are typically defined in **application/routes.php**. Here's an example:
+
+#### Register a view composer for the "home" view:
+
+ View::composer('home', function($view)
+ {
+ $view->nest('footer', 'partials.footer');
+ });
+
+Now each time the "home" view is created, an instance of the View will be passed to the registered Closure, allowing you to prepare the view however you wish.
+
+#### Register a composer that handles multiple views:
+
+ View::composer(array('home', 'profile'), function($view)
+ {
+ //
+ });
+
+> **Note:** A view can have more than one composer. Go wild!
+
+
+## Redirects
+
+It's important to note that both routes and controllers require responses to be returned with the 'return' directive. Instead of calling "Redirect::to()"" where you'd like to redirect the user. You'd instead use "return Redirect::to()". This distinction is important as it's different than most other PHP frameworks and it could be easy to accidentally overlook the importance of this practice.
+
+#### Redirecting to another URI:
+
+ return Redirect::to('user/profile');
+
+#### Redirecting with a specific status:
+
+ return Redirect::to('user/profile', 301);
+
+#### Redirecting to a secure URI:
+
+ return Redirect::to_secure('user/profile');
+
+#### Redirecting to the root of your application:
+
+ return Redirect::home();
+
+#### Redirecting back to the previous action:
+
+ return Redirect::back();
+
+#### Redirecting to a named route:
+
+ return Redirect::to_route('profile');
+
+#### Redirecting to a controller action:
+
+ return Redirect::to_action('home@index');
+
+Sometimes you may need to redirect to a named route, but also need to specify the values that should be used instead of the route's URI wildcards. It's easy to replace the wildcards with proper values:
+
+#### Redirecting to a named route with wildcard values:
+
+ return Redirect::to_route('profile', array($username));
+
+#### Redirecting to an action with wildcard values:
+
+ return Redirect::to_action('user@profile', array($username));
+
+
+## Redirecting With Flash Data
+
+After a user creates an account or signs into your application, it is common to display a welcome or status message. But, how can you set the status message so it is available for the next request? Use the with() method to send flash data along with the redirect response.
+
+ return Redirect::to('profile')->with('status', 'Welcome Back!');
+
+You can access your message from the view with the Session get method:
+
+ $status = Session::get('status');
+
+*Further Reading:*
+
+- *[Sessions](/docs/session/config)*
+
+
+## Downloads
+
+#### Sending a file download response:
+
+ return Response::download('file/path.jpg');
+
+#### Sending a file download and assigning a file name:
+
+ return Response::download('file/path.jpg', 'photo.jpg');
+
+
+## Errors
+
+To generating proper error responses simply specify the response code that you wish to return. The corresponding view stored in **views/error** will automatically be returned.
+
+#### Generating a 404 error response:
+
+ return Response::error('404');
+
+#### Generating a 500 error response:
+
+ return Response::error('500');
\ No newline at end of file
diff --git a/laravel/documentation/views/html.md b/laravel/documentation/views/html.md
new file mode 100644
index 0000000..d1fcae9
--- /dev/null
+++ b/laravel/documentation/views/html.md
@@ -0,0 +1,139 @@
+# Building HTML
+
+## Content
+
+- [Entities](#entities)
+- [Scripts And Style Sheets](#scripts-and-style-sheets)
+- [Links](#links)
+- [Links To Named Routes](#links-to-named-routes)
+- [Links To Controller Actions](#links-to-controller-actions)
+- [Mail-To Links](#mail-to-links)
+- [Images](#images)
+- [Lists](#lists)
+- [Custom Macros](#custom-macros)
+
+
+## Entities
+
+When displaying user input in your Views, it is important to convert all characters which have signifance in HTML to their "entity" representation.
+
+For example, the < symbol should be converted to its entity representation. Converting HTML characters to their entity representation helps protect your application from cross-site scripting:
+
+#### Converting a string to its entity representation:
+
+ echo HTML::entities('');
+
+#### Using the "e" global helper:
+
+ echo e('');
+
+
+## Scripts And Style Sheets
+
+#### Generating a reference to a JavaScript file:
+
+ echo HTML::script('js/scrollTo.js');
+
+#### Generating a reference to a CSS file:
+
+ echo HTML::style('css/common.css');
+
+#### Generating a reference to a CSS file using a given media type:
+
+ echo HTML::style('css/common.css', 'print');
+
+*Further Reading:*
+
+- *[Managing Assets](/docs/views/assets)*
+
+
+## Links
+
+#### Generating a link from a URI:
+
+ echo HTML::link('user/profile', 'User Profile');
+
+#### Generating a link that should use HTTPS:
+
+ echo HTML::secure_link('user/profile', 'User Profile');
+
+#### Generating a link and specifying extra HTML attributes:
+
+ echo HTML::link('user/profile', 'User Profile', array('id' => 'profile_link'));
+
+
+## Links To Named Routes
+
+#### Generating a link to a named route:
+
+ echo HTML::link_to_route('profile');
+
+#### Generating a link to a named route with wildcard values:
+
+ $url = HTML::link_to_route('profile', array($username));
+
+*Further Reading:*
+
+- *[Named Routes](/docs/routing#named-routes)*
+
+
+## Links To Controller Actions
+
+#### Generating a link to a controller action:
+
+ echo HTML::link_to_action('home@index');
+
+### Generating a link to a controller action with wildcard values:
+
+ echo HTML::link_to_action('user@profile', array($username));
+
+
+## Mail-To Links
+
+The "mailto" method on the HTML class obfuscates the given e-mail address so it is not sniffed by bots.
+
+#### Creating a mail-to link:
+
+ echo HTML::mailto('example@gmail.com', 'E-Mail Me!');
+
+#### Creating a mail-to link using the e-mail address as the link text:
+
+ echo HTML::mailto('example@gmail.com');
+
+
+## Images
+
+#### Generating an HTML image tag:
+
+ echo HTML::image('img/smile.jpg', $alt_text);
+
+#### Generating an HTML image tag with extra HTML attributes:
+
+ echo HTML::image('img/smile.jpg', $alt_text, array('id' => 'smile'));
+
+
+## Lists
+
+#### Creating lists from an array of items:
+
+ echo HTML::ol(array('Get Peanut Butter', 'Get Chocolate', 'Feast'));
+
+ echo HTML::ul(array('Ubuntu', 'Snow Leopard', 'Windows'));
+
+
+## Custom Macros
+
+It's easy to define your own custom HTML class helpers called "macros". Here's how it works. First, simply register the macro with a given name and a Closure:
+
+#### Registering a HTML macro:
+
+ HTML::macro('my_element', function()
+ {
+ return '';
+ });
+
+Now you can call your macro using its name:
+
+#### Calling a custom HTML macro:
+
+ echo HTML::my_element();
diff --git a/laravel/documentation/views/pagination.md b/laravel/documentation/views/pagination.md
new file mode 100644
index 0000000..602b09b
--- /dev/null
+++ b/laravel/documentation/views/pagination.md
@@ -0,0 +1,104 @@
+# Pagination
+
+## Contents
+
+- [The Basics](#the-basics)
+- [Using The Query Builder](#using-the-query-builder)
+- [Appending To Pagination Links](#appending-to-pagination-links)
+- [Creating Paginators Manually](#creating-paginators-manually)
+- [Pagination Styling](#pagination-styling)
+
+
+## The Basics
+
+Laravel's paginator was designed to reduce the clutter of implementing pagination.
+
+
+## Using The Query Builder
+
+Let's walk through a complete example of paginating using the [Fluent Query Builder](/docs/database/fluent):
+
+#### Pull the paginated results from the query:
+
+ $orders = DB::table('orders')->paginate($per_page);
+
+#### Display the results in a view:
+
+ results as $order): ?>
+ id; ?>
+
+
+#### Generate the pagination links:
+
+ links(); ?>
+
+The links method will create an intelligent, sliding list of page links that looks something like this:
+
+ Previous 1 2 ... 24 25 26 27 28 29 30 ... 78 79 Next
+
+The Paginator will automatically determine which page you're on and update the results and links accordingly.
+
+It's also possible to generate "next" and "previous" links:
+
+#### Generating simple "previous" and "next" links:
+
+ previous().' '.$orders->next(); ?>
+
+*Further Reading:*
+
+- *[Fluent Query Builder](/docs/database/fluent)*
+
+
+## Appending To Pagination Links
+
+You may need to add more items to the pagination links' query strings, such as the column your are sorting by.
+
+#### Appending to the query string of pagination links:
+
+ appends(array('sort' => 'votes'))->links();
+
+This will generate URLs that look something like this:
+
+ http://example.com/something?page=2&sort=votes
+
+
+## Creating Paginators Manually
+
+Sometimes you may need to create a Paginator instance manually, without using the query builder. Here's how:
+
+#### Creating a Paginator instance manually:
+
+ $orders = Paginator::make($orders, $total, $per_page);
+
+
+## Pagination Styling
+
+All pagination link elements can be style using CSS classes. Here is an example of the HTML elements generated by the links method:
+
+
+
+When you are on the first page of results, the "Previous" link will be disabled. Likewise, the "Next" link will be disabled when you are on the last page of results. The generated HTML will look like this:
+
+ Previous
\ No newline at end of file
diff --git a/laravel/documentation/views/templating.md b/laravel/documentation/views/templating.md
new file mode 100644
index 0000000..8849f0e
--- /dev/null
+++ b/laravel/documentation/views/templating.md
@@ -0,0 +1,180 @@
+# Templating
+
+## Contents
+
+- [The Basics](#the-basics)
+- [Sections](#sections)
+- [Blade Template Engine](#blade-template-engine)
+- [Blade Layouts](#blade-layouts)
+
+
+## The Basics
+
+Your application probably uses a common layout across most of its pages. Manually creating this layout within every controller action can be a pain. Specifying a controller layout will make your develompent much more enjoyable. Here's how to get started:
+
+#### Specify a "layout" property on your controller:
+
+ class Base_Controller extends Controller {
+
+ public $layout = 'layouts.common';
+
+ }
+
+#### Access the layout from the controllers' action:
+
+ public function action_profile()
+ {
+ $this->layout->nest('content', 'user.profile');
+ }
+
+> **Note:** When using layouts, actions do not need to return anything.
+
+
+## Sections
+
+View sections provide a simple way to inject content into layouts from nested views. For example, perhaps you want to inject a nested view's needed JavaScript into the header of your layout. Let's dig in:
+
+#### Creating a section within a view:
+
+
+
+
+
+#### Rendering the contents of a section:
+
+
+
+
+
+#### Using Blade short-cuts to work with sections:
+
+ @section('scripts')
+
+ @endsection
+
+
+ @yield('scripts')
+
+
+
+## Blade Template Engine
+
+Blade makes writing your views pure bliss. To create a blade view, simply name your view file with a ".blade.php" extension. Blade allows you to use beautiful, unobtrusive syntax for writing PHP control structures and echoing data. Here's an example:
+
+#### Echoing a variable using Blade:
+
+ Hello, {{$name}}.
+
+#### Echoing function results using Blade:
+
+ {{ Asset::styles() }}
+
+#### Rendering a view:
+
+
Profile
+
+ @include('user.profile')
+
+> **Note:** When using the **@include** Blade expression, the view will automatically inherit all of the current view data.
+
+#### Creating loops using Blade:
+
+
Comments
+
+ @foreach ($comments as $comment)
+ The comment body is {{$comment->body}}.
+ @endforeach
+
+#### Other Blade control structures:
+
+ @if (count($comments) > 0)
+ I have comments!
+ @else
+ I have no comments!
+ @endif
+
+ @for ($i =0; $i < count($comments) - 1; $i++)
+ The comment body is {{$comments[$i]}}
+ @endfor
+
+ @while ($something)
+ I am still looping!
+ @endwhile
+
+#### The "for-else" control structure:
+
+ @forelse ($posts as $post)
+ {{ $post->body }}
+ @empty
+ There are not posts in the array!
+ @endforelse
+
+
+#### The "unless" control structure:
+
+ @unless(Auth::check())
+ {{ HTML::link_to_route('login', 'Login'); }}
+ @endunless
+
+ // Equivalent...
+
+
+ ...
+
+
+
+#### Blade comments:
+
+ @if ($check)
+ {{-- This is a comment --}}
+ ...
+ @endif
+
+> **Note:** Blade comments, unlike HTML comments, are not visible in the HTML source.
+
+
+## Blade Layouts
+
+Not only does Blade provide clean, elegant syntax for common PHP control structures, it also gives you a beautiful method of using layouts for your views. For example, perhaps your application uses a "master" view to provide a common look and feel for your application. It may look something like this:
+
+
+
+ @section('navigation')
+
Nav Item 1
+
Nav Item 2
+ @yield_section
+
+
+
+ @yield('content')
+
+
+
+Notice the "content" section being yielded. We need to fill this section with some text, so let's make another view that uses this layout:
+
+ @layout('master')
+
+ @section('content')
+ Welcome to the profile page!
+ @endsection
+
+Great! Now, we can simply return the "profile" view from our route:
+
+ return View::make('profile');
+
+The profile view will automatically use the "master" template thanks to Blade's **@layout** expression.
+
+Sometimes you may want to only append to a section of a layout rather than overwrite it. For example, consider the navigation list in our "master" layout. Let's assume we just want to append a new list item. Here's how to do it:
+
+ @layout('master')
+
+ @section('navigation')
+ @parent
+
Nav Item 3
+ @endsection
+
+ @section('content')
+ Welcome to the profile page!
+ @endsection
+
+Notice the **@parent** Blade construct? It will be replaced with the contents of the layout's navigation section, providing you with a beautiful and powerful method of performing layout extension and inheritance.
\ No newline at end of file
diff --git a/laravel/error.php b/laravel/error.php
new file mode 100644
index 0000000..729f632
--- /dev/null
+++ b/laravel/error.php
@@ -0,0 +1,110 @@
+
Unhandled Exception
+
Message:
+
".$exception->getMessage()."
+
Location:
+
".$exception->getFile()." on line ".$exception->getLine()."