Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: App object to encapsulate global state and services #6681

Closed
15 of 27 tasks
chillu opened this issue Mar 6, 2017 · 60 comments
Closed
15 of 27 tasks

RFC: App object to encapsulate global state and services #6681

chillu opened this issue Mar 6, 2017 · 60 comments

Comments

@chillu
Copy link
Member

chillu commented Mar 6, 2017

Acceptance Criteria

  • A kernel object exists, which can be easily overridden in user code, to control the boot process of any silverstripe application.
  • An application object exists, which can be easily overridden in user code, to control the execution of any request in a silverstripe application.
  • All components which make up the state of the Kernel object are available via Injector service, even if these components are initialised pre-config (including the Kernel itself).
  • Kernel has no static members.
  • The Kernel object can be nested (and un-nested), which internally nests all core services, as well as injector / config. However, this nesting is performed per-instance and not via static accessors as with config / injector.
  • Cookie, Requirements, Config::inst() and Injector::inst() functionality remains unaltered.
  • HTTPRequest is not a part of kernel, nor are any request-specific services.
  • Session should accessible through the HTTPRequest (no longer static).
  • Development experience should not be greatly adversely affected for classes which use the main core traits.
  • If a non-current instance of Injector / Config is ever invoked, it must raise a logic error to enforce application consistency.
  • The concept is applied to all core modules
  • The upgrade path is clearly documented

Excludes

  • Converting static methods on core classes to instance methods
  • Converting core classes to interfaces
  • Global variable state (e.g. $_SESSION, $_REQUEST) for initial implementation.

Notes

  • PSR-11 discourages the direct use of service locators in implementations
  • Symfony exposes services service locators (e.g. $this->app->get('my-dependency'))

RFC Versions

Related

Tasks

  • Agree on RFC and implementation goals
  • Create new Kernel / Application interfaces and base classes
  • Re-implement nesting and refactor injector / config manifests into CoreKernal
  • Implement SilverStripe specific AppKernel to replace Core.php
  • Refactor main.php into HTTPApplication (incl errorcontrolchain)
  • Refactor cli-main.php to use new HTTPApplication (CLIApplication class is future-scope)
  • Implement HTTPRequest::createFromEnviroment()
  • Refactor Session instance to be a HTTPRequest member
  • Ensure Director::test (or some equivalent) is still available
  • Upgrading guide
  • Documentation, including customising app in user code
  • move ConfigureFromEnv.php into AppKernel::boot()
  • Move is_running_tests() into Kernel
  • lazy DB::connect()
  • Upgrade unit tests

WIP branches

@chillu
Copy link
Member Author

chillu commented Mar 6, 2017

Required for making manifest caches configurable through PSR-16: #6647

@tractorcow
Copy link
Contributor

I have written up a new RFC covering the full interface for App and DefautAppFactory

Please see https://gist.github.com/tractorcow/c0656a334c13eac8ae252610d226a1c6

@nyeholt
Copy link
Contributor

nyeholt commented May 17, 2017

Don't have time to delve too deeply right now, but a few years back AJShort did some extensive work down this line. There's a full commit list still at https://github.com/ajshort/sapphire/commits/composer , with relevant code mostly in https://github.com/ajshort/sapphire/tree/composer/src/SilverStripe/Framework

@micmania1
Copy link
Contributor

I don't really get the whole nest/unnest thing. I know that its a pattern used elsewhere but can't you just use clone? The only time I can see this being used would be in testing, but clone would work then too and you wouldn't have to call unnest() at the end. The only reason nest/unnest would be required is if we're making static calls to App::inst() in which case we'd need to track the current app.

This leads on to my next question...
App::inst() vs __construct($app) - For classes which need to know about the app object, what's the end goal?

Injector::inst() and Config::inst() - where does this leave these methods? Would they be deprecated in favour of $app->getConfig()?

@tractorcow
Copy link
Contributor

tractorcow commented May 17, 2017

Nesting is important to ensure that state is retained at the point of nesting. This means that nesting at the application level includes not only nesting of the various direct dependencies, but also the current state of each dependent nested chains.

E.g.

