Wrappable methods and RecessView variable scope... Help

30 views
Skip to first unread message

Josh Lockhart

unread,
May 31, 2009, 12:11:34 PM5/31/09
to recess-f...@googlegroups.com
Hi everyone,

I have started using Recess, and from what I can see, this is an absolutely brilliant framework. However, there are a few things that I am stuck on. I have read the docs, and I have explored the framework code's inline docs.But I am still stuck.

Issue 1

I am stuck when it comes to implementing wrapper methods for wrappable methods. I am attempting to wrap a model's Save method. This is my code.

<?php
/**
* !Database default
* !Table users
*/
class User extends Model{

/**
 * !Before save
 */
function beforeSave(){
//perform some validation
return true;
}

}
?>

Unfortunately, Recess throws an error saying it does not recognize the !Before annotation. I'm probably doing something wrong here, but I'm not sure what.

Issue 2

I am trying to use RecessView for my application's views. My code looks like this.

<?php
/**
 * !View RecessView
 */
class MyController extends AuthenticatedController {

/**
 * !Route GET, /foo
 */
function foo(){
return $this->ok('foo');
}

}
?>

In this example, MyController::foo() returns a template file called 'foo.php'. This template file is a child template file of 'bar.php' (the master layout file). 'foo.php' looks like this:

<?php Layout::extend('bar'); ?>
Hello World

And 'bar.php' looks like this:

<html>
<body>
This is the master layout
<?php Layout::slot('body'); ?><?php Layout::slotEnd(); ?>
</body>
</html>

When I access MyController::foo(), the child template 'foo.php' is correctly called and inserted into master template 'bar.php'. However, any variables assigned to template 'foo.php' are not made available to upstream templates. Is it possible (without calling `global $var` in the templates) to pass template variables into upstream templates? For now, I have resorted to NativeView using simple include() statements to include a header and footer template. This is not ideal, but it does solve the problem for now.

Thank you in advance for your help!
Josh

Kris Jordan

unread,
Jun 2, 2009, 2:35:30 PM6/2/09
to recess-f...@googlegroups.com
Josh --

Just wanted to follow up on your questions. The Before and After annotations are now in Recess edge so your code for Issue 1 should work if you pull the latest commits.

I've been working on the doc's for 'Core' functionality that cover implementing annotations, wrappable methods, before, after, etc. that I will push up later today. Wanted to offer some insights on !Before and !After while we're in-context, though.

With Recess 0.20 (edge, currently) there are key methods on framework classes that are wrappable. This means that you can 'wrap' an invocation of the method with objects that implement IWrapper (have a before() and after() method). !Before and !After are short-cut annotations that allow you to wrap wrappable methods without the trouble of writing an IWrapper.

Simple example:
class MyModel extends Model { 
  /** !Before insert, update, delete */
  function echoBefore() {
     echo 'Called before!';
  }

  /** !After insert */
  function echoAfter($result) {
      echo 'Called after!';
      if($result) {
          echo 'Success!';
      } else {
          echo 'Failure!';
      }
  }
}

In this example you see echoBefore() registering to be called before all calls to insert, update, and delete. So calling $model->insert() will echo 'Called before!', then it will perform the insert operation, and finally it will call echoAfter.  If you were to call $model->delete() only 'Called before!' would be echoed because 'delete' is not registered in the !After annotation in echoAfter.

Notice there are no arguments in echoBefore, this is because the method it wraps, insert, takes no arguments. Also notice that echoAfter takes one argument $result. This is the return value of the wrapped method.

More complex example: 

class MyController extends Controller {

    /** !Before serve */
    function authenticate(Request $request) {
          // do some authentication
          if(!$authenticated) {
               Library::import('recess.http.responses.ForbiddenResponse');
               return new ForbiddenResponse($request);
          }
    }

    /** !Before serve */
    function echoBefore(Request $request) {
          echo 'called before serve!';
    }

    /** !After serve */
    function addSomeViewVariable(Response $response) {
       $response->data['somevar'] = 'some val';
       return $response;
    }

    /** !After serve */
    function changeSomeViewVariable(Response $response) {
       $response->data['somevar'] = 'some other val';
       return $response;
    }
}

In this example there is a short-circuit response in the authenticate method. If you return a value from a method called using !Before this will short-circuit the before chain and return this value to the caller. Also notice that because serve($request) takes one parameter, all methods that are wrapped using !Before must also take the $request parameter. The final note on !Before (also applies to !After) is that methods will be called in the order they are registered. So in this case the call chain looks like: authenticate, echoBefore, wrappedServe, addSomeViewVariable, changeSomeViewVariable.

Finally, this example shows off the ability to manipulate a return value with !After. If you return a value from a method registered After a wrapped method call, its value will replace the wrapped methods' return value. Unlike the short-circuit behavior in !Before, though, this new return value will continue being passed down the !After chain. There is no way to short-circuit out of the !After chain. Thus, in the above example, when the Response finally gets sent to the view the variable named $somevar will be set to 'some other val'.

If you find yourself using the same logic across classes with methods using  !Before and !After you've got a great candidate for creating your own custom annotation and wrapper. I'll follow up with a link to this in the documentation when it goes on-line shortly.

-Kris
Reply all
Reply to author
Forward
0 new messages