State A:
App (state1)
-  Config (state1)
-  Injector (state1)

Injector::nest()

State B:
App (state1)
-  Config (state1)
-  Injector (state2)

action:
App::nest();

State: C

App (state2)
-  Config (state1)
-  Injector (state2)

Config::nest()
Injector::nest()

State D:
App (state2)
-  Config (state2)
-  Injector (state3)

App::unnest() (note: resets entire chain of nesting for config / injector to point at original App::nest())

App (state1)
  - Config (state1)
  - Injector (state2)

@tractorcow
Copy link
Contributor

tractorcow commented May 17, 2017

The only time I can see this being used would be in testing, but clone would work then too and you wouldn't have to call unnest() at the end.

If you never called unnest, then how could you return to the original state? You would end up with a different config in your local variable clone vs App::inst()->getConfig().

@tractorcow
Copy link
Contributor

App::inst() vs __construct($app) - For classes which need to know about the app object, what's the end goal?

Well, simply App::inst() is a getter, and the constructor is only used when creating the initial app. The end goal is to consolidate global state into an object.

@tractorcow
Copy link
Contributor

Injector::inst() and Config::inst() - where does this leave these methods? Would they be deprecated in favour of $app->getConfig()?

Yes.

@tractorcow
Copy link
Contributor

@nyeholt main class found at https://github.com/ajshort/sapphire/blob/composer/src/SilverStripe/Framework/Core/Application.php

It does look VERY similar doesn't it? :)

@tractorcow
Copy link
Contributor

Also just to add, I dislike injecting everything with an app property. If you wanted to keep Object class and add setApp / getApp maybe, but we've already agreed that class is going.

@micmania1
Copy link
Contributor

If you never called unnest, then how could you return to the original state? You would end up with a different config in your local variable clone vs App::inst()->getConfig().

If the use-case is for testing, then the variable (nested app) would only exist for the length of the test so would be destroyed and forgot about automatically. You would never actually nest.

eg.

protected function setUp() {
    $initialApp = App:inst();
    $this->app = clone $initialApp;
}

public function testApp() {
    $this->assertInstanceOf(App::class, $this->app);
}

This wouldn't work if you called App::inst() everywhere which is what triggered my question about static call vs injection via constructor.

@tractorcow
Copy link
Contributor

tractorcow commented May 17, 2017

I see your point.

If we did use an app property on every object, but that's very risk prone, given that it only takes a single object to have a mis-assigned app var for it to be running in an incorrect state.

This could easily come around when pre-existing objects are created at the point the application is nested; It'll only affect future objects, and we have no way to guarantee they won't interact with the prior ones. This is why I'm against per-object app assignment.

@micmania1
Copy link
Contributor

What are we testing that would require the entire app to be cloned/nested anyway? Sounds like a pretty big coupling problem we have :p

@tractorcow
Copy link
Contributor

FunctionalTest doesn't use process isolation.

@dhensby
Copy link
Contributor

dhensby commented May 17, 2017

I feel like we need to be looking at https://github.com/symfony/http-kernel for a lot of inspiration here - perhaps even looking to use it - though that may be impossible because it can't accept our DI and so on.

But initially from looking at the proposals it's not clear to me how a request is handled.

I feel we should be aiming for a startup script with bare bones like this:

<?php

$request = HTTPRequest::createFromGlobals();
$response = HTTPResponse::create();

$app = new SilverStripe();

$app->handleRequest($request, $response);

$response->output();

At the moment it's not clear to me how this app object would be used? Or is it really just a holder of state and we are shifting our current global state onto the app object but still leaving a lot of the boot up as is?

@tractorcow
Copy link
Contributor

is it really just a holder of state and we are shifting our current global state onto the app object but still leaving a lot of the boot up as is?

This is generally my feeling; It's a refactor not a radical behavioural change.

@sminnee
Copy link
Member

sminnee commented May 17, 2017

At the moment it's not clear to me how this app object would be used? Or is it really just a holder of state and we are shifting our current global state onto the app object but still leaving a lot of the boot up as is?

The 3 pieces that aren't easily refactored are, module manifest -> config -> injector. The app object can provide these.

I don't think that the app object should provide handleRequest(), for now I'd say leave that responsibility to the director or possibly to a Director and provide a getDirector(). The App object would be constructed even if you were running a small support script that that didn't make use of the router, or somewhere where you were using SilverStripe with another controller stack.

@sminnee
Copy link
Member

sminnee commented May 17, 2017

On nest() / unnest():

There's no longer a case where you need to run tests and have the parent global app object — we deleted the dev/tests/ URL. So you could probably build tests using App::set_inst().

The areas where it would be more likely to be of use would be things like staticpublisher where you want to craft an altered global state for a portion of execution. This is kind of an advanced case and could be handled as an API addition beyond the initial implementation, if needs be. I don't think we would need nest() in the first version, and if we don't implement it now it would give us the freedom to potentially design a better API when we have the use-case in front of us.

For example, rather than nest / unnest we might have something closer Member::actAs()

@tractorcow
Copy link
Contributor

We could drop App::nest() and continue to use individual Injector::nest() / Config::nest() as-is for now. Would that be a fair compromise to get v1 of app done?

@sminnee
Copy link
Member

sminnee commented May 17, 2017

We could drop App::nest() and continue to use individual Injector::nest() / Config::nest() as-is for now. Would that be a fair compromise to get v1 of app done?

No, I think that's worse than creating App::nest() as we'd want to remove the static instances of injector & config. Maybe add the nest() method but mark as experimental.

@chillu
Copy link
Member Author

chillu commented Jun 1, 2017

$response->getRequest() sounds like an API created to mask the deficiencies of another API (a Cookie object which is used for both read and write). Not every response will have a corresponding request, right? I think we should defer this refactor and concentrate on Kernel and Application. Let's see how far we get with the core of this RFC, and then decide if we can still fit the cookie handling into beta1.

Note that cookie reading is part of PSR-7, but writing isn't (only indirectly via Response->with Header()). Related:

https://laravel.com/docs/5.4/responses#attaching-cookies-to-responses
https://symfony.com/doc/current/components/http_foundation.html#setting-cookies
http://paul-m-jones.com/archives/6310
https://github.com/hansott/psr7-cookies
https://github.com/dflydev/dflydev-fig-cookies

$request->getSession() looks a bit more straightforward, that should only live on the request, not the response, right? Both Laravel and Symfony handle it like that.

@sminnee
Copy link
Member

sminnee commented Jun 1, 2017

Do we have to fix cookies (and everything else related to the controller stack) as part of this ticket? It feels like it's turning into a cascade of "fix everything annoying" ;-)

If I were to refactor cookie, I'd probably have a middleware that

  • builds a CookieJar object based on the cookie header of a request
  • attaches it as an attribute to the request object
  • after processing is compete, check for changes to the CookieJar object
  • writes appropriate Set-Cookie headers to the response

However that's well beyond the scope of this card

@tractorcow
Copy link
Contributor

I've had a discussion with @chillu and decided to update the scope of the request / response refactor.

https://gist.github.com/tractorcow/2bb76d12074b885b9b2923dafa07ae88

Cookies API remains unchanged, but we will move Session::inst() into $request->getSession().

@chillu
Copy link
Member Author

chillu commented Jun 1, 2017

Old ACs:

  • There is clear documentation on how to instantiate SS core classes and their dependencies (when to use new vs. dependency injection)
  • There is a way to replace dependencies during early bootstrap (e.g. caching layers initialised before injector kicks in)
  • Interoperability with other libraries is maintained by minimizing use of SS-specific references like Injector and Config in core classes
  • I can use smaller parts of SilverStripe without copying hundreds of lines of main.php and Core.php code in other controller stacks (e.g. Silex and Lumen). Note: This is an architectural goal, and doesn’t need to be operational as part of this card.
  • Configuration can easily be mocked directly on core class instances (without relying on Config::nest() global state)
  • It is clear which dependencies a class relies on without reading the entire class implementation
  • There are no directly overlapping APIs (DataModel method arguments)
  • The concept is applied to all core modules
  • The upgrade path is clearly documented

New ACs:

  • A kernel object exists, which can be easily overridden in user code, to control the boot process of any silverstripe application.
  • An application object exists, which can be easily overridden in user code, to control the execution of any request in a silverstripe application.
  • All components which make up the state of the Kernel object are available via Injector service, even if these components are initialised pre-config (including the Kernel itself).
  • Kernel has no static members.
  • The Kernel object can be nested (and un-nested), which internally nests all core services, as well as injector / config. However, this nesting is performed per-instance and not via static accessors as with config / injector.
  • Cookie, Requirements, Config::inst() and Injector::inst() functionality remains unaltered.
  • HTTPRequest is not a part of kernel, nor are any request-specific services.
  • Session should accessible through the HTTPRequest (no longer static).
  • Development experience should not be greatly adversely affected for classes which use the main core traits.
  • If a non-current instance of Injector / Config is ever invoked, it must raise a logic error to enforce application consistency.
  • The concept is applied to all core modules
  • The upgrade path is clearly documented

@tractorcow
Copy link
Contributor

Nice +1 thanks @chillu

@tractorcow
Copy link
Contributor

Just so that everyone here is clear, we are going to close and accept this RFC pretty early next week. Please get in your concerns early if you have anything you would like to add.

@tractorcow
Copy link
Contributor

Hello, the discussion seems to have tailed off, and given our general agreement on approach we will close this discussion and move onto implementation.

@tractorcow
Copy link
Contributor

todo : update A/C and task.

@tractorcow
Copy link
Contributor

I've just updated the tasks for this story. Quite a lot of progress made so far!

  • no more ConfigureFromEnv.php
  • No more SapphireTest::is_running_tests()
  • Lazy-connect DB::getConn() (great for database-less requests)
  • no more DataModel
  • ErrorControlChain is now entirely optional middleware
  • no more die() anywhere (throwing HTTPResponse_Exception is now preferred).
  • no more Session::inst()
  • no more phpunitshim

@tractorcow
Copy link
Contributor

I've added WIP branches to the initial story body.

New progress:

  • SapphireTest refactor (now boots custom application, injectable test state for restoring / setting initial state). Versioned / etc specific test state is now shifted into versioned module. See tests.yml for core config.
  • Refactor of nesting: No longer do we need to count nest() / unnest() instances! just keep a reference to the initial object, and call ->activate() on it to revert all subsequent nesting. Works on injector, config, and the new app kernel. I've removed static variables from injector / config.
  • Core tests are passing.

chillu pushed a commit that referenced this issue Jun 22, 2017
See #7037
and #6681

Squashed commit of the following:

commit 8f65e56
Author: Ingo Schommer <me@chillu.com>
Date:   Thu Jun 22 22:25:50 2017 +1200

    Fixed upgrade guide spelling

commit 76f9594
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Thu Jun 22 16:38:34 2017 +1200

    BUG Fix non-test class manifest including sapphiretest / functionaltest

commit 9379834
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Thu Jun 22 15:50:47 2017 +1200

    BUG Fix nesting bug in Kernel

commit 188ce35
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Thu Jun 22 15:14:51 2017 +1200

    BUG fix db bootstrapping issues

commit 7ed4660
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Thu Jun 22 14:49:07 2017 +1200

    BUG Fix issue in DetailedErrorFormatter

commit 738f50c
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Thu Jun 22 11:49:19 2017 +1200

    Upgrading notes on mysite/_config.php

commit 6279d28
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Thu Jun 22 11:43:28 2017 +1200

    Update developer documentation

commit 5c90d53
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Thu Jun 22 10:48:44 2017 +1200

    Update installer to not use global databaseConfig

commit f9b2ba4
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Wed Jun 21 21:04:39 2017 +1200

    Fix behat issues

commit 5b59a91
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Wed Jun 21 17:07:11 2017 +1200

    Move HTTPApplication to SilverStripe\Control namespace

commit e2c4a18
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Wed Jun 21 16:29:03 2017 +1200

    More documentation
    Fix up remaining tests
    Refactor temp DB into TempDatabase class so it’s available outside of unit tests.

commit 5d235e6
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Wed Jun 21 12:13:15 2017 +1200

    API HTTPRequestBuilder::createFromEnvironment() now cleans up live globals
    BUG Fix issue with SSViewer
    Fix Security / View tests

commit d88d4ed
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Tue Jun 20 16:39:43 2017 +1200

    API Refactor AppKernel into CoreKernel

commit f7946ae
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Tue Jun 20 16:00:40 2017 +1200

    Docs and minor cleanup

commit 12bd31f
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Tue Jun 20 15:34:34 2017 +1200

    API Remove OutputMiddleware
    API Move environment / global / ini management into Environment class
    API Move getTempFolder into TempFolder class
    API Implement HTTPRequestBuilder / CLIRequestBuilder
    BUG Restore SS_ALLOWED_HOSTS check in original location
    API CoreKernel now requires $basePath to be passed in
    API Refactor installer.php to use application to bootstrap
    API move memstring conversion globals to Convert
    BUG Fix error in CoreKernel nesting not un-nesting itself properly.

commit bba9791
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Mon Jun 19 18:07:53 2017 +1200

    API Create HTTPMiddleware and standardise middleware for request handling

commit 2a10c23
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Mon Jun 19 17:42:42 2017 +1200

    Fixed ORM tests

commit d75a8d1
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Mon Jun 19 17:15:07 2017 +1200

    FIx i18n tests

commit 06364af
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Mon Jun 19 16:59:34 2017 +1200

    Fix controller namespace
    Move states to sub namespace

commit 2a278e2
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Mon Jun 19 12:49:45 2017 +1200

    Fix forms namespace

commit b65c212
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Thu Jun 15 18:56:48 2017 +1200

    Update API usages

commit d1d4375
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Thu Jun 15 18:41:44 2017 +1200

    API Refactor $flush into HTPPApplication
    API Enforce health check in Controller::pushCurrent()
    API Better global backup / restore
    Updated Director::test() to use new API

commit b220534
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Tue Jun 13 22:05:57 2017 +1200

    Move app nesting to a test state helper

commit 6037041
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Tue Jun 13 21:46:04 2017 +1200

    Restore kernel stack to fix multi-level nesting

commit 2f6336a
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Tue Jun 13 17:23:21 2017 +1200

    API Implement kernel nesting

commit fc7188d
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Tue Jun 13 15:43:13 2017 +1200

    Fix core tests

commit a0ae723
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Tue Jun 13 15:23:52 2017 +1200

    Fix manifest tests

commit ca03395
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Tue Jun 13 15:00:00 2017 +1200

    API Move extension management into test state

commit c66d433
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Tue Jun 13 14:10:59 2017 +1200

    API Refactor SapphireTest state management into SapphireTestState
    API Remove Injector::unregisterAllObjects()
    API Remove FakeController

commit f26ae75
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Mon Jun 12 18:04:34 2017 +1200

    Implement basic CLI application object

commit 001d559
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Mon Jun 12 17:39:38 2017 +1200

    Remove references to SapphireTest::is_running_test()
    Upgrade various code

commit de079c0
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Wed Jun 7 18:07:33 2017 +1200

    API Implement APP object
    API Refactor of Session
@chillu
Copy link
Member Author

chillu commented Jun 22, 2017

🎉🎉🎉

@chillu chillu closed this as completed Jun 22, 2017
unclecheese pushed a commit to open-sausages/silverstripe-framework that referenced this issue Jun 26, 2017
See silverstripe#7037
and silverstripe#6681

Squashed commit of the following:

commit 8f65e56
Author: Ingo Schommer <me@chillu.com>
Date:   Thu Jun 22 22:25:50 2017 +1200

    Fixed upgrade guide spelling

commit 76f9594
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Thu Jun 22 16:38:34 2017 +1200

    BUG Fix non-test class manifest including sapphiretest / functionaltest

commit 9379834
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Thu Jun 22 15:50:47 2017 +1200

    BUG Fix nesting bug in Kernel

commit 188ce35
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Thu Jun 22 15:14:51 2017 +1200

    BUG fix db bootstrapping issues

commit 7ed4660
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Thu Jun 22 14:49:07 2017 +1200

    BUG Fix issue in DetailedErrorFormatter

commit 738f50c
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Thu Jun 22 11:49:19 2017 +1200

    Upgrading notes on mysite/_config.php

commit 6279d28
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Thu Jun 22 11:43:28 2017 +1200

    Update developer documentation

commit 5c90d53
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Thu Jun 22 10:48:44 2017 +1200

    Update installer to not use global databaseConfig

commit f9b2ba4
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Wed Jun 21 21:04:39 2017 +1200

    Fix behat issues

commit 5b59a91
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Wed Jun 21 17:07:11 2017 +1200

    Move HTTPApplication to SilverStripe\Control namespace

commit e2c4a18
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Wed Jun 21 16:29:03 2017 +1200

    More documentation
    Fix up remaining tests
    Refactor temp DB into TempDatabase class so it’s available outside of unit tests.

commit 5d235e6
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Wed Jun 21 12:13:15 2017 +1200

    API HTTPRequestBuilder::createFromEnvironment() now cleans up live globals
    BUG Fix issue with SSViewer
    Fix Security / View tests

commit d88d4ed
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Tue Jun 20 16:39:43 2017 +1200

    API Refactor AppKernel into CoreKernel

commit f7946ae
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Tue Jun 20 16:00:40 2017 +1200

    Docs and minor cleanup

commit 12bd31f
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Tue Jun 20 15:34:34 2017 +1200

    API Remove OutputMiddleware
    API Move environment / global / ini management into Environment class
    API Move getTempFolder into TempFolder class
    API Implement HTTPRequestBuilder / CLIRequestBuilder
    BUG Restore SS_ALLOWED_HOSTS check in original location
    API CoreKernel now requires $basePath to be passed in
    API Refactor installer.php to use application to bootstrap
    API move memstring conversion globals to Convert
    BUG Fix error in CoreKernel nesting not un-nesting itself properly.

commit bba9791
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Mon Jun 19 18:07:53 2017 +1200

    API Create HTTPMiddleware and standardise middleware for request handling

commit 2a10c23
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Mon Jun 19 17:42:42 2017 +1200

    Fixed ORM tests

commit d75a8d1
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Mon Jun 19 17:15:07 2017 +1200

    FIx i18n tests

commit 06364af
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Mon Jun 19 16:59:34 2017 +1200

    Fix controller namespace
    Move states to sub namespace

commit 2a278e2
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Mon Jun 19 12:49:45 2017 +1200

    Fix forms namespace

commit b65c212
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Thu Jun 15 18:56:48 2017 +1200

    Update API usages

commit d1d4375
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Thu Jun 15 18:41:44 2017 +1200

    API Refactor $flush into HTPPApplication
    API Enforce health check in Controller::pushCurrent()
    API Better global backup / restore
    Updated Director::test() to use new API

commit b220534
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Tue Jun 13 22:05:57 2017 +1200

    Move app nesting to a test state helper

commit 6037041
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Tue Jun 13 21:46:04 2017 +1200

    Restore kernel stack to fix multi-level nesting

commit 2f6336a
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Tue Jun 13 17:23:21 2017 +1200

    API Implement kernel nesting

commit fc7188d
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Tue Jun 13 15:43:13 2017 +1200

    Fix core tests

commit a0ae723
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Tue Jun 13 15:23:52 2017 +1200

    Fix manifest tests

commit ca03395
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Tue Jun 13 15:00:00 2017 +1200

    API Move extension management into test state

commit c66d433
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Tue Jun 13 14:10:59 2017 +1200

    API Refactor SapphireTest state management into SapphireTestState
    API Remove Injector::unregisterAllObjects()
    API Remove FakeController

commit f26ae75
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Mon Jun 12 18:04:34 2017 +1200

    Implement basic CLI application object

commit 001d559
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Mon Jun 12 17:39:38 2017 +1200

    Remove references to SapphireTest::is_running_test()
    Upgrade various code

commit de079c0
Author: Damian Mooyman <damian@silverstripe.com>
Date:   Wed Jun 7 18:07:33 2017 +1200

    API Implement APP object
    API Refactor of Session
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment